如何获得有意义的CIAreaHistogram输出?

Ora*_*kan 5 cocoa objective-c core-image cifilter

我想计算a的直方图CGImage.我正在使用CIAreaHistogram内置CoreImage过滤器.

Justin Mrkva已经做了类似的事情.他说:

我得到直方图本身的CIImage,然后我通过自定义内核运行(参见结尾)将alpha值设置为1(因为否则直方图计算的alpha值被预乘)然后将其转换为NSBitmapImageRep.

我的问题是:是否有可能获得直方图数据而无需创建自定义内核?如果是这样,怎么样?

以下代码只是尝试渲染直方图而不修改alpha值:

- (void)printHistogram:(CGImageRef)img {

    NSNumber* buckets = @10;

    CIImage* img_ = [CIImage imageWithCGImage:img];

    CIFilter* histF = [CIFilter filterWithName:@"CIAreaHistogram"];
    [histF setValue:img_ forKey:@"inputImage"];
    [histF setValue:[CIVector vectorWithX:0.0
                                        Y:0.0
                                        Z:CGImageGetWidth(img)
                                        W:CGImageGetHeight(img)]
             forKey:@"inputExtent"];
    [histF setValue:buckets forKey:@"inputCount"];
    [histF setValue:@1.0 forKey:@"inputScale"];

    CIImage* histImg = [histF valueForKey:@"outputImage"];

    int rowBytes = [buckets intValue] * 4; // ARGB has 4 components
    uint8_t byteBuffer[rowBytes]; // Buffer to render into
    CGColorSpaceRef cspace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);

    CIContext* ctx = [[CIContext alloc] init];
    [ctx render:histImg
       toBitmap:byteBuffer
       rowBytes:rowBytes
         bounds:[histImg extent]
         format:kCIFormatARGB8
     colorSpace:cspace];

    CGColorSpaceRelease(cspace);

    for (int i=0; i<[buckets intValue]; i++) {
        const uint8_t* pixel = &byteBuffer[i*4];
        printf("%d:%u-%u-%u-%u\n",i,pixel[0],pixel[1],pixel[2],pixel[3]);
    }

}   
Run Code Online (Sandbox Code Playgroud)

给出输出(当在彩色照片上运行时):

0:0-0-0-0
1:0-0-0-0
2:0-0-0-0
3:0-0-0-0
4:0-0-0-0
5:0-0-0-0
6:0-0-0-0
7:0-0-0-0
8:0-0-0-0
9:255-33-6-7
Run Code Online (Sandbox Code Playgroud)

我尝试CIColorMatrix在渲染之前将alpha值设置为1.0:

CIFilter* biasF = [CIFilter filterWithName:@"CIColorMatrix"];
[biasF setDefaults];
[biasF setValue:histImg forKey:@"inputImage"];
[biasF setValue:[CIVector vectorWithX:0.0 Y:0.0 Z:0.0 W:1.0] forKey:@"inputBiasVector"];
Run Code Online (Sandbox Code Playgroud)

即使输出格式是ARGB,根据我从核心图像过滤器参考中所理解的,alpha分量是向量中的最后一个值(因此W:1.0).

但是这产生了以下输出:

0:255-255-255-255
1:255-255-255-255
2:255-255-255-255
3:255-255-255-255
4:255-255-255-255
5:255-255-255-255
6:255-255-255-255
7:255-255-255-255
8:255-255-0-255
9:255-66-11-15
Run Code Online (Sandbox Code Playgroud)

所有的帮助和建议将不胜感激!


编辑:我知道这个问题似乎相似.但是,接受的答案规定:

缺点是:您需要将值读取为浮点数,而不是整数,这意味着您必须将CGBitmapContext连接到blit.或者,如果您将所有内容保留在CI域中,您将需要另一个过滤器来读取数据并使用它打印出一些内容.

然而,看看Justin Mrkva的问题让我觉得应该可以获得整数值...如果我的想法有误,请告诉我.

再次感谢!


编辑2:所有的拳头,感谢David和jstn的评论.对不起,我花了很长时间才回到这里.我在一个项目上昼夜不停地工作(实际上是那个导致我遇到这个问题的项目,但我最终使用了一种完全不同的方法,不再使用CIAreaHistogram).现在我终于有了一些时间,我想回到这一点.即使我本身并不需要它,我仍然想要了解这个东西是如何工作的!

根据David Hayward的建议,我做了以下修改.

- (void)printHistogram:(CGImageRef)img {

    NSNumber* buckets = @10;

    CIImage* img_ = [CIImage imageWithCGImage:img];

    CIFilter* histF = [CIFilter filterWithName:@"CIAreaHistogram"];
    [histF setValue:img_ forKey:@"inputImage"];
    [histF setValue:[CIVector vectorWithX:0.0
                                        Y:0.0
                                        Z:CGImageGetWidth(img)
                                        W:CGImageGetHeight(img)]
             forKey:@"inputExtent"];
    [histF setValue:buckets forKey:@"inputCount"];
    [histF setValue:@1.0 forKey:@"inputScale"];

    CIImage* histImg = [histF valueForKey:@"outputImage"];

    NSUInteger arraySize = [buckets intValue] * 4; // ARGB has 4 components

    // CHANGE 1: Since I will be rendering in float values, I set up the
    //           buffer using CGFloat
    CGFloat byteBuffer[arraySize]; // Buffer to render into

    // CHANGE 2: I wasn't supposed to call [[CIContext alloc] init]
    //           this is a more proper way of getting the context
    CIContext* ctx = [[NSGraphicsContext currentContext] CIContext];

    // CHANGE 3: I use colorSpace:NULL to use the output cspace of the ctx
    // CHANGE 4: Format is now kCIFormatRGBAf
    [ctx render:histImg
       toBitmap:byteBuffer
       rowBytes:arraySize
         bounds:[histImg extent]
         format:kCIFormatRGBAf
     colorSpace:NULL]; // uses the output cspace of the contetxt

    // CHANGE 5: I print the float values
    for (int i=0; i<[buckets intValue]; i++) {
        const CGFloat* pixel = &byteBuffer[i*4];
        printf("%d: %0.2f , %0.2f , %0.2f , %0.2f\n", i,pixel[0],pixel[1],pixel[2],pixel[3]);
    }
}   
Run Code Online (Sandbox Code Playgroud)

这给出了以下输出:

0: 0.00 , 0.00 , 0.00 , 0.00
1: 0.00 , 0.00 , 0.00 , 0.00
2: 0.00 , 0.00 , 0.00 , 0.00
3: 0.00 , 0.00 , 0.00 , 0.00
4: 0.00 , 0.00 , 0.00 , 0.00
5: 0.00 , 0.00 , 0.00 , 0.00
6: 0.00 , 0.00 , 1.00 , 0.00
7: 0.00 , 0.00 , 0.00 , 0.00
8: 0.00 , 0.00 , 0.00 , 0.00
9: 3.00 , 0.00 , 0.00 , 0.00
Run Code Online (Sandbox Code Playgroud)

使用各种格式以及如何解析信息会产生截然不同且荒谬的输出.

我很确定问题在于没有正确理解位图数据的表示方式.

还有什么建议?

Dav*_*ard 1

三点建议:

  • 使用 inputScale 获得直方图计数。如果 inputScale 为 1,则生成的直方图 bin 值将为 1.0(如果渲染为 ARGB8,则为 255)(如果整个区域具有该 bin 值)
  • 将 CI 的工作色彩空间传递给 render:toBitmap:。在 Mavericks 上,工作空间是 kCGColorSpaceGenericRGBLinear。在 Yosemite 上它是线性 sRGB。
  • 在 OS X 上,您可以使用 kCIFormatRGBAf 来获取浮点数据
  • 在 iOS 上,您可以使用 kCIFormatRGBAh 来获取半浮点数据