2012-07-06 36 views
5

我正在製作一個簡單的管道,它從AVCaptureSession獲取圖像,在OpenCV中處理它們,然後在OpenGL中呈現它們。它基於RosyWriter,但沒有音頻和錄音功能。 OpenCV處理看起來像從CVImageBufferRef獲取內存的所有權

- (void)processPixelBuffer: (CVImageBufferRef)pixelBuffer 
{ 
CVPixelBufferLockBaseAddress(pixelBuffer, 0); 
int bufferWidth = CVPixelBufferGetWidth(pixelBuffer); 
int bufferHeight = CVPixelBufferGetHeight(pixelBuffer); 
unsigned char *pixel = (unsigned char *)CVPixelBufferGetBaseAddress(pixelBuffer); 

cv::Mat image = cv::Mat(bufferWidth,bufferHeight,CV_8UC4,pixel); 
//do any processing 
[self setDisplay_matrix:image]; 
CVPixelBufferUnlockBaseAddress(pixelBuffer, 0); 
} 

在這個函數到目前爲止我沒有複製任何內存,我想保持它的方式。問題是pixelBuffer可能仍然擁有display_image中包含的內存。處理代碼可能會或可能不會分配新內存並將其存儲在映像中。如果處理沒有分配新的內存,我必須使用display_matrix傳遞pixelBuffer以防止數據被擦除。有沒有辦法讓我獲得記憶的所有權?我想銷燬pixelBuffer而不破壞它指向的內存。

在相關說明中,LockBaseAddress究竟幹什麼?如果我傳遞一個cv :: Mat,CVImageBufferRef對將不得不鎖定基地址,每次我想用cv :: Mat修改/使用數據時?

+0

嗨錘子,你如何渲染你的cv :: Mat圖像到OpenGL ES中嗎?預先感謝 – lilouch 2016-07-18 11:45:33

回答

0

您可以從基地址數據創建數據提供程序而無需複製,然後從此數據提供程序創建UIImage。爲了避免在引用此映像時重新使用緩衝區,您需要保留樣本緩衝區和鎖定基地址。他們應該被解鎖,並自動釋放時你會忘記這個圖像對象:

- (void)captureOutput:(AVCaptureOutput *)captureOutput 
didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer 
     fromConnection:(AVCaptureConnection *)connection 
{ 
    // Retain sample buffer and lock base address 
    CFRetain(sampleBuffer); 
    CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer); 
    CVPixelBufferLockBaseAddress(imageBuffer, 0); 

    size_t bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer); 
    size_t height = CVPixelBufferGetHeight(imageBuffer); 
    size_t width = CVPixelBufferGetWidth(imageBuffer); 
    void *baseAddress = (void *)CVPixelBufferGetBaseAddressOfPlane(imageBuffer, 0); 

    UIImage *image = imageFromData(baseAddress, width, height, bytesPerRow, sampleBuffer); 

    // Now you can store this UIImage as long as you want 
} 

我已經從這個項目中得到了https://github.com/k06a/UIImage-DecompressAndMap/blob/master/UIImage%2BDecompressAndMap.mimageFromData通過它一點點:

UIImage *imageFromData(void *data, size_t width, size_t height, size_t bytesPerRow, CMSampleBufferRef sampleBuffer) 
{ 
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 
    CGDataProviderRef provider = CGDataProviderCreateWithData((void *)sampleBuffer, data, bytesPerRow * height, munmap_wrapper); 
    CGImageRef inflatedImage = CGImageCreate(width, height, 8, 4*8, bytesPerRow, colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst, provider, NULL, NO, kCGRenderingIntentDefault); 

    CGColorSpaceRelease(colorSpace); 
    CGDataProviderRelease(provider); 

    UIImage *img = [UIImage imageWithCGImage:inflatedImage scale:scale orientation:UIImageOrientationUp]; 
    CGImageRelease(inflatedImage); 
    return img; 
} 

您還需要提供unlock_function

void unlock_function(void *info, const void *data, size_t size) 
{ 
    // Unlock base address release sample buffer 
    CMSampleBufferRef sampleBuffer = (CMSampleBufferRef)info; 
    CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer); 
    CVPixelBufferUnlockBaseAddress(imageBuffer, 0); 
    CFRelease(sampleBuffer); 
}