将UIImage转换为cv :: Mat

时间:2013-01-15 07:07:46

标签: ios objective-c opencv

我有一个UIImage,它是从iPhone相机拍摄的照片,现在我希望将UIImage转换为cv :: Mat(OpenCV)。我使用以下代码行来完成此任务:

-(cv::Mat)CVMat
{

CGColorSpaceRef colorSpace = CGImageGetColorSpace(self.CGImage);
CGFloat cols = self.size.width;
CGFloat rows = self.size.height;

cv::Mat cvMat(rows, cols, CV_8UC4); // 8 bits per component, 4 channels

CGContextRef contextRef = CGBitmapContextCreate(cvMat.data,                 // Pointer to backing data
                                                cols,                      // Width of bitmap
                                                rows,                     // Height of bitmap
                                                8,                          // Bits per component
                                                cvMat.step[0],              // Bytes per row
                                                colorSpace,                 // Colorspace
                                                kCGImageAlphaNoneSkipLast |
                                                kCGBitmapByteOrderDefault); // Bitmap info flags

CGContextDrawImage(contextRef, CGRectMake(0, 0, cols, rows), self.CGImage);
CGContextRelease(contextRef);

return cvMat;
}

此代码适用于横向模式下的UIImage,但当我使用与从纵向模式拍摄的图像相同的代码时,图像会向右旋转90度。

我是iOS和Objective C的新手,因此我无法弄清楚出了什么问题。

有人可以告诉我代码有什么问题,或者我错过了什么。

2 个答案:

答案 0 :(得分:43)

这是因为UIImage实际上不是肖像。使用iPhone相机拍摄的所有照片都是原始位图状态的横向,例如3264宽x 2488高。 “肖像”照片通过图像中设置的方向EXIF标志显示,例如,照片库应用程序可根据此标志和相机的查看方向旋转图像。

该标志还会影响UIImage报告其宽度和高度属性的方式,将它们从位图值转换为标记为纵向的图像。

cv::Mat不打扰其中任何一个。这意味着(i)在翻译为cv::Mat时,纵向图像会将size.widthsize.height值换位,以及(ii)从cv::Mat翻译时,您将拥有失去了方向旗。

UIImage转到cv::Mat时处理此问题的最简单方法是在图像标记为肖像时交换宽度和高度值:

if  (self.imageOrientation == UIImageOrientationLeft
      || self.imageOrientation == UIImageOrientationRight) {
         cols = self.size.height;
         rows = self.size.width;
    }

cv::Mat转换回UIImage时,您需要恢复方向标记。假设您的cv::Mat -> UIImage代码包含以下内容:

self = [self initWithCGImage:imageRef];

您可以使用此方法,并按照原始方式重置方向。

self = [self initWithCGImage:imageRef scale:1 orientation:orientation];

答案 1 :(得分:10)

您应该考虑使用原生OpenCV函数来转换前后:

#import <opencv2/imgcodecs/ios.h>
...
UIImage* MatToUIImage(const cv::Mat& image);
void UIImageToMat(const UIImage* image,
                         cv::Mat& m, bool alphaExist = false);

注意:如果你的UIImage来自相机,你应该正常化&#39;转换为cv::Mat之前的(上传后的iOS UIImagePickerController结果图像方向),因为OpenCV没有考虑Exif数据。如果你不这样做,结果应该是错误的。