2013-10-14 16 views
8

Vorrei eseguire alcune operazioni a un CVPixelBufferRef e venire fuori con un raccolto cv::MatCome faccio a convertire da un CVPixelBufferRef a un cv OpenCV :: Mat

  • ad una regione di interesse
  • in scala ad una dimensione fissa
  • equalizzato dell'istogramma
  • convertito in scala di grigi - 8 bit per pixel (CV_8UC1)

Non sono sicuro di quale sia l'ordine più efficiente per farlo, tuttavia, so che tutte le operazioni sono disponibili su una matrice CV aperta, quindi vorrei sapere come convertirlo.

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

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

risposta

12

Ho trovato la risposta in alcuni excellent GitHub source code. L'ho adattato qui per semplicità. Fa anche la conversione in scala di grigi per me.

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

Sto pensando che il miglior ordine sarà:

  1. Converti in scala di grigi (dal momento che è fatto quasi automaticamente)
  2. Crop (questo dovrebbe essere un funzionamento veloce e ridurrà il numero di pixel da lavorare)
  3. Scale down
  4. Equalizzare dell'istogramma
+0

Ciao @ Robert, sai come si può fare il contrario che è quello di diciamo convertire cv :: Mat in un CVPixelBuffer o sample Buffer? Grazie. – lilouch

+0

Il seguente codice non funzionerà almeno su iPhone 6 e iPhone6 ​​+ con iOS 10.2 che ho testato poiché l'array di pixel sottostante non è continuo nella memoria. Si prega di consultare la mia risposta aggiornata qui http://stackoverflow.com/questions/12355257/open-cv-ios-video-processing/43523459#43523459. – PalmRobotZ

+0

E Swift? – user924

2

Sto usando questo. Il mio cv:Mat è configurato con il colorFormat BGR (8UC3).

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

cos'è 'self.rows'? perché non 'mat.rows'? anche come creare 'CMSampleBufferRef' da questo' CVImageBufferRef'? – user924

Problemi correlati