1

次のシナリオ。ディスパッチ 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がないと、ブロックが実行されるまでに有効でなくなる可能性があります。フレームワークから外部的に取得していますが、ハンドラーが終了した後の継続的な寿命に関する約束はありません。したがって、それをコピーする必要があります。したがって、クローンによってコードが機能します。

もう 1 つの問題は、メソッドのスタック フレームに割り当てられているメモリへのアクセスにあります。

__blockから宣言を削除する必要がありますimage- そうしないと、ブロックには単なるコピーではなく、構造体ポインターへのポインターが渡されます。image構造体ポインタはスタックに割り当てられるため、ブロックが実行されるまでに、以前のメモリは有効ではなくなります。

于 2012-02-11T17:33:14.483 に答える