Created
February 1, 2012 09:08
-
-
Save dominiklessel/1716068 to your computer and use it in GitHub Desktop.
NSImage to cv::Mat and vice versa
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Import helper | |
#import "NSImage+OpenCV.h" | |
// Example usage … | |
cv::Mat cvMat_test; | |
NSImage *image = [NSImage imageNamed:@"test.jpg"]; | |
cvMat_test = [image CVMat]; | |
[myImageView setImage:[NSImage imageWithCVMat:cvMat_test]]; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// NSImage+OpenCV.h | |
// | |
#import <AppKit/AppKit.h> | |
@interface NSImage (NSImage_OpenCV) { | |
} | |
+(NSImage*)imageWithCVMat:(const cv::Mat&)cvMat; | |
-(id)initWithCVMat:(const cv::Mat&)cvMat; | |
@property(nonatomic, readonly) cv::Mat CVMat; | |
@property(nonatomic, readonly) cv::Mat CVGrayscaleMat; | |
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// NSImage+OpenCV.mm | |
// | |
#import "NSImage+OpenCV.h" | |
static void ProviderReleaseDataNOP(void *info, const void *data, size_t size) | |
{ | |
return; | |
} | |
@implementation NSImage (NSImage_OpenCV) | |
-(CGImageRef)CGImage | |
{ | |
CGContextRef bitmapCtx = CGBitmapContextCreate(NULL/*data - pass NULL to let CG allocate the memory*/, | |
[self size].width, | |
[self size].height, | |
8 /*bitsPerComponent*/, | |
0 /*bytesPerRow - CG will calculate it for you if it's allocating the data. This might get padded out a bit for better alignment*/, | |
[[NSColorSpace genericRGBColorSpace] CGColorSpace], | |
kCGBitmapByteOrder32Host|kCGImageAlphaPremultipliedFirst); | |
[NSGraphicsContext saveGraphicsState]; | |
[NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithGraphicsPort:bitmapCtx flipped:NO]]; | |
[self drawInRect:NSMakeRect(0,0, [self size].width, [self size].height) fromRect:NSZeroRect operation:NSCompositeCopy fraction:1.0]; | |
[NSGraphicsContext restoreGraphicsState]; | |
CGImageRef cgImage = CGBitmapContextCreateImage(bitmapCtx); | |
CGContextRelease(bitmapCtx); | |
return cgImage; | |
} | |
-(cv::Mat)CVMat | |
{ | |
CGImageRef imageRef = [self CGImage]; | |
CGColorSpaceRef colorSpace = CGImageGetColorSpace(imageRef); | |
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), imageRef); | |
CGContextRelease(contextRef); | |
CGImageRelease(imageRef); | |
return cvMat; | |
} | |
-(cv::Mat)CVGrayscaleMat | |
{ | |
CGImageRef imageRef = [self CGImage]; | |
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray(); | |
CGFloat cols = self.size.width; | |
CGFloat rows = self.size.height; | |
cv::Mat cvMat = cv::Mat(rows, cols, CV_8UC1); // 8 bits per component, 1 channel | |
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 | |
kCGImageAlphaNone | | |
kCGBitmapByteOrderDefault); // Bitmap info flags | |
CGContextDrawImage(contextRef, CGRectMake(0, 0, cols, rows), imageRef); | |
CGContextRelease(contextRef); | |
CGColorSpaceRelease(colorSpace); | |
CGImageRelease(imageRef); | |
return cvMat; | |
} | |
+ (NSImage *)imageWithCVMat:(const cv::Mat&)cvMat | |
{ | |
return [[NSImage alloc] initWithCVMat:cvMat]; | |
} | |
- (id)initWithCVMat:(const 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); | |
CGImageRef imageRef = CGImageCreate(cvMat.cols, // Width | |
cvMat.rows, // Height | |
8, // Bits per component | |
8 * cvMat.elemSize(), // Bits per pixel | |
cvMat.step[0], // Bytes per row | |
colorSpace, // Colorspace | |
kCGImageAlphaNone | kCGBitmapByteOrderDefault, // Bitmap info flags | |
provider, // CGDataProviderRef | |
NULL, // Decode | |
false, // Should interpolate | |
kCGRenderingIntentDefault); // Intent | |
NSBitmapImageRep *bitmapRep = [[NSBitmapImageRep alloc] initWithCGImage:imageRef]; | |
NSImage *image = [[NSImage alloc] init]; | |
[image addRepresentation:bitmapRep]; | |
CGImageRelease(imageRef); | |
CGDataProviderRelease(provider); | |
CGColorSpaceRelease(colorSpace); | |
return image; | |
} | |
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// NSImage+OpenCV.h | |
// | |
#import <AppKit/AppKit.h> | |
@interface NSImage (NSImage_OpenCV) { | |
} | |
+(NSImage*)imageWithCVMat:(const cv::Mat&)cvMat; | |
-(id)initWithCVMat:(const cv::Mat&)cvMat; | |
@property(nonatomic, readonly) cv::Mat CVMat; | |
@property(nonatomic, readonly) cv::Mat CVGrayscaleMat; | |
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// NSImage+OpenCV.mm | |
// | |
#import "NSImage+OpenCV.h" | |
static void ProviderReleaseDataNOP(void *info, const void *data, size_t size) | |
{ | |
return; | |
} | |
@implementation NSImage (NSImage_OpenCV) | |
-(CGImageRef)CGImage | |
{ | |
CGContextRef bitmapCtx = CGBitmapContextCreate(NULL/*data - pass NULL to let CG allocate the memory*/, | |
[self size].width, | |
[self size].height, | |
8 /*bitsPerComponent*/, | |
0 /*bytesPerRow - CG will calculate it for you if it's allocating the data. This might get padded out a bit for better alignment*/, | |
[[NSColorSpace genericRGBColorSpace] CGColorSpace], | |
kCGBitmapByteOrder32Host|kCGImageAlphaPremultipliedFirst); | |
[NSGraphicsContext saveGraphicsState]; | |
[NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithGraphicsPort:bitmapCtx flipped:NO]]; | |
[self drawInRect:NSMakeRect(0,0, [self size].width, [self size].height) fromRect:NSZeroRect operation:NSCompositeCopy fraction:1.0]; | |
[NSGraphicsContext restoreGraphicsState]; | |
CGImageRef cgImage = CGBitmapContextCreateImage(bitmapCtx); | |
CGContextRelease(bitmapCtx); | |
return cgImage; | |
} | |
-(cv::Mat)CVMat | |
{ | |
CGImageRef imageRef = [self CGImage]; | |
CGColorSpaceRef colorSpace = CGImageGetColorSpace(imageRef); | |
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), imageRef); | |
CGContextRelease(contextRef); | |
CGImageRelease(imageRef); | |
return cvMat; | |
} | |
-(cv::Mat)CVGrayscaleMat | |
{ | |
CGImageRef imageRef = [self CGImage]; | |
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray(); | |
CGFloat cols = self.size.width; | |
CGFloat rows = self.size.height; | |
cv::Mat cvMat = cv::Mat(rows, cols, CV_8UC1); // 8 bits per component, 1 channel | |
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 | |
kCGImageAlphaNone | | |
kCGBitmapByteOrderDefault); // Bitmap info flags | |
CGContextDrawImage(contextRef, CGRectMake(0, 0, cols, rows), imageRef); | |
CGContextRelease(contextRef); | |
CGColorSpaceRelease(colorSpace); | |
CGImageRelease(imageRef); | |
return cvMat; | |
} | |
+ (NSImage *)imageWithCVMat:(const cv::Mat&)cvMat | |
{ | |
return [[NSImage alloc] initWithCVMat:cvMat]; | |
} | |
- (id)initWithCVMat:(const 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); | |
CGImageRef imageRef = CGImageCreate(cvMat.cols, // Width | |
cvMat.rows, // Height | |
8, // Bits per component | |
8 * cvMat.elemSize(), // Bits per pixel | |
cvMat.step[0], // Bytes per row | |
colorSpace, // Colorspace | |
kCGImageAlphaNone | kCGBitmapByteOrderDefault, // Bitmap info flags | |
provider, // CGDataProviderRef | |
NULL, // Decode | |
false, // Should interpolate | |
kCGRenderingIntentDefault); // Intent | |
NSBitmapImageRep *bitmapRep = [[NSBitmapImageRep alloc] initWithCGImage:imageRef]; | |
NSImage *image = [[NSImage alloc] init]; | |
[image addRepresentation:bitmapRep]; | |
CGImageRelease(imageRef); | |
CGDataProviderRelease(provider); | |
CGColorSpaceRelease(colorSpace); | |
return image; | |
} | |
@end |
Thank you for doing the heavy lifting of converting. ;o) To answer the above question, if you are using Xcode, you change the .m to a .mm file.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hello-
A little bit of a Objective C++ newbie here. Just curious: how did you get C++ types to work inside of an Objective C header?
Cheers