2011-11-09 15 views
23

मुझे सीवी पिक्सेलबफर से UIIMAGE प्राप्त करने में कुछ समस्याएं आ रही हैं।एक सीवी पिक्सेलबफर को यूआईएममेज में कैसे चालू करें?

CVPixelBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(imageDataSampleBuffer); 
CFDictionaryRef attachments = CMCopyDictionaryOfAttachments(kCFAllocatorDefault, imageDataSampleBuffer, kCMAttachmentMode_ShouldPropagate); 
CIImage *ciImage = [[CIImage alloc] initWithCVPixelBuffer:pixelBuffer options:(NSDictionary *)attachments]; 
if (attachments) 
    CFRelease(attachments); 
size_t width = CVPixelBufferGetWidth(pixelBuffer); 
size_t height = CVPixelBufferGetHeight(pixelBuffer); 
if (width && height) { // test to make sure we have valid dimensions 
    UIImage *image = [[UIImage alloc] initWithCIImage:ciImage]; 

    UIImageView *lv = [[UIImageView alloc] initWithFrame:self.view.frame]; 
    lv.contentMode = UIViewContentModeScaleAspectFill; 
    self.lockedView = lv; 
    [lv release]; 
    self.lockedView.image = image; 
    [image release]; 
} 
[ciImage release]; 

height और width दोनों सही ढंग से कैमरे के संकल्प की तैयारी में हैं: यह है कि मैं क्या कोशिश कर रहा हूँ है। image बनाया गया है लेकिन मुझे लगता है कि यह काला (या शायद पारदर्शी?) है। मैं समझ नहीं पा रहा हूं कि समस्या कहां है। किसी भी सुझाव की सराहना की जाएगी।

+0

आप निश्चित रूप से बीच में एक सीआईएममेज चाहते हैं, उदा। क्योंकि आप कुछ इंटरमीडिएट सीआईएफल्टर्स को फेंकने जा रहे हैं, या सीजीबीआईटीएमएपी कॉन्टेक्स्टक्रेट -> यूआईएममेज जाने के लिए स्वीकार्य होगा? – Tommy

+0

अभी के लिए, मैं बस इसे एक दृश्य में प्रदर्शित करना चाहता हूं और देख रहा हूं कि मैं किससे निपट रहा हूं। सड़क के नीचे, मैं पिक्सेल के साथ खेलना चाहता हूँ। – mahboudz

उत्तर

36

सभी स्पष्ट सामग्री जो आपके प्रश्न से सीधे संबंधित नहीं हैं: AVCaptureVideoPreviewLayer कैमरों में से किसी एक से स्वतंत्र दृश्य में पाइप वीडियो का सबसे सस्ता तरीका है यदि डेटा कहां से आ रहा है और आपके पास नहीं है इसे संशोधित करने की तत्काल योजनाएं। आपको खुद को धक्का देने की ज़रूरत नहीं है, पूर्वावलोकन परत सीधे AVCaptureSession से जुड़ा हुआ है और खुद अपडेट करता है।

मुझे केंद्रीय प्रश्न के बारे में विश्वास की कमी के लिए प्रवेश करना होगा। CIImage और अन्य दो प्रकार की छवि के बीच एक अर्थपूर्ण अंतर है - CIImage एक छवि के लिए एक नुस्खा है और आवश्यक रूप से पिक्सेल द्वारा समर्थित नहीं है। यह कुछ ऐसा हो सकता है जैसे "यहां से पिक्सल लें, इस तरह बदलें, इस फ़िल्टर को लागू करें, इस तरह बदलें, इस अन्य छवि के साथ विलय करें, इस फ़िल्टर को लागू करें"। सिस्टम को पता नहीं है कि CIImage ऐसा लगता है जब तक कि आप इसे प्रस्तुत करना नहीं चुनते। यह मूल रूप से उपयुक्त सीमाओं को भी नहीं जानता है जिसमें इसे रास्टराइज करना है।

UIImage केवल CIImage को लपेटने के लिए purports। यह इसे पिक्सल में परिवर्तित नहीं करता है। संभवतः UIImageView इसे प्राप्त करना चाहिए, लेकिन यदि ऐसा है तो मुझे लगता है कि आप उचित आउटपुट आयत की आपूर्ति कहां नहीं पाएंगे।

मैं लिया है सफलता सिर्फ साथ समस्या के dodging:

CIImage *ciImage = [CIImage imageWithCVPixelBuffer:pixelBuffer]; 

CIContext *temporaryContext = [CIContext contextWithOptions:nil]; 
CGImageRef videoImage = [temporaryContext 
        createCGImage:ciImage 
        fromRect:CGRectMake(0, 0, 
          CVPixelBufferGetWidth(pixelBuffer), 
          CVPixelBufferGetHeight(pixelBuffer))]; 

UIImage *uiImage = [UIImage imageWithCGImage:videoImage]; 
CGImageRelease(videoImage); 

के साथ उत्पादन आयत निर्दिष्ट करने के लिए एक स्पष्ट अवसर देता है। मुझे यकीन है कि एक मध्यस्थ के रूप में CGImage का उपयोग किए बिना एक मार्ग है, इसलिए कृपया यह न मानें कि यह समाधान सर्वोत्तम अभ्यास है।

+0

धन्यवाद, मैं इसे आज़मा दूंगा। पूर्वावलोकन लेयर उपयोगी नहीं है कि मुझे अधिक संकल्प की आवश्यकता है। और एक jpegrepresentation के बजाय मैं CIIImage के साथ जा रहा हूं यह देखने के लिए है कि जेपीईजी संपीड़न महत्वपूर्ण कलाकृतियों को जोड़ रहा है या नहीं। यदि वास्तव में कलाकृतियों न्यूनतम हैं, तो मैं वास्तव में जेपीईजी के साथ रहना चुन सकता हूं। – mahboudz

+0

यह काम करता है। धन्यवाद! – mahboudz

11

UIImage प्राप्त करने का एक और तरीका। निष्पादित करता ~ 10 गुना तेजी से, कम से कम मेरे मामले में:

int w = CVPixelBufferGetWidth(pixelBuffer); 
int h = CVPixelBufferGetHeight(pixelBuffer); 
int r = CVPixelBufferGetBytesPerRow(pixelBuffer); 
int bytesPerPixel = r/w; 

unsigned char *buffer = CVPixelBufferGetBaseAddress(pixelBuffer); 

UIGraphicsBeginImageContext(CGSizeMake(w, h)); 

CGContextRef c = UIGraphicsGetCurrentContext(); 

unsigned char* data = CGBitmapContextGetData(c); 
if (data != NULL) { 
    int maxY = h; 
    for(int y = 0; y<maxY; y++) { 
     for(int x = 0; x<w; x++) { 
     int offset = bytesPerPixel*((w*y)+x); 
     data[offset] = buffer[offset];  // R 
     data[offset+1] = buffer[offset+1]; // G 
     data[offset+2] = buffer[offset+2]; // B 
     data[offset+3] = buffer[offset+3]; // A 
     } 
    } 
} 
UIImage *img = UIGraphicsGetImageFromCurrentImageContext(); 

UIGraphicsEndImageContext(); 
+0

आपको एक वृद्धिशील पॉइंटर का उपयोग करना चाहिए, जो आपको – jjxtra

+6

पर एक छोटा सा गति बढ़ावा देगा, आपको सीवी पिक्सेलबफररबेट एड्रेस पर कॉल करने से पहले सीवी पिक्सेलबफर लॉकबेस एड्रेस पर कॉल डालना होगा और डेटा कॉपी के बाद CVPixelBufferUnlockBaseAddress को कॉल करें। इसके अलावा आप डेटा की एक ब्लॉक प्रतिलिपि करने के लिए CVPixelBufferGetDataSize और memcpy() का उपयोग करने पर विचार करना चाहेंगे। –

8

जब तक आपकी छवि डेटा कुछ अलग स्वरूप है कि एक प्रकार का शराबी या रूपांतरण की आवश्यकता है में है - मैं कुछ भी करने का कोई incrementing की सिफारिश करेंगे ... बस में डेटा प्रकार का जहाज़ अपने memcpy के साथ संदर्भ स्मृति क्षेत्र में:

//not here... unsigned char *buffer = CVPixelBufferGetBaseAddress(pixelBuffer); 

UIGraphicsBeginImageContext(CGSizeMake(w, h)); 

CGContextRef c = UIGraphicsGetCurrentContext(); 

void *ctxData = CGBitmapContextGetData(c); 

// MUST READ-WRITE LOCK THE PIXEL BUFFER!!!! 
CVPixelBufferLockBaseAddress(pixelBuffer, 0); 
void *pxData = CVPixelBufferGetBaseAddress(pixelBuffer); 
memcpy(ctxData, pxData, 4 * w * h); 
CVPixelBufferUnlockBaseAddress(pixelBuffer, 0); 

... and so on... 
+0

मुझे CGImageCreate पथ की तुलना में पुराने उपकरणों पर ~ 50% एफपीएस बढ़ावा मिला है। धन्यवाद! –

+2

सावधान रहें क्योंकि सीवी पिक्सेलबफर में पंक्तियों के अंत में अक्सर पैडिंग बाइट्स होते हैं। अर्थात। CVPixelBufferGetBytesPerRow आप अपेक्षा से अधिक हो सकता है। फिर आपकी प्रतिलिपि बनाई गई छवि आउटपुट सभी slanty देखेंगे। – Baxissimo

3

पिछली विधियों ने मुझे सीजी रास्टर डेटा रिसाव का नेतृत्व किया। रूपांतरण की यह विधि मेरे लिए रिसाव नहीं हुई:

@autoreleasepool { 

    CGImageRef cgImage = NULL; 
    OSStatus res = CreateCGImageFromCVPixelBuffer(pixelBuffer,&cgImage); 
    if (res == noErr){ 
     UIImage *image= [UIImage imageWithCGImage:cgImage scale:1.0 orientation:UIImageOrientationUp]; 

    } 
    CGImageRelease(cgImage); 
} 


    static OSStatus CreateCGImageFromCVPixelBuffer(CVPixelBufferRef pixelBuffer, CGImageRef *imageOut) 
    { 
     OSStatus err = noErr; 
     OSType sourcePixelFormat; 
     size_t width, height, sourceRowBytes; 
     void *sourceBaseAddr = NULL; 
     CGBitmapInfo bitmapInfo; 
     CGColorSpaceRef colorspace = NULL; 
     CGDataProviderRef provider = NULL; 
     CGImageRef image = NULL; 

     sourcePixelFormat = CVPixelBufferGetPixelFormatType(pixelBuffer); 
     if (kCVPixelFormatType_32ARGB == sourcePixelFormat) 
      bitmapInfo = kCGBitmapByteOrder32Big | kCGImageAlphaNoneSkipFirst; 
     else if (kCVPixelFormatType_32BGRA == sourcePixelFormat) 
      bitmapInfo = kCGBitmapByteOrder32Little | kCGImageAlphaNoneSkipFirst; 
     else 
      return -95014; // only uncompressed pixel formats 

     sourceRowBytes = CVPixelBufferGetBytesPerRow(pixelBuffer); 
     width = CVPixelBufferGetWidth(pixelBuffer); 
     height = CVPixelBufferGetHeight(pixelBuffer); 

     CVPixelBufferLockBaseAddress(pixelBuffer, 0); 
     sourceBaseAddr = CVPixelBufferGetBaseAddress(pixelBuffer); 

     colorspace = CGColorSpaceCreateDeviceRGB(); 

     CVPixelBufferRetain(pixelBuffer); 
     provider = CGDataProviderCreateWithData((void *)pixelBuffer, sourceBaseAddr, sourceRowBytes * height, ReleaseCVPixelBuffer); 
     image = CGImageCreate(width, height, 8, 32, sourceRowBytes, colorspace, bitmapInfo, provider, NULL, true, kCGRenderingIntentDefault); 

     if (err && image) { 
      CGImageRelease(image); 
      image = NULL; 
     } 
     if (provider) CGDataProviderRelease(provider); 
     if (colorspace) CGColorSpaceRelease(colorspace); 
     *imageOut = image; 
     return err; 
    } 

    static void ReleaseCVPixelBuffer(void *pixel, const void *data, size_t size) 
    { 
     CVPixelBufferRef pixelBuffer = (CVPixelBufferRef)pixel; 
     CVPixelBufferUnlockBaseAddress(pixelBuffer, 0); 
     CVPixelBufferRelease(pixelBuffer); 
    } 
0

स्विफ्ट में इसे आजमाएं।

extension UIImage { 
    public convenience init?(pixelBuffer: CVPixelBuffer) { 
     var cgImage: CGImage? 
     VTCreateCGImageFromCVPixelBuffer(pixelBuffer, nil, &cgImage) 

     if let cgImage = cgImage { 
      self.init(cgImage: cgImage) 
     } else { 
      return nil 
     } 
    } 
} 

नोट: आरजीबी पिक्सेल बफ़र्स के लिए यह केवल काम करता है, ग्रेस्केल के लिए नहीं।

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