Thursday, 15 August 2013

I get the following error [NSImage CVMat]: unrecognized selector sent to instance

I get the following error [NSImage CVMat]: unrecognized selector sent to
instance

First a disclaimer: I am new to Cocoa and Objective-C. I am trying to
learn to work with Cocoa and Opencv so I don't have to deal with Qt. Also,
if this question has already been answered, I'd appreciate it if someone
could point me to the answer.
I am using the code from this post: NSImage to cv::Mat and vice versa to
try and convert my NSImage to Mat and back. The problem is, I always end
up getting the unrecognized selector sent to instance error. As far as I
understand this error, it is thrown when a method that doesn't exist is
called. But the method that I am calling does exist. I'm at a complete
loss here and would really appreciate some help in dumbed down words. The
code is exactly the same as the post linked to above. The error is as
follows:
2013-08-15 17:24:52.554 Espejismo[2368:303] -[NSImage CVMat]: unrecognized
selector sent to instance 0x1020198d0
2013-08-15 17:25:03.969 Espejismo[2368:303] An uncaught exception was raised
2013-08-15 17:25:03.969 Espejismo[2368:303] -[NSImage CVMat]: unrecognized
selector sent to instance 0x1020198d0
2013-08-15 17:25:03.972 Espejismo[2368:303] (
0 CoreFoundation 0x00007fff93e76b06
__exceptionPreprocess + 198
1 libobjc.A.dylib 0x00007fff97e0c3f0
objc_exception_throw + 43
2 CoreFoundation 0x00007fff93f0d40a
-[NSObject(NSObject) doesNotRecognizeSelector:] + 186
3 CoreFoundation 0x00007fff93e6502e
___forwarding___ + 414
4 CoreFoundation 0x00007fff93eaadad
__forwarding_prep_1___ + 237
5 Espejismo 0x000000010000209e -[TestView
initWithFrame:] + 334
6 AppKit 0x00007fff942c00a3
-[NSCustomView nibInstantiateWithObjectInstantiator:] + 657
7 AppKit 0x00007fff9429f625
-[NSIBObjectData instantiateObject:] + 266
8 AppKit 0x00007fff9429edf7
-[NSIBObjectData nibInstantiateWithOwner:topLevelObjects:] + 337
9 AppKit 0x00007fff9427e11d loadNib + 317
10 AppKit 0x00007fff9427d649
+[NSBundle(NSNibLoading) _loadNibFile:nameTable:withZone:ownerBundle:]
+ 219
11 AppKit 0x00007fff9427d47e
-[NSBundle(NSNibLoading) loadNibNamed:owner:topLevelObjects:] + 200
12 AppKit 0x00007fff9427d25e
+[NSBundle(NSNibLoading) loadNibNamed:owner:] + 360
13 AppKit 0x00007fff942799ff
NSApplicationMain + 398
14 Espejismo 0x0000000100001112 main + 34
15 libdyld.dylib 0x00007fff922077e1 start + 0
)
2013-08-15 17:25:03.973 Espejismo[2368:303] *** Terminating app due to
uncaught exception 'NSInvalidArgumentException', reason: '-[NSImage
CVMat]: unrecognized selector sent to instance 0x1020198d0'
*** First throw call stack:
(
0 CoreFoundation 0x00007fff93e76b06
__exceptionPreprocess + 198
1 libobjc.A.dylib 0x00007fff97e0c3f0
objc_exception_throw + 43
2 CoreFoundation 0x00007fff93f0d40a
-[NSObject(NSObject) doesNotRecognizeSelector:] + 186
3 CoreFoundation 0x00007fff93e6502e
___forwarding___ + 414
4 CoreFoundation 0x00007fff93eaadad
__forwarding_prep_1___ + 237
5 Espejismo 0x000000010000209e -[TestView
initWithFrame:] + 334
6 AppKit 0x00007fff942c00a3
-[NSCustomView nibInstantiateWithObjectInstantiator:] + 657
7 AppKit 0x00007fff9429f625
-[NSIBObjectData instantiateObject:] + 266
8 AppKit 0x00007fff9429edf7
-[NSIBObjectData nibInstantiateWithOwner:topLevelObjects:] + 337
9 AppKit 0x00007fff9427e11d loadNib + 317
10 AppKit 0x00007fff9427d649
+[NSBundle(NSNibLoading) _loadNibFile:nameTable:withZone:ownerBundle:]
+ 219
11 AppKit 0x00007fff9427d47e
-[NSBundle(NSNibLoading) loadNibNamed:owner:topLevelObjects:] + 200
12 AppKit 0x00007fff9427d25e
+[NSBundle(NSNibLoading) loadNibNamed:owner:] + 360
13 AppKit 0x00007fff942799ff
NSApplicationMain + 398
14 Espejismo 0x0000000100001112 main + 34
15 libdyld.dylib 0x00007fff922077e1 start + 0
)
libc++abi.dylib: terminate called throwing an exception
This error is always thrown at the following line:
cvMat_test = [image CVMat];
Which I'm assuming means that Xcode can't see the CVMat method. However,
Xcode lists that method as one of the methods for the project when I try
to call it with an instance of NSImage.
Here's the code from the other post that I linked to in case people don't
want to click over:
//
// 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
The implementation file:
//
// 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] autorelease];
}
- (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
My use of the file:
#import "AppDelegate.h"
@implementation AppDelegate
- (void)dealloc
{
[super dealloc];
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
// Insert code here to initialize your application
cv::Mat cvMat_test;
NSImage *image = [NSImage imageNamed:@"image.jpg"];
cvMat_test = [image CVMat];
}
@end

No comments:

Post a Comment