2013-10-14 12 views
8

Tôi muốn thực hiện một vài thao tác với một CVPixelBufferRef và đi ra với một vụ mùa cv::MatLàm thế nào để chuyển đổi từ một CVPixelBufferRef một cv OpenCV :: Mat

  • đến một khu vực quan tâm
  • quy mô đến một kích thước cố định
  • cân bằng histogram
  • chuyển đổi sang thang màu xám - 8 bit cho mỗi pixel (CV_8UC1)

Tôi không chắc chắn về thứ tự hiệu quả nhất là làm điều này, tuy nhiên, tôi biết rằng tất cả các hoạt động có sẵn trên một ma trận CV mở, vì vậy tôi muốn biết cách chuyển đổi nó.

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

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

Trả lời

12

Tôi tìm thấy câu trả lời trong một số excellent GitHub source code. Tôi thích nghi nó ở đây để đơn giản. Nó cũng chuyển đổi thang độ xám cho tôi.

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); 

Tôi nghĩ rằng thứ tự tốt nhất sẽ là:

  1. Chuyển đổi sang dạng grayscale (kể từ khi nó được thực hiện gần như tự động)
  2. Crop (điều này phải là một hoạt động nhanh và sẽ giảm số lượng các điểm ảnh để làm việc với)
  3. Scale xuống
  4. cân bằng histogram
+0

Hi @Robert, bạn có biết làm thế nào bạn có thể làm điều ngược lại đó là chuyển đổi cv :: Mat thành CVPixelBuffer hoặc Buffer mẫu? Cảm tạ. – lilouch

+0

Đoạn mã sau sẽ không hoạt động tối thiểu trên iPhone 6 và iPhone6 ​​+ với iOS 10.2 mà tôi đã thử nghiệm vì mảng pixel cơ bản không liên tục trong bộ nhớ. Vui lòng xem câu trả lời cập nhật của tôi tại đây http://stackoverflow.com/questions/12355257/open-cv-ios-video-processing/43523459#43523459. – PalmRobotZ

+0

Còn Swift thì sao? – user924

2

Tôi đang sử dụng tính năng này. My cv:Mat được cấu hình 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 = self.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; 
} 
+0

'self.rows' là gì? tại sao không phải là 'mat.rows'? cũng làm thế nào để tạo ra 'CMSampleBufferRef' từ' CVImageBufferRef' này? – user924

Các vấn đề liên quan