¿Cómo puedo convertir un CVPixelBufferRef a un openCV cv :: Mat

Me gustaría realizar algunas operaciones a un CVPixelBufferRef y salir con un cv::Mat

  • recortar a una región de interés
  • escalado a una dimensión fija
  • ecualizó el histogtwig
  • convertir a escala de grises – 8 bits por píxel ( CV_8UC1 )

No estoy seguro de cuál es el order más eficiente para hacer esto, sin embargo, sé que todas las operaciones están disponibles en una matriz abierta: CV, por lo que me gustaría saber cómo convertirla.

 - (void) captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection { CVPixelBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer); cv::Mat frame = f(pixelBuffer); // how do I implement f()? 

Encontré la respuesta en un excelente código fuente de GitHub . Lo adapté aquí por sencillez. También hace la conversión en escala de grises para mí.

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

Estoy pensando que el mejor order será:

  1. Convierte a escala de grises (ya que se hace casi automáticamente)
  2. Recortar (esto debería ser una operación rápida y networkingucirá la cantidad de píxeles con los que trabajar)
  3. Reducir proporcionalmente
  4. Ecualizar el histogtwig

Estoy usando esto Mi cv:Mat está configurado 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; }