2016-06-05 33 views
10

मैं 120 एफपीएस पर आईओएस पर रीयलटाइम वीडियो प्रोसेसिंग कर रहा हूं और जीपीयू (डाउनसमूल, कन्वर्ट कलर इत्यादि) पर प्रीप्रोसेस इमेज करना चाहता हूं। सीपीयू पर पर्याप्त तेज़) और बाद में ओपनसीवी का उपयोग कर सीपीयू पर पोस्टप्रोसेस फ्रेम।आईफोन पर जीपीयू (धातु) और सीपीयू (ओपनसीवी) पर कैमरा फीड डेटा प्रोसेसिंग

धातु का उपयोग करके जीपीयू और सीपीयू के बीच कैमरा फ़ीड साझा करने का सबसे तेज़ तरीका क्या है?

दूसरे शब्दों में की तरह पाइप दिखेगा:

CMSampleBufferRef -> MTLTexture or MTLBuffer -> OpenCV Mat 

मैं CMSampleBufferRef परिवर्तित कर रहा हूँ -> निम्नलिखित तरीके

CVPixelBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer); 

// textureRGBA 
{ 
    size_t width = CVPixelBufferGetWidth(pixelBuffer); 
    size_t height = CVPixelBufferGetHeight(pixelBuffer); 
    MTLPixelFormat pixelFormat = MTLPixelFormatBGRA8Unorm; 

    CVMetalTextureRef texture = NULL; 
    CVReturn status = CVMetalTextureCacheCreateTextureFromImage(NULL, _textureCache, pixelBuffer, NULL, pixelFormat, width, height, 0, &texture); 
    if(status == kCVReturnSuccess) { 
     textureBGRA = CVMetalTextureGetTexture(texture); 
     CFRelease(texture); 
    } 
} 

MTLTexture मेरी धातु शेडर बाद मैं OpenCV को MTLTexture परिवर्तित finised है

cv::Mat image; 
... 
CGSize imageSize = CGSizeMake(drawable.texture.width, drawable.texture.height); 
int imageByteCount = int(imageSize.width * imageSize.height * 4); 
int mbytesPerRow = 4 * int(imageSize.width); 

MTLRegion region = MTLRegionMake2D(0, 0, int(imageSize.width), int(imageSize.height)); 
CGSize resSize = CGSizeMake(drawable.texture.width, drawable.texture.height); 
[drawable.texture getBytes:image.data bytesPerRow:mbytesPerRow fromRegion:region mipmapLevel:0]; 

कुछ टिप्पणियों:

1) दुर्भाग्य से MTLTexture.getBytes सीपीयू के लिए GPU से महंगा (नकल डेटा लगता है) और मेरे iphone 5 एस जो है बहुत ज्यादा ~ 100fps

2 में जब प्रसंस्करण पर 5ms चारों ओर ले जाता है) मैं कुछ लोगों को देखा है? निम्नलिखित विधि के साथ MTLTexture के बजाय MTLBuffer का उपयोग करें: metalDevice.newBufferWithLength(byteCount, options: .StorageModeShared) (देखें: Memory write performance - GPU CPU Shared Memory)

हालांकि CMSampleBufferRef और CVPixelBufferRef साथ CoreVideo द्वारा प्रबंधित अनुमान है।

+0

GPU सभी संकल्पों के लिए समर्थित नहीं है। मुझे पता है, यह तुम्हारा जवाब नहीं है। मैं सिर्फ जीपीयू के बारे में एक जानकारी देता हूं। –

+0

क्या आपने GPUImage https://github.com/BradLarson/GPUImage –

+0

को आजमाया है, मैंने GPUImage की कोशिश की लेकिन सबसे बड़ी बोटलेंक्ट GPU से CPU तक डेटा ट्रांसफर कर रही है। GPUImage ओपनजीएल का उपयोग अच्छा और धातु एपीआई के विपरीत के तहत साझा स्मृति नहीं हो सकता है। – pzo

उत्तर

4

ऐसा करने का सबसे तेज़ तरीका एमटीएलबफर द्वारा समर्थित एमटीएलटेक्चर का उपयोग करना है; यह एक विशेष प्रकार का एमटीएलटेक्चर है जो एमटीएलबफर के साथ मेमोरी साझा करता है। हालांकि, आपकी सी प्रोसेसिंग (ओपनसीवी) एक फ्रेम या दो पीछे चल रही है, यह अपरिहार्य है क्योंकि आपको जीपीयू (एन्कोडिंग) में कमांड जमा करने की आवश्यकता है और जीपीयू को इसे प्रस्तुत करने की ज़रूरत है, अगर आप प्रतीक्षा करते हैं तो GPU सुनिश्चित करने के लिए पूरा करें समाप्त हो गया है कि सिर्फ सीपीयू को chews और अपमानजनक है।

तो प्रक्रिया होगी: सबसे पहले आप एमटीएलबफर बनाते हैं तो आप विशेष एमटीएलटेक्चर बनाने के लिए एमटीएलबफर विधि "न्यूटेक्चर विथ डिस्क्रिप्टर: ऑफसेट: बाइट्सरररो:" का उपयोग करते हैं। आपको पहले विशेष रूप से विशेष एमटीएलटेक्चर (एक आवृत्ति चर के रूप में) बनाने की आवश्यकता है, फिर आपको मानक प्रतिपादन पाइपलाइन (गणना करने वाले शेडर्स का उपयोग करने से तेज़ी से) स्थापित करने की आवश्यकता है जो एमएमएसएलटेक्चर को सीएमएसएमएल बफररफ से बनाया जाएगा और इसे अपने विशेष एमटीएलटेक्चर में पास कर देगा, जो आप पास कर सकते हैं और एक पास में आवश्यक रंग परिवर्तन कर सकते हैं। फिर आप gpu को कमांड बफर सबमिट करते हैं, बाद के पास आप केवल [theMTLbuffer सामग्री] को बाइट्स पर पॉइंटर को पकड़ने के लिए कॉल कर सकते हैं जो ओपनसीवी में उपयोग के लिए आपके विशेष एमटीएलटेक्चर को वापस ले जाता है।

सीपीयू/जीपीयू व्यवहार में रोक लगाने वाली कोई भी तकनीक कभी भी कुशल नहीं होगी क्योंकि आधा समय इंतजार किया जाएगा यानी सीपीयू जीपीयू खत्म होने की प्रतीक्षा करता है और जीपीयू को अगले एन्कोडिंग के लिए भी इंतजार करना पड़ता है (जब जीपीयू काम कर रहा है आप चाहते हैं कि सीपीयू अगले फ्रेम को एन्कोड कर रहा है और जीपीयू खत्म होने की प्रतीक्षा करने के बजाए कोई ओपनसीवी काम कर रहा है)।

इसके अलावा, जब लोग आम तौर पर रीयल-टाइम प्रोसेसिंग का संदर्भ लेते हैं तो वे आमतौर पर रीयल-टाइम फीडबैक (विज़ुअल) के साथ कुछ प्रोसेसिंग का जिक्र कर रहे हैं, 4 और उससे ऊपर के सभी आधुनिक आईओएस डिवाइसों में 60 हर्ट्ज स्क्रीन रीफ्रेश दर है, इसलिए कोई प्रतिक्रिया उस से तेज प्रस्तुत किया गया व्यर्थ है, लेकिन यदि आपको 1 (60 हर्ट्ज पर) बनाने के लिए 2 फ्रेम (120 हर्ट्ज पर) की आवश्यकता है तो आपको कस्टम टाइमर होना चाहिए या कैडिसप्ले लिंक को संशोधित करना होगा।

+0

अच्छी युक्ति है कि GPU प्रतिपादन (बनावट शेडर्स) 60fps तक सीमित हो सकता है - समझ में आता है। मुझे वास्तव में सबसे छोटी विलंबता की आवश्यकता है - मेरे पास कस्टम प्राकृतिक यूजर इंटरफेस है जो प्रदर्शित करने के बजाए उपयोगकर्ता को फीडबैक के रूप में ध्वनि का उपयोग करता है। मुझे लगता है कि जीपीयू खत्म होने के लिए सीपीयू इंतजार नहीं कर रहा है - मैं सिर्फ जीपीयू (कंट्रास्ट एडजस्ट, फ़िल्टर कलर साइज का समायोजन) में कुछ प्रीप्रोकैसिंग को ले जाना चाहता हूं, वे जीपीयू पर बहुत तेज हैं और सीपीयू (एनईओएन के साथ घटना) पर बहुत धीमी गति से मेरे कड़े कम्प्यूटेशनल बजट पर विचार करते हैं । जीपीयू के अन्य भागों को स्थानांतरित नहीं किया जा सकता है (जैसे असंभव लगता है?) जैसे कि समोच्च विश्लेषण। लगता है कि जीपीयू मेरे लिए एक मृत अंत है। – pzo

+0

मुझे नहीं लगता कि यह एक मृत अंत है, कम से कम 60Hz पर चलने वाली पाइपलाइन स्थापित करना अपेक्षाकृत आसान होगा, जहां आप प्रत्येक फ्रेम को एन्कोड करते हैं और अपने समोच्च विश्लेषण करते हैं और साथ ही GPU आवश्यक प्रीप्रोकैसिंग करता है, एक बार जब आप यह 60 हर्ट्ज पर जा रहा है और अनुकूलित किया गया है (धातु फ्रेम डीबगर और धातु प्रणाली ट्रेस बहुत उपयोगी उपकरण हैं) इसे 120 हर्ट्ज तक जैक करने का प्रयास करें। मैंने कभी भी टाइमर या कैडिसप्ले लिंक का उपयोग करने की कोशिश नहीं की है, इसलिए मैं आपकी मदद नहीं कर सकता, लेकिन जांचें: http://stackoverflow.com/questions/23885638/change-interval-of-cadisplaylink। – Gary

+0

इसके अलावा, मैं समोच्च विश्लेषण से बहुत परिचित नहीं हूं, लेकिन धातु की गणना कार्यक्षमता का उपयोग करके आप इसे बाहर ले जा सकते हैं, क्योंकि कंट्रास्ट समायोजन या आकार बदलने से GPU को प्रभावित नहीं किया जा रहा है (यदि फ़िल्टर जटिल है तो LUT का उपयोग करें)। मानक वर्टेक्स और खंड के शेडरों के साथ भी GPU पर गैर-अनुकूल GPU सामान करने में सक्षम होने के लिए अक्सर चालें होती हैं, मैंने मेटल का उपयोग करके एक कनेक्टेड घटक लेबलिंग एल्गोरिदम लागू किया और यह छोटी छवियों के लिए सी संस्करण से बहुत दूर नहीं था – Gary

संबंधित मुद्दे