为NSImage工作CIAreaHistogram / CIHistogramDisplayFilter示例

时间:2016-10-24 16:01:45

标签: objective-c image cocoa core-graphics core-image

我不知道如何使用NSImageCIAreaHistogram过滤器从CIHistogramDisplayFilter输入中获取实际,有意义的直方图图像。

我在这里阅读了Apple的“核心图像过滤器参考”和相关帖子,但无论我尝试什么,我都没有得到有意义的输出。

到目前为止,这是我的代码:

- (void) testHist3:(NSImage *)image {

    CIContext* context = [[NSGraphicsContext currentContext] CIContext];

    NSBitmapImageRep *rep = [image bitmapImageRepresentation];
    CIImage *ciImage = [[CIImage alloc] initWithBitmapImageRep:rep];


    ciImage = [CIFilter filterWithName:@"CIAreaHistogram" keysAndValues:kCIInputImageKey, ciImage, @"inputExtent", ciImage.extent, @"inputScale", [NSNumber numberWithFloat:1.0], @"inputCount", [NSNumber numberWithFloat:256.0], nil].outputImage;
    ciImage = [CIFilter filterWithName:@"CIHistogramDisplayFilter" keysAndValues:kCIInputImageKey, ciImage, @"inputHeight", [NSNumber numberWithFloat:100.0], @"inputHighLimit", [NSNumber numberWithFloat:1.0], @"inputLowLimit", [NSNumber numberWithFloat:0.0], nil].outputImage;


    CGImageRef cgImage2 = [context createCGImage:ciImage fromRect:ciImage.extent];
    NSImage *img2 = [[NSImage alloc] initWithCGImage:cgImage2 size:ciImage.extent.size];

    NSLog(@"Histogram image: %@", img2);
    self.histImage = img2;


}

我得到的是具有零表示(=不可见)的64x100图像。如果我使用

创建CI上下文
CIContext *context = [[CIContext alloc] init];

然后生成的图像是灰色的,但至少它确实有一个表示:

Histogram image: <NSImage 0x6100002612c0 Size={64, 100} Reps=(
    "<NSCGImageSnapshotRep:0x6100002620c0 cgImage=<CGImage 0x6100001a1880>>" )>

输入图像是1024x768 JPEG图像。

我对Core Image或Core Graphics几乎没有经验,所以错误可能是转换回NSImage ......有什么想法吗?

编辑 2016-10-26:通过rickster非常全面的答案,我能够取得很大的进步。

确实是inputExtent参数弄乱了我的结果。提供CIVector解决了问题。我发现你不能把它留到默认值;我不知道默认值是什么,但它不是输入图像的完整大小。 (我发现通过过滤器运行图像和镜像版本;我得到了不同的直方图。)

修改 2016-10-28:

所以,我现在有一个可用的,可显示的直方图;我的下一步是弄清楚“中间”直方图(来自滤波器的256x1像素图像)如何能够包含实际的直方图信息,即使除了最后一个像素之外的所有直方图总是(0,0,0,0)。

1 个答案:

答案 0 :(得分:1)

我认为代码中的[image bitmapImageRepresentation]是一个大致相当于(NSBitmapImageRep *)image.representations[0]的本地类别方法?否则,首先要确保您获得了正确的输入。

接下来,看起来您将ciImage.extent的原始输出传递给过滤器参数 - 假设所述参数需要CIVector对象而不是CGRect结构,那么'可能在运行时将输入结果插入过滤器。通过使用基于字典的过滤方法filterWithName:withInputParametersimageByApplyingFilter:withInputParameters:,您可以获得更有用的此类问题诊断 - 如果您尝试将nil传递给过滤器密钥或通过一些不是正确对象的东西,你会得到一个编译时错误。后者为您提供了一种简单的方法,可以直接从输入图像到输出图像或链式过滤器,而无需创建中间CIFilter个对象,并且需要在每个对象上设置输入图像。

相关提示:您传递的大多数参数都是这些过滤器的默认值,因此您只能传递所需的值:

CIImage *hist = [inputImage imageByApplyingFilter:@"CIAreaHistogram"
                              withInputParameters:@{ @"inputCount": @256 }];
CIImage *outputImage = [hist imageByApplyingFilter:@"CIHistogramDisplayFilter"
                               withInputParameters:nil];

最后,根据您的输入图像的样子,您可能仍会从CIHistogramDisplayFilter获得几乎 - 全灰色图像,因为所有直方图区间可能都有非常小的条形图。我为Lenna得到以下信息:

small bars histogram

增加kCIInputScaleKey的值可以帮助解决这个问题。

此外,您无需通过CGImage即可从CIImage转到NSImage - 创建NSCIImageRep而AppKit会自动管理CIContext当需要为显示/输出渲染图像时,在幕后。

// input from NSImage
NSBitmapImageRep *inRep = [nsImage bitmapImageRepresentation];
CIImage *inputImage = [[CIImage alloc] initWithBitmapImageRep:inRep];

CIImage *outputImage = // filter, rinse, repeat

// output to NSImage
NSCIImageRep *outRep = [NSCIImageRep imageRepWithCIImage: outputImage];
NSImage *outNSImage = [[NSImage alloc] init];
[outNSImage addRepresentation: outRep];