IPhoneカメラからキャプチャした写真であるUIImageがあります。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とObjectiveCの初心者なので、何が悪いのか理解できません。
誰かがコードの何が問題なのか教えてもらえますか、それとも私は何かを見逃していますか?.
これは、UIImage
が実際には縦向きではないためです。 iPhoneカメラで撮影されたすべての写真は、生のビットマップ状態の風景です。たとえば、幅3264x高さ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];
ネイティブのOpenCV関数を使用して前後に変換することを検討する必要があります。
#import <opencv2/imgcodecs/ios.h>
...
UIImage* MatToUIImage(const cv::Mat& image);
void UIImageToMat(const UIImage* image,
cv::Mat& m, bool alphaExist = false);
注:UIImageがカメラからのものである場合、OpenCVはExifデータを考慮しないため、cv::Mat
に変換する前に、それを「正規化」する必要があります(アップロード後のiOS UIImagePickerController結果画像の向き)。そうしないと、結果の方向が間違ってしまうはずです。