以OpenCV Mat格式从相机捕获静止图像

时间:2014-01-17 09:53:32

标签: ios opencv avfoundation

我正在开发一个iOS应用程序并尝试使用捕获会话从相机获取静态图像快照,但我无法将其成功转换为OpenCV Mat。

使用以下代码创建静止图像输出:

- (void)createStillImageOutput;
{
    // setup still image output with jpeg codec
    self.stillImageOutput = [[AVCaptureStillImageOutput alloc] init];
    NSDictionary *outputSettings = [NSDictionary dictionaryWithObjectsAndKeys:AVVideoCodecJPEG, AVVideoCodecKey, nil];
    [self.stillImageOutput setOutputSettings:outputSettings];
    [self.captureSession addOutput:self.stillImageOutput];

    for (AVCaptureConnection *connection in self.stillImageOutput.connections) {
        for (AVCaptureInputPort *port in [connection inputPorts]) {
            if ([port.mediaType isEqual:AVMediaTypeVideo]) {
                self.videoCaptureConnection = connection;
                break;
            }
        }
        if (self.videoCaptureConnection) {
            break;
        }
    }
    NSLog(@"[Camera] still image output created");
}

然后尝试使用此代码捕获静止图像:

[self.stillImageOutput captureStillImageAsynchronouslyFromConnection:self.videoCaptureConnection
                                                   completionHandler:
 ^(CMSampleBufferRef imageSampleBuffer, NSError *error)
 {
     if (error == nil && imageSampleBuffer != NULL)
     {
         NSData *jpegData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageSampleBuffer];
     }

我需要一种基于缓冲区中像素数据创建OpenCV Mat的方法。 我尝试使用此代码创建一个Mat,我从OpenCV摄像机类摄像机here中获取该代码:

    CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
    CVPixelBufferLockBaseAddress(imageBuffer, 0);

    void* bufferAddress;
    size_t width;
    size_t height;
    size_t bytesPerRow;

    CGColorSpaceRef colorSpace;
    CGContextRef context;

    int format_opencv;

    OSType format = CVPixelBufferGetPixelFormatType(imageBuffer);
    if (format == kCVPixelFormatType_420YpCbCr8BiPlanarFullRange) {

        format_opencv = CV_8UC1;

        bufferAddress = CVPixelBufferGetBaseAddressOfPlane(imageBuffer, 0);
        width = CVPixelBufferGetWidthOfPlane(imageBuffer, 0);
        height = CVPixelBufferGetHeightOfPlane(imageBuffer, 0);
        bytesPerRow = CVPixelBufferGetBytesPerRowOfPlane(imageBuffer, 0);

    } else { // expect kCVPixelFormatType_32BGRA

        format_opencv = CV_8UC4;

        bufferAddress = CVPixelBufferGetBaseAddress(imageBuffer);
        width = CVPixelBufferGetWidth(imageBuffer);
        height = CVPixelBufferGetHeight(imageBuffer);
        bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer);

    }

    cv::Mat image(height, width, format_opencv, bufferAddress, bytesPerRow);

但它无法在CVPixelBufferGetWidth或CVPixelBufferGetHeight调用上获得图像的实际高度和宽度,因此Mat的创建失败。

我知道我可以使用以下代码基于像素数据创建UIImage:

             UIImage* newImage = [UIImage imageWithData:jpegData];

但我更喜欢直接构建一个CvMat,就像OpenCV CvVideoCamera类中的情况一样,因为我只对OpenCV中的图像处理感兴趣而且我不想再次浪费时间转换而不会冒失去质量的风险或者有方向问题(无论如何,OpenCV提供的UIImagetoCV转换功能导致内存泄漏而不释放内存)。

请告知我如何将图像作为OpenCV Mat获取。 提前谢谢。

1 个答案:

答案 0 :(得分:1)

我找到了解决问题的方法。

解决方案是:

通过在OpenCv Camera Class中重写此方法:“createVideoPreviewLayer”

它应该是这样的:

- (void)createVideoPreviewLayer;
{

    self.parentView.layer.sublayers = nil;
    if (captureVideoPreviewLayer == nil) {
        captureVideoPreviewLayer = [[AVCaptureVideoPreviewLayer alloc]
        initWithSession:self.captureSession];
    }

    if (self.parentView != nil) {
        captureVideoPreviewLayer.frame = self.parentView.bounds;
        captureVideoPreviewLayer.videoGravity =
        AVLayerVideoGravityResizeAspectFill;
        [self.parentView.layer addSublayer:captureVideoPreviewLayer];
    }
    NSLog(@"[Camera] created AVCaptureVideoPreviewLayer");
}

你应该将这一行添加到“createVideoPreviewLayer”方法中解决 问题:

self.parentView.layer.sublayers = nil;

,您需要使用pause方法而不是stop方法