Skip to content

Instantly share code, notes, and snippets.

@tomas789
Last active May 29, 2024 15:13
Show Gist options
  • Save tomas789/f54080e88e8cfa187228322823328c01 to your computer and use it in GitHub Desktop.
Save tomas789/f54080e88e8cfa187228322823328c01 to your computer and use it in GitHub Desktop.
OpenCV <-> Objective-C++ (UIImage) conversion

OpenCV -> UIImage

cv::Mat mat /* = ... */;
UIImage* image = [UIImage fromCvMat:mat];

UIImage -> OpenCV

UIImage* image /* = ... */;
cv::Mat mat = [UIImage toCvMat:image];

Original conversion code from OpenCV iOS tutorial, video processing

#import <UIKit/UIKit.h>
#ifdef __cplusplus
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdocumentation"
#import <opencv2/core/core.hpp>
#pragma clang pop
#endif
@interface UIImage (UIImage_OpenCvConversion)
#ifdef __cplusplus
+ (cv::Mat)toCvMat:(UIImage *)image;
+ (cv::Mat)toCvMatGray:(UIImage *)image;
+ (UIImage *)fromCvMat:(cv::Mat)cvMat;
#endif
@end
#import "UIImage+OpenCvConversion.h"
#ifdef __cplusplus
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdocumentation"
#import <opencv2/core/core.hpp>
#import <opencv2/imgproc/imgproc.hpp>
#pragma clang pop
#endif
@implementation UIImage (UIImage_OpenCvConversion)
#ifdef __cplusplus
+ (cv::Mat)toCvMat:(UIImage *)image
{
CGColorSpaceRef colorSpace = CGImageGetColorSpace(image.CGImage);
CGFloat cols = image.size.width;
CGFloat rows = image.size.height;
cv::Mat cvMat(rows, cols, CV_8UC4); // 8 bits per component, 4 channels (color channels + alpha)
CGContextRef contextRef = CGBitmapContextCreate(cvMat.data, // Pointer to 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), image.CGImage);
CGContextRelease(contextRef);
return cvMat;
}
+ (cv::Mat)toCvMatGray:(UIImage *)image
{
CGColorSpaceRef colorSpace = CGImageGetColorSpace(image.CGImage);
CGFloat cols = image.size.width;
CGFloat rows = image.size.height;
cv::Mat cvMat(rows, cols, CV_8UC1); // 8 bits per component, 1 channels
CGContextRef contextRef = CGBitmapContextCreate(cvMat.data, // Pointer to 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), image.CGImage);
CGContextRelease(contextRef);
return cvMat;
}
+ (UIImage *)fromCvMat:(cv::Mat)cvMat
{
NSData *data = [NSData dataWithBytes:cvMat.data length:cvMat.elemSize()*cvMat.total()];
CGColorSpaceRef colorSpace;
if (cvMat.elemSize() == 1) {
colorSpace = CGColorSpaceCreateDeviceGray();
} else {
colorSpace = CGColorSpaceCreateDeviceRGB();
}
CGDataProviderRef provider = CGDataProviderCreateWithCFData((__bridge CFDataRef)data);
// Creating CGImage from cv::Mat
CGImageRef imageRef = CGImageCreate(cvMat.cols, //width
cvMat.rows, //height
8, //bits per component
8 * cvMat.elemSize(), //bits per pixel
cvMat.step[0], //bytesPerRow
colorSpace, //colorspace
kCGImageAlphaNone|kCGBitmapByteOrderDefault,// bitmap info
provider, //CGDataProviderRef
NULL, //decode
false, //should interpolate
kCGRenderingIntentDefault //intent
);
// Getting UIImage from CGImage
UIImage *finalImage = [UIImage imageWithCGImage:imageRef];
CGImageRelease(imageRef);
CGDataProviderRelease(provider);
CGColorSpaceRelease(colorSpace);
return finalImage;
}
#endif
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment