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

7
我想计算CGImage的直方图。我正在使用内置于CoreImage滤镜的CIAreaHistogram
Justin Mrkva已经做了something along similar lines。他说:
引用: 我获取直方图本身的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]);
    }

}   

给出输出(在彩色照片上运行时):
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

我尝试使用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"];

尽管输出格式为ARGB,但根据Core Image Filter Reference的理解,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

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


编辑:我知道这个问题看起来很相似。然而,被接受的答案规定:

简单来说:你需要将值作为浮点数读取,而不是整数,这意味着你需要连接一个CGBitmapContext进行复制。或者如果你保持一切在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]);
    }
}   

这将产生以下输出:
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

玩弄格式的变化以及信息解析方式的不同会导致截然不同和荒谬的输出结果。
我相当确定问题在于没有正确理解位图数据的表示方式。
还有其他建议吗?
6个回答

1

三个建议:

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

David,iOS中是否有使用kCIFormatRGBAf之外的替代方案,因为它不可用?此外,即使使用EAGLContext进行渲染,使用CIAreaHistogram会看到高CPU使用率是正常的吗?我在CIFunHouse中加载它时获得大约相同的性能。 - jstn
谢谢,我看到你更新了答案并提到了kCIFormatRGBAh,但它对我仍然无效(不仅是直方图滤镜输出,而是任何核心图像)。我在这里创建了一个单独的问题,并附上了代码示例,也许你可以看一下:https://dev59.com/Jofca4cB1Zd3GeqPmbMe - jstn
亲爱的David,感谢您的建议。我尝试了一些(请参见上面的EDIT 2)。但我还没有成功。顺便说一下,我不明白您关于使用inputScale的建议。您描述的行为(1.0 = 整个区域覆盖)正是我想要的。对于在给定通道中不是单调的图像,没有一个bin应该是1.0,但总和应始终为1.0。 - Oral Okan

1

在CIAreaHistogram上有一个未记录的方法叫做outputData,可能会很有用。


0

顺便说一下,这里有一个可以获取CIAreaAverage Core Image过滤器值的工作(准确)代码:

- (CIImage *)outputImage
    CGRect inputExtent = [self.inputImage extent];
    CIVector *extent = [CIVector vectorWithX:inputExtent.origin.x
                                           Y:inputExtent.origin.y
                                           Z:inputExtent.size.width
                                           W:inputExtent.size.height];
    CIImage* inputAverage = [CIFilter filterWithName:@"CIAreaAverage" keysAndValues:@"inputImage", self.inputImage, @"inputExtent", extent, nil].outputImage;

    //CIImage* inputAverage = [self.inputImage imageByApplyingFilter:@"CIAreaMinimum" withInputParameters:@{@"inputImage" : inputImage, @"inputExtent" : extent}];
    EAGLContext *myEAGLContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
    NSDictionary *options = @{ kCIContextWorkingColorSpace : [NSNull null] };
    CIContext *myContext = [CIContext contextWithEAGLContext:myEAGLContext options:options];

    size_t rowBytes = 32 ; // ARGB has 4 components
    uint8_t byteBuffer[rowBytes]; // Buffer to render into

    [myContext render:inputAverage toBitmap:byteBuffer rowBytes:rowBytes bounds:[inputAverage extent] format:kCIFormatRGBA8 colorSpace:nil];

    const uint8_t* pixel = &byteBuffer[0];
    float red   = pixel[0] / 255.0;
    float green = pixel[1] / 255.0;
    float blue  = pixel[2] / 255.0;
    NSLog(@"%f, %f, %f\n", red, green, blue);


    return outputImage;

示例输出:

2015-05-23 15:58:10.854 CIFunHouse[2400:489896] BSXPCMessage received error for message: Connection interrupted
2015-05-23 15:58:15.470 CIFunHouse[2400:489913] 0.000000, 0.000000, 0.305882
2015-05-23 15:58:15.582 CIFunHouse[2400:489913] 0.501961, 0.380392, 0.898039
2015-05-23 15:58:15.622 CIFunHouse[2400:489913] 0.564706, 0.917647, 0.831373
2015-05-23 15:58:15.665 CIFunHouse[2400:489913] 0.501961, 0.380392, 0.898039
2015-05-23 15:58:15.706 CIFunHouse[2400:489913] 0.501961, 0.380392, 0.898039
2015-05-23 15:58:15.748 CIFunHouse[2400:489913] 0.564706, 0.917647, 0.831373
2015-05-23 15:58:15.792 CIFunHouse[2400:489913] 0.564706, 0.917647, 0.831373
2015-05-23 15:58:15.834 CIFunHouse[2400:489913] 0.752941, 0.858824, 0.890196
2015-05-23 15:58:15.874 CIFunHouse[2400:489913] 0.690196, 0.309804, 0.819608
2015-05-23 15:58:15.915 CIFunHouse[2400:489913] 0.752941, 0.858824, 0.890196
2015-05-23 15:58:15.956 CIFunHouse[2400:489913] 0.752941, 0.858824, 0.890196
2015-05-23 15:58:15.998 CIFunHouse[2400:489913] 0.752941, 0.858824, 0.890196
2015-05-23 15:58:16.040 CIFunHouse[2400:489913] 0.690196, 0.309804, 0.819608
2015-05-23 15:58:16.079 CIFunHouse[2400:489913] 0.501961, 0.380392, 0.898039
2015-05-23 15:58:16.121 CIFunHouse[2400:489913] 0.501961, 0.380392, 0.898039
2015-05-23 15:58:16.163 CIFunHouse[2400:489913] 0.501961, 0.380392, 0.898039
2015-05-23 15:58:16.205 CIFunHouse[2400:489913] 0.501961, 0.380392, 0.898039
2015-05-23 15:58:16.247 CIFunHouse[2400:489913] 0.690196, 0.309804, 0.819608
2015-05-23 15:58:16.288 CIFunHouse[2400:489913] 0.501961, 0.380392, 0.898039
2015-05-23 15:58:16.330 CIFunHouse[2400:489913] 0.501961, 0.380392, 0.898039
2015-05-23 15:58:16.372 CIFunHouse[2400:489913] 0.501961, 0.380392, 0.898039
2015-05-23 15:58:16.413 CIFunHouse[2400:489895] 0.690196, 0.309804, 0.819608
2015-05-23 15:58:16.455 CIFunHouse[2400:489895] 0.501961, 0.380392, 0.898039
2015-05-23 15:58:16.496 CIFunHouse[2400:489913] 0.690196, 0.309804, 0.819608
2015-05-23 15:58:16.543 CIFunHouse[2400:489913] 0.501961, 0.380392, 0.898039
2015-05-23 15:58:16.579 CIFunHouse[2400:489913] 0.752941, 0.858824, 0.890196
2015-05-23 15:58:16.623 CIFunHouse[2400:489913] 0.564706, 0.917647, 0.831373
2015-05-23 15:58:16.667 CIFunHouse[2400:489913] 0.752941, 0.858824, 0.890196
2015-05-23 15:58:16.705 CIFunHouse[2400:489913] 0.564706, 0.917647, 0.831373
2015-05-23 15:58:16.746 CIFunHouse[2400:489913] 0.564706, 0.917647, 0.831373
2015-05-23 15:58:16.788 CIFunHouse[2400:489913] 0.752941, 0.858824, 0.890196
2015-05-23 15:58:16.829 CIFunHouse[2400:489913] 0.690196, 0.309804, 0.819608
2015-05-23 15:58:16.873 CIFunHouse[2400:489913] 0.690196, 0.309804, 0.819608
2015-05-23 15:58:16.912 CIFunHouse[2400:489970] 0.752941, 0.858824, 0.890196
2015-05-23 15:58:16.955 CIFunHouse[2400:489913] 0.690196, 0.309804, 0.819608
2015-05-23 15:58:16.996 CIFunHouse[2400:489913] 0.752941, 0.858824, 0.890196
2015-05-23 15:58:17.038 CIFunHouse[2400:489913] 0.752941, 0.858824, 0.890196
2015-05-23 15:58:17.080 CIFunHouse[2400:489913] 0.752941, 0.858824, 0.890196
2015-05-23 15:58:17.122 CIFunHouse[2400:489913] 0.752941, 0.858824, 0.890196
2015-05-23 15:58:17.163 CIFunHouse[2400:489913] 0.690196, 0.309804, 0.819608
2015-05-23 15:58:17.205 CIFunHouse[2400:489913] 0.690196, 0.309804, 0.819608
2015-05-23 15:58:17.246 CIFunHouse[2400:489913] 0.690196, 0.309804, 0.819608
2015-05-23 15:58:17.288 CIFunHouse[2400:489970] 0.690196, 0.309804, 0.819608
2015-05-23 15:58:17.330 CIFunHouse[2400:489913] 0.752941, 0.858824, 0.890196
2015-05-23 15:58:17.371 CIFunHouse[2400:489913] 0.752941, 0.858824, 0.890196
2015-05-23 15:58:17.415 CIFunHouse[2400:489913] 0.690196, 0.309804, 0.819608
2015-05-23 15:58:17.456 CIFunHouse[2400:489913] 0.752941, 0.858824, 0.890196
2015-05-23 15:58:17.496 CIFunHouse[2400:489913] 0.690196, 0.309804, 0.819608
2015-05-23 15:58:17.539 CIFunHouse[2400:489913] 0.690196, 0.309804, 0.819608
2015-05-23 15:58:17.580 CIFunHouse[2400:489895] 0.501961, 0.380392, 0.898039
2015-05-23 15:58:17.622 CIFunHouse[2400:489895] 0.690196, 0.309804, 0.819608
2015-05-23 15:58:17.664 CIFunHouse[2400:489895] 0.690196, 0.309804, 0.819608
2015-05-23 15:58:17.705 CIFunHouse[2400:489895] 0.690196, 0.309804, 0.819608
2015-05-23 15:58:17.746 CIFunHouse[2400:489895] 0.752941, 0.858824, 0.890196
2015-05-23 15:58:17.788 CIFunHouse[2400:489895] 0.752941, 0.858824, 0.890196
2015-05-23 15:58:17.830 CIFunHouse[2400:489895] 0.752941, 0.858824, 0.890196
2015-05-23 15:58:17.873 CIFunHouse[2400:489895] 0.690196, 0.309804, 0.819608
2015-05-23 15:58:17.914 CIFunHouse[2400:489895] 0.752941, 0.858824, 0.890196
2015-05-23 15:58:17.956 CIFunHouse[2400:489895] 0.690196, 0.309804, 0.819608
2015-05-23 15:58:17.997 CIFunHouse[2400:489913] 0.501961, 0.941176, 0.831373
2015-05-23 15:58:18.038 CIFunHouse[2400:489913] 0.752941, 0.858824, 0.890196
2015-05-23 15:58:18.080 CIFunHouse[2400:489913] 0.752941, 0.858824, 0.890196
2015-05-23 15:58:18.122 CIFunHouse[2400:489913] 0.752941, 0.858824, 0.890196
2015-05-23 15:58:18.163 CIFunHouse[2400:489913] 0.690196, 0.309804, 0.819608
2015-05-23 15:58:18.206 CIFunHouse[2400:489913] 0.690196, 0.309804, 0.819608
2015-05-23 15:58:18.248 CIFunHouse[2400:489913] 0.752941, 0.858824, 0.890196
2015-05-23 15:58:18.289 CIFunHouse[2400:489913] 0.752941, 0.858824, 0.890196
2015-05-23 15:58:18.330 CIFunHouse[2400:489895] 0.690196, 0.309804, 0.819608
2015-05-23 15:58:18.372 CIFunHouse[2400:489895] 0.752941, 0.858824, 0.890196
2015-05-23 15:58:18.413 CIFunHouse[2400:489895] 0.690196, 0.309804, 0.819608
2015-05-23 15:58:18.459 CIFunHouse[2400:489895] 0.752941, 0.858824, 0.890196
2015-05-23 15:58:18.497 CIFunHouse[2400:489895] 0.752941, 0.858824, 0.890196
2015-05-23 15:58:18.538 CIFunHouse[2400:489895] 0.690196, 0.309804, 0.819608
2015-05-23 15:58:18.580 CIFunHouse[2400:489895] 0.690196, 0.309804, 0.819608
2015-05-23 15:58:18.622 CIFunHouse[2400:489895] 0.752941, 0.858824, 0.890196
2015-05-23 15:58:18.663 CIFunHouse[2400:489913] 0.690196, 0.309804, 0.819608
2015-05-23 15:58:18.706 CIFunHouse[2400:489913] 0.690196, 0.309804, 0.819608
2015-05-23 15:58:18.747 CIFunHouse[2400:489895] 0.690196, 0.309804, 0.819608
2015-05-23 15:58:18.789 CIFunHouse[2400:489895] 0.752941, 0.858824, 0.890196
2015-05-23 15:58:18.830 CIFunHouse[2400:489913] 0.690196, 0.309804, 0.819608
2015-05-23 15:58:18.868 CIFunHouse[2400:489913] 0.690196, 0.309804, 0.819608
2015-05-23 15:58:18.907 CIFunHouse[2400:489913] 0.752941, 0.858824, 0.890196
2015-05-23 15:58:18.949 CIFunHouse[2400:489913] 0.752941, 0.858824, 0.890196
2015-05-23 15:58:18.990 CIFunHouse[2400:489913] 0.690196, 0.309804, 0.819608
2015-05-23 15:58:19.044 CIFunHouse[2400:489913] 0.690196, 0.309804, 0.819608
2015-05-23 15:58:19.091 CIFunHouse[2400:489913] 0.690196, 0.309804, 0.819608
2015-05-23 15:58:19.134 CIFunHouse[2400:489913] 0.690196, 0.309804, 0.819608
2015-05-23 15:58:19.173 CIFunHouse[2400:489913] 0.752941, 0.858824, 0.890196
2015-05-23 15:58:19.213 CIFunHouse[2400:489913] 0.690196, 0.309804, 0.819608
2015-05-23 15:58:19.254 CIFunHouse[2400:489913] 0.752941, 0.858824, 0.890196
2015-05-23 15:58:19.298 CIFunHouse[2400:489913] 0.564706, 0.917647, 0.831373
2015-05-23 15:58:19.337 CIFunHouse[2400:489913] 0.752941, 0.858824, 0.890196
2015-05-23 15:58:19.377 CIFunHouse[2400:489913] 0.752941, 0.858824, 0.890196
2015-05-23 15:58:19.415 CIFunHouse[2400:489913] 0.564706, 0.917647, 0.831373
2015-05-23 15:58:19.455 CIFunHouse[2400:489913] 0.564706, 0.917647, 0.831373
2015-05-23 15:58:19.498 CIFunHouse[2400:489913] 0.752941, 0.858824, 0.890196
2015-05-23 15:58:19.540 CIFunHouse[2400:489913] 0.564706, 0.917647, 0.831373
2015-05-23 15:58:19.588 CIFunHouse[2400:489913] 0.501961, 0.380392, 0.898039
2015-05-23 15:58:19.630 CIFunHouse[2400:489913] 0.690196, 0.309804, 0.819608
2015-05-23 15:58:19.674 CIFunHouse[2400:489913] 0.501961, 0.380392, 0.898039
2015-05-23 15:58:19.719 CIFunHouse[2400:489913] 0.690196, 0.309804, 0.819608
2015-05-23 15:58:19.763 CIFunHouse[2400:489913] 0.690196, 0.309804, 0.819608
2015-05-23 15:58:19.806 CIFunHouse[2400:489913] 0.690196, 0.309804, 0.819608
2015-05-23 15:58:19.851 CIFunHouse[2400:489913] 0.752941, 0.858824, 0.890196
2015-05-23 15:58:19.902 CIFunHouse[2400:489913] 0.690196, 0.309804, 0.819608
2015-05-23 15:58:19.960 CIFunHouse[2400:489913] 0.690196, 0.309804, 0.819608
2015-05-23 15:58:20.016 CIFunHouse[2400:489913] 0.690196, 0.309804, 0.819608
2015-05-23 15:58:20.073 CIFunHouse[2400:489913] 0.690196, 0.309804, 0.819608
2015-05-23 15:58:20.139 CIFunHouse[2400:489913] 0.000000, 0.882353, 0.898039
2015-05-23 15:58:20.198 CIFunHouse[2400:489913] 0.000000, 0.882353, 0.898039
2015-05-23 15:58:20.253 CIFunHouse[2400:489913] 0.000000, 0.882353, 0.898039
2015-05-23 15:58:20.316 CIFunHouse[2400:489913] 0.313726, 0.894118, 0.831373
2015-05-23 15:58:20.389 CIFunHouse[2400:489913] 0.313726, 0.894118, 0.831373
2015-05-23 15:58:20.472 CIFunHouse[2400:489913] 0.313726, 0.894118, 0.831373
2015-05-23 15:58:20.554 CIFunHouse[2400:489913] 0.313726, 0.894118, 0.831373
2015-05-23 15:58:20.631 CIFunHouse[2400:489913] 0.690196, 0.309804, 0.819608
2015-05-23 15:58:20.714 CIFunHouse[2400:489913] 0.752941, 0.858824, 0.890196
2015-05-23 15:58:20.784 CIFunHouse[2400:489913] 0.752941, 0.858824, 0.890196
2015-05-23 15:58:20.839 CIFunHouse[2400:489913] 0.690196, 0.309804, 0.819608
2015-05-23 15:58:20.887 CIFunHouse[2400:489913] 0.690196, 0.309804, 0.819608
2015-05-23 15:58:20.935 CIFunHouse[2400:489913] 0.752941, 0.858824, 0.890196
2015-05-23 15:58:20.981 CIFunHouse[2400:489913] 0.752941, 0.858824, 0.890196

你只对第一个像素感兴趣(仅4个字节),为什么要分配32个字节? - Bjorn Roche
我只是想问一下,为什么你使用了32而不是16。 - Bjorn Roche

0

我自己也曾经遇到过这个问题,尽管是在iOS上。我想要从实时视频中获取直方图数据以进行自己的可视化,但遇到了与Justin Mrkva相同的问题。

即使使用CIHistogramDisplayFilter,输出看起来对我来说也不太对(太平淡了?),而且CIAreaHistogram单独消耗了25-30%的CPU。这还没有从GPU中绘制到EAGLContext,更没有将数据带回来...

所以我完全放弃了Core Image并转向vImage,它完美地解决了我的问题。它仍然需要大量的CPU,但对我来说比CIAreaHistogram少得多,并且输出与我在Photoshop中看到的一致。如果您试图完全停留在GPU上,这并不理想,但根据您的应用程序,它可能是更好的选择(它肯定更精确)。

它并没有直接回答你的问题,但这里是使用 vImage 获取 CGImage 直方图的方法。我正在做基本相同的事情,只是换成了 CVPixelBuffer 并锁定了基地址。通道顺序是不同的,但不应该有影响:

#import <Accelerate/Accelerate.h>

CFDataRef imageData = CGDataProviderCopyData(CGImageGetDataProvider(image));

vImage_Buffer vImageBuffer;
vImageBuffer.data = (UInt8 *)CFDataGetBytePtr(imageData);
vImageBuffer.width = CGImageGetWidth(image);
vImageBuffer.height = CGImageGetHeight(image);
vImageBuffer.rowBytes = CGImageGetBytesPerRow(image);

vImagePixelCount red[256];
vImagePixelCount green[256];
vImagePixelCount blue[256];
vImagePixelCount alpha[256];
vImagePixelCount *histogram[4] = { red, green, blue, alpha };

vImage_Error error = vImageHistogramCalculation_ARGB8888(&vImageBuffer, histogram, 0);

if (error != kvImageNoError)
    NSLog(@"vImage error: %ld", error);

CFRelease(imageData);

// histogram now contains unsigned long counts for each channel

我仍然想知道如何在iOS上正确使用CIAreaHistogram


亲爱的jstn,非常感谢你的建议。我最终采取了完全不同的方法。在手动编写了一个CPU密集型的直方图测量程序之后,它能够按照我想要的方式工作,结果发现直方图方法并不是整个大局下的正确解决方案...感谢你告诉我vImage,现在我至少知道了将来如何获得一个可行的直方图 - 但出于好奇,我仍然会尝试弄清楚如何使用CIAreaHistogram来完成它! - Oral Okan

0

以下是您最初想要做的方法;事实证明,在上下文中更改格式是导致您获得所有不同结果的原因。

顺便说一句,这个示例代码使用了一个EAGLContext,据说更快,尽管在我迄今为止的经验中并非如此。不过,这里是代码:

    CIFilter* histogram = [CIFilter filterWithName:@"CIAreaHistogram"];
[histogram setValue:inputImage forKey:@"inputImage"];
[histogram setValue:[CIVector vectorWithX:0.0 Y:0.0 Z:self.inputImage.extent.size.width W:self.inputImage.extent.size.height] forKey:@"inputExtent"];
[histogram setValue:@256 forKey:@"inputCount"];
[histogram setValue:@1.0 forKey:@"inputScale"];
/*id histogramData = [histogram valueForKey:@"outputData"];
if (histogramData)
    NSLog(@"outputData: %@", histogramData);*/

@autoreleasepool {
    CIImage* histogramImage = [histogram valueForKey:@"outputImage"];
    int rowBytes = 256 * 4; // ARGB has 4 components
    uint8_t byteBuffer[rowBytes]; // Buffer to render into

    EAGLContext *myEAGLContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
    NSDictionary *options = @{ kCIContextWorkingColorSpace : [NSNull null] };
    CIContext *ctx = [CIContext contextWithEAGLContext:myEAGLContext options:options];
    //CIContext* ctx = [[CIContext alloc] init];
    [ctx render:histogramImage toBitmap:byteBuffer
       rowBytes:rowBytes
         bounds:[histogramImage extent]
         format:kCIFormatRGBAf
     colorSpace:nil];

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

应该使用kCIFormatRGBA8而不是kCIFormatRGBAf,因为你要将数据复制到字节而不是浮点数中。 - Bjorn Roche
你会如何编写这个代码?我想尝试一下你的想法。我相信将其一个替换成另一个需要对其他属性进行更改。我想尝试一下你的想法。 - James Bush
如果你坚持使用kCIFormatRGBAf,你需要将uint8_t更改为float和rowBytes:rowBytes更改为rowBytes:rowBytes * 4。(你正在请求大小为float的数据,但只给了它1字节。) - Bjorn Roche

0

我花了一些时间在这上面,但是从来没有让kCIFormatARGB8工作。另一个帖子说kCIFormatARGBf在iOS上不起作用,所以我尝试使用kCIFormatRGBAh

kCIFormatRGBAh很奇怪:它是将RGBA数据打包为16位浮点数(“半浮点数”)。C语言没有本地的半浮点类型,您必须依赖于编译器特定的数据类型。幸运的是,gcc和clang似乎都支持类型__fp16

// img is input
histogramFilter = [CIFilter filterWithName:@"CIAreaHistogram" keysAndValues:@"inputScale", @1, @"inputCount", @256, nil];
CIVector *extent = [[CIVector alloc] initWithCGRect:img.extent];
[histogramFilter setValue:extent forKey:@"inputExtent"];
[histogramFilter setValue:img forKey:kCIInputImageKey];
CIImage *histImg = histogramFilter.outputImage;

int rowBytes = 256 * 4; // ARGB has 4 components.
__fp16 byteBuffer[rowBytes]; // Buffer to render into
rowBytes *= 2; //__fp16 is 2 bytes

EAGLContext *myEAGLContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
NSDictionary *options = @{ kCIContextWorkingColorSpace : [NSNull null] };
CIContext *ctx = [CIContext contextWithEAGLContext:myEAGLContext options:options];
[ctx render:histImg toBitmap:byteBuffer
   rowBytes:rowBytes
     bounds:[histImg extent]
     format:kCIFormatRGBAh
 colorSpace:nil];

for (int i = 0; i < 256; i++)
{
    const __fp16* pixel = &byteBuffer[i*4];

    NSLog(@"%d: %f, %f, %f, %f\n", i, (float)pixel[0], (float)pixel[1], (float)pixel[2], (float)pixel[3]);
}

我认为这在模拟器上不会起作用,因为模拟器不支持kCIFormatRGBAh。


我更新了这个答案,展示了计算输入范围的正确方法。其他答案中给出的方法是错误的,可能会导致错误的结果。 - Bjorn Roche

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接