Frage

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. So if there is an easier way to achieve what I'm trying to do, I'd welcome any tips on that. 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

PS: I have tried adding the "-all_load" to "Other Linker Flags" but that doesn't work either.

War es hilfreich?

Lösung

Adding the NSImage+OpenCV.mm file to your project isn't enough; you also have to add it to your target. You can do this from the File Inspector when that file is selected, or by dragging it from the Project Navigator into the target's Compile Sources build phase.

In the future, when you add new existing source files to your project, always look over the list of targets in the options sheet and make sure the right targets are checked.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top