2012-07-06 8 views
5

Estoy haciendo una tubería simple que obtiene imágenes de AVCaptureSession, las procesa en OpenCV y luego las traduce en OpenGL. Está basado en RosyWriter pero sin las capacidades de audio y grabación. El procesamiento de OpenCV pareceTome posesión de la memoria de 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); 
} 

En esta función hasta el momento no se han copiado cualquier memoria y me gustaría que siga siendo así. El problema es que pixelBuffer aún puede poseer la memoria contenida en display_image. El código de procesamiento puede o no asignar nueva memoria y almacenarla en la imagen. Si el procesamiento no asignó nueva memoria, tengo que pasar pixelBuffer alrededor con display_matrix para evitar que se borren los datos. ¿Hay alguna forma de que tome posesión de la memoria? Quiero destruir pixelBuffer sin destruir la memoria que apunta también.

En una nota relacionada, ¿qué hace exactamente LockBaseAddress? Si estuviera pasando un cv :: Mat, el par CVImageBufferRef tendría que bloquear la dirección base cada vez que quiera modificar/usar los datos con cv :: Mat?

+0

Hola Hammer, ¿cómo renderizas tu imagen de cv :: Mat en OpenGL ES? Gracias de antemano – lilouch

Respuesta

0

Puede crear el proveedor de datos a partir de los datos de la dirección base sin copiar, y luego crear el UIImage de este proveedor de datos. Para evitar la reutilización del búfer mientras refiere esta imagen, debe conservar el búfer de muestra y bloquear la dirección base. Deben ser desbloqueados y se liberan automáticamente cuando se olvidará de este objeto de imagen:

- (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 
} 

Tengo imageFromData de este proyecto https://github.com/k06a/UIImage-DecompressAndMap/blob/master/UIImage%2BDecompressAndMap.m y adoptaron un poco:

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; 
} 

También es necesario proporcionar 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); 
} 
Cuestiones relacionadas