【问题标题】:I get the following error [NSImage CVMat]: unrecognized selector sent to instance我收到以下错误 [NSImage CVMat]: unrecognized selector sent to instance
【发布时间】:2025-11-26 07:45:01
【问题描述】:

首先声明:我是 Cocoa 和 Objective-C 的新手。我正在尝试学习使用 Cocoa 和 Opencv,所以我不必处理 Qt。因此,如果有更简单的方法来实现我正在尝试做的事情,我会欢迎任何提示。另外,如果这个问题已经得到解答,如果有人能指出我的答案,我将不胜感激。

我正在使用这篇文章中的代码:NSImage to cv::Mat and vice versa 尝试将我的 NSImage 转换为 Mat 并返回。问题是,我总是最终将无法识别的选择器发送到实例错误。据我了解,此错误是在调用不存在的方法时引发的。但是我调用的方法确实存在。我在这里完全不知所措,非常感谢您对愚蠢的话语的帮助。该代码与上面链接的帖子完全相同。错误如下:

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

此错误总是在以下行抛出:

cvMat_test = [image CVMat];

我假设这意味着 Xcode 看不到 CVMat 方法。但是,当我尝试使用 NSImage 实例调用该方法时,Xcode 将该方法列为项目的方法之一。

这是我链接到的另一篇文章中的代码,以防人们不想点击:

//
//  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

实现文件:

//
//  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

我对文件的使用:

#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:我尝试将“-all_load”添加到“其他链接器标志”,但这也不起作用。

【问题讨论】:

  • 您是否尝试通过静态库添加该类别?如果是这样,请确保 NSImage+OpenCV.mm 文件处于静态库的 Compile Sources 构建阶段。如果您不想将它放在任何类型的库中,请确保 NSImage+OpenCV.mm 文件处于应用程序的编译源构建阶段。
  • @PeterHosey 真是太简单了。所以我的问题不在于 Obj-C 或 Cocoa,而是我对 Xcode 缺乏了解。我刚刚将 NSImage+OpenCV 复制到 Build Phases -> Compile Sources。您能否写下您的评论作为答案,以便我支持并接受它?

标签: objective-c cocoa opencv nsimage mat


【解决方案1】:

将 NSImage+OpenCV.mm 文件添加到您的项目是不够的;您还必须将其添加到您的目标中。您可以在选择该文件时从文件检查器中执行此操作,或者将其从项目导航器拖到目标的编译源构建阶段。

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

【讨论】:

    最近更新 更多