使用 openCV IPLimage __block 的dispatch_async 出现 EXC_BAD_ACCESS 问题

发布于 2025-01-04 15:08:07 字数 2593 浏览 1 评论 0原文

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

- (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 会产生影响?我缺少什么?我想删除该声明,因为越快越好。

Following scenario. Real time camera feed processing with openCV on ios using dispatch asnyc. Here is capture sampleBufferMethod that is converting the buffer to an IplImage and then using it.

- (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);
        ...
 });
}

Pretty straight forward, except that this here:

        cvResize(image, out, 0);

gives me a EXC_BAD_ACCESS. I got a workaround which I found playing with it forever:

- (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);
        ...
 });
}

Key line:

    __block  IplImage *image=cvCloneImage(_image);

So what I don't understand is why cvCloneImage makes the difference? What am I missing? I would like to get rid of that statement since the faster the better.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

美人如玉 2025-01-11 15:08:07

如果没有您的解决方法,imageBuffer 在块执行时可能无效。您是从框架外部获取它的,据我所知,一旦您的处理程序完成,就不会保证它的持续生命周期。因此你应该复制它。因此,您的克隆使代码能够工作。

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

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

Without your workaround, imageBuffer might not be valid by the time the block executes. You are getting it externally from the framework, with no promises AFAIK regarding its continued lifetime once your handler finishes. Therefore you should copy it. Therefore, your clone makes the code work.

Another issue is in accessing memory which is allocated in the method's stack frame.

You should remove the __block declaration from image - Otherwise the block is passed a pointer to the image struct pointer, instead of just a copy. Since the struct pointer is allocated on the stack, by the time your block runs, the memory where it was before is no longer valid.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文