Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Converting UIImage to cv::Mat

I have a UIImage which is a pic captured from an iPhone Camera now I want the UIImage to be converted to cv::Mat (OpenCV). I am using the following lines of code to accomplish this :

-(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; } 

This Code works fine for the UIImage in Landscape mode but when I use the same code with Images taken from Portrait mode the images gets rotated by 90 degrees towards the right.

I am a newbie in iOS and Objective C and hence I am not able to figure out what is wrong.

Can somebody tell me what is wrong with the code or am I missing out something.

like image 821
user1606191 Avatar asked Jan 15 '13 07:01

user1606191


1 Answers

This will be because the UIImage is not actually portrait. All photos taken with the iPhone camera are landscape in their raw bitmap state, eg 3264 wide x 2488 high. A "portrait" photo is displayed as such by the orientation EXIF flag set in the image, which is honoured, for example, by the photo library app which swivels images according to this flag and the viewing orientation of the camera.

The flag also affects how UIImage reports its width and height properties, transposing them from their bitmap values for images flagged as portrait.

cv::Mat doesn't bother with any of that. This means that (i) when translating to cv::Mat a portrait image will have its size.width and size.height values transposed, and (ii) when translating back from cv::Mat you will have lost the orientation flag.

The simplest way to handle this when going from UIImage to cv::Mat is to swap width and height values if the image is flagged as portrait:

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

When translating back from cv::Mat to UIImage, you will want to reinstate the orientation flag. Assuming your cv::Mat -> UIImage code contains this:

self = [self initWithCGImage:imageRef]; 

you can use this method instead, and reset the orientation as per the original.

self = [self initWithCGImage:imageRef scale:1 orientation:orientation]; 
like image 174
foundry Avatar answered Oct 11 '22 13:10

foundry