如何获得有意义的CIAreaHistogram输出? [英] How to get meaningful CIAreaHistogram output?

查看:335
本文介绍了如何获得有意义的CIAreaHistogram输出?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想计算 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有4个组件
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\\\
,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

所有帮助和建议都将非常感谢!






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


缺点是:您需要将值读取为浮点数,而不是int,必须连接一个CGBitmapContext到blit。或者,如果你把所有的东西都放在CI土地上,你需要另一个过滤器来读取数据并打印出来。


,看看 Justin Mrkva的问题让我认为获取整数值应该是可能的...请让我知道我的想法是否有错误。



再次感谢!






编辑2:首先,感谢大卫和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¥b $ b 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有4个组件

// CHANGE 1:因为我将使用浮点值渲染,我使用CGFloat
设置
//缓冲区CGFloat byteBuffer [arraySize] ; //缓冲区渲染到

// CHANGE 2:我不应该调用[[CIContext alloc] init]
//这是一个更合适的方式获取上下文
CIContext * ctx = [[NSGraphicsContext currentContext] CIContext];

// CHANGE 3:我使用colorSpace:NULL来使用ctx的输出cspace
// CHANGE 4:格式现在是kCIFormatRGBAf
[ctx render:histImg
toBitmap:byteBuffer
rowBytes:arraySize
bounds:[histImg extent]
format:kCIFormatRGBAf
colorSpace:NULL]; //使用contetxt的输出cspace

// CHANGE 5:我打印浮点值
for(int i = 0; i <[buckets intValue]; i ++){
const CGFloat * pixel =& byteBuffer [i * 4];
printf(%d:%0.2f,%0.2f,%0.2f,%0.2f \\\
,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

使用各种格式以及如何解析信息会产生截然不同的荒谬结果。

$ b $



任何进一步的建议?

解决方案

三个建议:




  • 使用inputScale增加直方图计数。如果inputScale为1,则如果整个区域具有该bin值,那么结果的直方图bin值将为1.0(如果呈现给ARGB8则为255)。

  • 通过CI的工作颜色空间进行渲染:toBitmap: 。在小牛上,工作空间是kCGColorSpaceGenericRGBLinear。在Yosemite上,它是线性的sRGB。

  • 在OS X上,您可以使用kCIFormatRGBAf获取浮点数据

  • 浮动数据


I want to calculate the histogram of a CGImage. I am using the CIAreaHistogram built-in CoreImage filter.

Justin Mrkva has done something along similar lines. He says:

I get the CIImage for the histogram itself, which I then run through a custom kernel (see end of post) to set alpha values to 1 (since otherwise the alpha value from the histogram calculations is premultiplied) and then convert it to an NSBitmapImageRep.

My question is: is it possible to get the histogram data without having to create a custom kernel? If so, how?

The following code simply tries to render the histogram without chaning the alpha values:

- (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]);
    }

}   

Giving the output (when run on a color photo):

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

I tried using CIColorMatrix to set the alpha values to 1.0 before rendering:

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"];

Even though the output format is ARGB, from what I understand from the Core Image Filter Reference, the alpha component is the last value in the vector (thus W:1.0).

But this yielded the following output:

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

All help and advice will be much appreciated!


EDIT: I know this question seems similar. However, the accepted answer stipulates:

The short of it is: you need to read the values as floats, not ints, which means you'll have to hook up a CGBitmapContext to blit to. Or if you keep everything in CI land, you'll need another filter to read the data and print something out with it.

However, looking at Justin Mrkva's question makes me think that getting integer values should be possible... Please let me know if there is an error in my thinking.

Thanks again!


EDIT 2: Fist of all, thank you to both David and jstn for their comments. Sorry it took so long for me to come back to this. I was working around the clock on a project (in fact it was that project that led me to this problem, but I ended up using an altogether different approach that no longer utilizes CIAreaHistogram). Now that I finally have some time on my hands, I wanted to get back to this. Even though I don't need it per se, I still want to understand how this thing really works!

Following David Hayward's suggestions, I made the following modifications.

- (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]);
    }
}   

This gives the following output:

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

Playing around with variations of formats and how the information is parsed yields wildly different and absurd outputs.

I'm quite sure the trouble lies in not properly understanding precisely how the bitmap data is represented.

Any further suggestions?

解决方案

Three suggestions:

  • use inputScale to gain the histogram counts up. If inputScale is 1, then a resulting histogram bin value will be 1.0 (255 if rendered to ARGB8) if the entire area has that bin value)
  • pass CI's working colorspace to render:toBitmap:. On Mavericks the working space is kCGColorSpaceGenericRGBLinear. On Yosemite it is linear sRGB.
  • on OS X you can use kCIFormatRGBAf to get float data
  • on iOS you can use kCIFormatRGBAh to get half-float data

这篇关于如何获得有意义的CIAreaHistogram输出?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆