【问题标题】:How do I convert from a CVPixelBufferRef to an openCV cv::Mat如何从 CVPixelBufferRef 转换为 openCV cv::Mat
【发布时间】:2013-10-21 22:15:06
【问题描述】:

我想对CVPixelBufferRef 执行一些操作,然后输出cv::Mat

  • 裁剪到感兴趣的区域
  • 缩放到固定尺寸
  • 均衡直方图
  • 转换为灰度 - 每像素 8 位 (CV_8UC1)

我不确定执行此操作的最有效顺序是什么,但是,我知道所有操作都可以在 open:CV 矩阵上使用,所以我想知道如何转换它。

- (void) captureOutput:(AVCaptureOutput *)captureOutput 
         didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer 
         fromConnection:(AVCaptureConnection *)connection
{
     CVPixelBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);

     cv::Mat frame = f(pixelBuffer); // how do I implement f()?

【问题讨论】:

    标签: c++ ios objective-c opencv avcapturesession


    【解决方案1】:

    我在一些excellent GitHub source code 中找到了答案。为了简单起见,我在这里对其进行了调整。它还为我做了灰度转换。

    CVPixelBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
    OSType format = CVPixelBufferGetPixelFormatType(pixelBuffer);
    
    // Set the following dict on AVCaptureVideoDataOutput's videoSettings to get YUV output
    // @{ kCVPixelBufferPixelFormatTypeKey : kCVPixelFormatType_420YpCbCr8BiPlanarFullRange }
    
    NSAssert(format == kCVPixelFormatType_420YpCbCr8BiPlanarFullRange, @"Only YUV is supported");
    
    // The first plane / channel (at index 0) is the grayscale plane
    // See more infomation about the YUV format
    // http://en.wikipedia.org/wiki/YUV
    CVPixelBufferLockBaseAddress(pixelBuffer, 0);
    void *baseaddress = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 0);
    
    CGFloat width = CVPixelBufferGetWidth(pixelBuffer);
    CGFloat height = CVPixelBufferGetHeight(pixelBuffer);
    
    cv::Mat mat(height, width, CV_8UC1, baseaddress, 0);
    
    // Use the mat here
    
    CVPixelBufferUnlockBaseAddress(pixelBuffer, 0);
    

    我认为最好的顺序是:

    1. 转换为灰度(因为它几乎是自动完成的)
    2. 裁剪(这应该是一种快速操作,并且会减少要处理的像素数)
    3. 按比例缩小
    4. 均衡直方图

    【讨论】:

    • 嗨@Robert,你知道如何做相反的事情,即将 cv::Mat 转换为 CVPixelBuffer 或 sample Buffer 吗?谢谢。
    • 以下代码至少在我测试过的带有 iOS 10.2 的 iPhone 6 和 iPhone6+ 上不起作用,因为底层像素数组在内存中不连续。请在此处查看我的更新答案stackoverflow.com/questions/12355257/…
    • 斯威夫特呢?
    【解决方案2】:

    我正在使用这个。我的cv:Mat 配置为 BGR(8UC3) colorFormat。

    CVImageBufferRef -> cv::Mat

    - (cv::Mat) matFromImageBuffer: (CVImageBufferRef) buffer {
    
        cv::Mat mat ;
    
        CVPixelBufferLockBaseAddress(buffer, 0);
    
        void *address = CVPixelBufferGetBaseAddress(buffer);
        int width = (int) CVPixelBufferGetWidth(buffer);
        int height = (int) CVPixelBufferGetHeight(buffer);
    
        mat   = cv::Mat(height, width, CV_8UC4, address, 0);
        //cv::cvtColor(mat, _mat, CV_BGRA2BGR);
    
        CVPixelBufferUnlockBaseAddress(buffer, 0);
    
        return mat;
    }
    

    cv::Mat -> CVImageBufferRef (CVPixelBufferRef)

    - (CVImageBufferRef) getImageBufferFromMat: (cv::Mat) mat {
    
        cv::cvtColor(mat, mat, CV_BGR2BGRA);
    
        int width = mat.cols;
        int height = mat.rows;
    
        NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
                                 // [NSNumber numberWithBool:YES], kCVPixelBufferCGImageCompatibilityKey,
                                 // [NSNumber numberWithBool:YES], kCVPixelBufferCGBitmapContextCompatibilityKey,
                                 [NSNumber numberWithInt:width], kCVPixelBufferWidthKey,
                                 [NSNumber numberWithInt:height], kCVPixelBufferHeightKey,
                                 nil];
    
        CVPixelBufferRef imageBuffer;
        CVReturn status = CVPixelBufferCreate(kCFAllocatorMalloc, width, height, kCVPixelFormatType_32BGRA, (CFDictionaryRef) CFBridgingRetain(options), &imageBuffer) ;
    
    
        NSParameterAssert(status == kCVReturnSuccess && imageBuffer != NULL);
    
        CVPixelBufferLockBaseAddress(imageBuffer, 0);
        void *base = CVPixelBufferGetBaseAddress(imageBuffer) ;
        memcpy(base, mat.data, _mat.total()*4);
        CVPixelBufferUnlockBaseAddress(imageBuffer, 0);
    
        return imageBuffer;
    }
    

    【讨论】:

    • 什么是self.rows?为什么不mat.rows?还有如何从这个CVImageBufferRef创建CMSampleBufferRef
    • 哦..它有一些错误。
    • @keyOfVv 函数开头的“-”是什么意思?
    • @Amacelia 表示该函数是实例方法,而不是目标 C 中的类方法。
    猜你喜欢
    • 1970-01-01
    • 2022-06-13
    • 2018-04-16
    • 2011-06-28
    • 2016-08-16
    • 2022-06-25
    • 1970-01-01
    • 2021-11-24
    • 2017-06-03
    相关资源
    最近更新 更多