0

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.

4

1 回答 1

1

将 NSImage+OpenCV.mm 文件添加到您的项目是不够的;您还必须将其添加到您的目标中。您可以在选择该文件时从 File Inspector 执行此操作,或者将其从 Project Navigator 拖到目标的 Compile Sources 构建阶段。

将来,当您将新的现有源文件添加到项目中时,请始终查看选项表中的目标列表并确保检查了正确的目标。

于 2013-08-16T16:36:34.210 回答