Я пытаюсь преобразовать CGImageRef в OpenCV cv :: Mat.
Все отлично работает с 4-канальными изображениями, но для изображений в градациях серого происходит сбой, потому что функция GetRowBytes CGImageRef возвращает значение, превышающее значение mat.step [0] (равное ширине изображения).
Например, у меня есть CGImageRef градаций серого шириной 500 пикселей, а функция CGImageGetBytesPerRow возвращает 512.
Почему он возвращает это значение? И как мне правильно создать мой cv :: Mat?
- (cv::Mat) CVGrayscaleMatWithCGImage:(CGImageRef)image
{
// NSLog(@"%zu", CGImageGetBytesPerRow(image)); -> return 512
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray();
CGFloat cols = CGImageGetWidth(image);
CGFloat rows = CGImageGetHeight(image);
cv::Mat cvMat = cv::Mat(rows, cols, CV_8UC1); // 8 bits per component, 1 channel
CGContextRef contextRef = CGBitmapContextCreate(cvMat.data,
cols,
rows,
8,
cvMat.step[0], // Bytes per row -> return 500
colorSpace,
kCGImageAlphaNone |
kCGBitmapByteOrderDefault);
CGContextDrawImage(contextRef, CGRectMake(0, 0, cols, rows), image);
CGContextRelease(contextRef);
CGColorSpaceRelease(colorSpace);
return cvMat;
}
Я наконец получил это на работу. Количество байтов в строке должно быть кратным 16.
Вот код:
- (cv::Mat) CVGrayscaleMatWithCGImage:(CGImageRef)image
{
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray();
CGFloat cols = CGImageGetWidth(image);
CGFloat rows = CGImageGetHeight(image);
cv::Mat cvMat = cv::Mat(rows, cols, CV_8UC1); // 8 bits per component, 1 channel
unsigned long rowBytes = cvMat.step[0];
if (rowBytes % 16) {
rowBytes = ((rowBytes / 16) + 1) * 16;
}
CGContextRef contextRef = CGBitmapContextCreate(cvMat.data,
cols,
rows,
8,
rowBytes,
colorSpace,
kCGImageAlphaNone |
kCGBitmapByteOrderDefault);
CGContextDrawImage(contextRef, CGRectMake(0, 0, cols, rows), image);
CGContextRelease(contextRef);
CGColorSpaceRelease(colorSpace);
return cvMat;
}