1

以下场景。使用dispatch asnyc在ios上使用openCV进行实时相机馈送处理。这是捕获将缓冲区转换为 IplImage 然后使用它的 sampleBufferMethod。

- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection    
{

    __block IplImage *image = 0;
    CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
    CVPixelBufferLockBaseAddress(imageBuffer, 0);

    // get information of the image in the buffer
    uint8_t *bufferBaseAddress = (uint8_t *)CVPixelBufferGetBaseAddressOfPlane(imageBuffer, 0);
    size_t bufferWidth = CVPixelBufferGetWidth(imageBuffer);
    size_t bufferHeight = CVPixelBufferGetHeight(imageBuffer);

    // create IplImage
    if (bufferBaseAddress) 
    {
        image = cvCreateImage(cvSize(bufferWidth, bufferHeight), IPL_DEPTH_8U, 4);
        image->imageData = (char*)bufferBaseAddress;
    }    
    // release memory
    CVPixelBufferUnlockBaseAddress(imageBuffer, 0);


    dispatch_async(dispatch_get_main_queue(), ^{
        IplImage *out=cvCreateImage(cvSize(568, 320), IPL_DEPTH_8U, 4);
        cvResize(image, out, 0);
        ...
 });
}

非常简单,除了这里:

        cvResize(image, out, 0);

给我一个 EXC_BAD_ACCESS。我找到了一个解决方法,我发现它永远在玩它:

- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection 
{

    IplImage *_image = 0;
    CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
    CVPixelBufferLockBaseAddress(imageBuffer, 0);

    // get information of the image in the buffer
    uint8_t *bufferBaseAddress = (uint8_t *)CVPixelBufferGetBaseAddressOfPlane(imageBuffer, 0);
    size_t bufferWidth = CVPixelBufferGetWidth(imageBuffer);
    size_t bufferHeight = CVPixelBufferGetHeight(imageBuffer);

    // create IplImage
    if (bufferBaseAddress) 
    {
        _image = cvCreateImage(cvSize(bufferWidth, bufferHeight), IPL_DEPTH_8U, 4);
        _image->imageData = (char*)bufferBaseAddress;
    }    
    // release memory
    CVPixelBufferUnlockBaseAddress(imageBuffer, 0);

    __block IplImage *image=cvCloneImage(_image);

    dispatch_async(dispatch_get_main_queue(), ^{
        IplImage *out=cvCreateImage(cvSize(568, 320), IPL_DEPTH_8U, 4);
        cvResize(image, out, 0);
        ...
 });
}

关键线:

    __block  IplImage *image=cvCloneImage(_image);

所以我不明白为什么 cvCloneImage 会有所作为?我错过了什么?我想摆脱这种说法,因为越快越好。

4

1 回答 1

2

如果没有您的解决方法,imageBuffer在块执行时可能无效。您从框架外部获取它,一旦您的处理程序完成,AFAIK 就没有关于它的持续生命周期的承诺。因此,您应该复制它。因此,您的克隆使代码工作。

另一个问题是访问在方法的堆栈帧中分配的内存。

您应该从中删除__block声明image- 否则该块将传递一个指向结构指针的image指针,而不仅仅是一个副本。由于结构指针是在堆栈上分配的,所以当你的块运行时,它之前所在的内存不再有效。

于 2012-02-11T17:33:14.483 回答