将UIImage转换为cv :: Mat

use*_*191 31 opencv objective-c ios

我有一个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;
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

fou*_*dry 44

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

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

cv::Mat不打扰任何一个.这意味着(i)当翻译成cv::Mat肖像图像时,其值size.widthsize.height值将被转换,以及(ii)从cv::Mat您翻译时,您将丢失方向标记.

从去当处理这种情况最简单的方法UIImagecv::Mat是如果图像被标记为肖像交换宽度和高度值:

if  (self.imageOrientation == UIImageOrientationLeft
      || self.imageOrientation == UIImageOrientationRight) {
         cols = self.size.height;
         rows = self.size.width;
    }
Run Code Online (Sandbox Code Playgroud)

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

self = [self initWithCGImage:imageRef];
Run Code Online (Sandbox Code Playgroud)

您可以使用此方法,并根据原始方法重置方向.

self = [self initWithCGImage:imageRef scale:1 orientation:orientation];
Run Code Online (Sandbox Code Playgroud)


cde*_*urs 10

您应该考虑使用本机OpenCV函数进行前后转换:

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

注意:如果你的UIImage来自相机,你应该在转换之前"规范化"它(上传后的iOS UIImagePickerController结果图像方向),cv::Mat因为OpenCV没有考虑Exif数据.如果你不这样做,结果应该是错误的.