我有一个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的新手,因此我无法弄清楚出了什么问题。
有人可以告诉我代码有什么问题,或者我错过了什么。
答案 0 :(得分:43)
这是因为UIImage
实际上不是肖像。使用iPhone相机拍摄的所有照片都是原始位图状态的横向,例如3264宽x 2488高。 “肖像”照片通过图像中设置的方向EXIF标志显示,例如,照片库应用程序可根据此标志和相机的查看方向旋转图像。
该标志还会影响UIImage
报告其宽度和高度属性的方式,将它们从位图值转换为标记为纵向的图像。
cv::Mat
不打扰其中任何一个。这意味着(i)在翻译为cv::Mat
时,纵向图像会将size.width
和size.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数据。如果你不这样做,结果应该是错误的。