以下方案。使用dispatch asnyc在ios上使用openCV进行实时摄像机馈送处理。这是捕获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会有所不同?我错过了什么?我想摆脱这种说法,因为越快越好。
答案 0 :(得分:2)
如果没有您的解决方法,imageBuffer
可能在块执行时无效。你是从框架外部获得它,没有承诺AFAIK关于它的处理程序完成后它的持续生命周期。因此你应该复制它。因此,您的克隆使代码有效。
另一个问题是访问在方法的堆栈帧中分配的内存。
您应该从__block
中删除image
声明 - 否则该块会将指针传递给image
结构指针,而不仅仅是副本。由于struct指针是在堆栈上分配的,所以当块运行时,它之前的内存不再有效。