2012-07-06 37 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); 
}