Как мне конвертировать из CVPixelBufferRef в openCV cv :: Mat

Я хотел бы выполнить несколько операций для 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()?

9

Решение

Я нашел ответ в некоторых отличный исходный код GitHub. Я адаптировал это здесь для простоты. Это также делает преобразование серого для меня.

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. Выровнять гистограмму
12

Другие решения

Я использую это. мой 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 = 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;
}
2