Como obter uma saída CIAreaHistogram significativa?
Eu quero calcular o histograma de umCGImage
. Estou usando oCIAreaHistogram
construídas emCoreImage
filtro.
Justin Mrkva fezalgo semelhante. Ele diz:
Eu recebo o CIImage para o próprio histograma, que, em seguida, corro através de um kernel personalizado (consulte o final da postagem) para definir valores alfa como 1 (caso contrário, o valor alfa dos cálculos do histograma é pré-multiplicado) e depois o converto em um NSBitmapImageRep.
Minha pergunta é:é possível obter os dados do histograma sem ter que criar um kernel personalizado? Se sim, como?
O código a seguir simplesmente tenta renderizar o histograma sem procurar os valores alfa:
- (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]);
}
}
Fornecendo a saída (quando executada em uma foto colorida):
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
Eu tentei usarCIColorMatrix
para definir os valores alfa como 1.0 antes da renderização:
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"];
Mesmo que o formato de saída seja ARGB, pelo que entendi na Referência do filtro de imagem principal, o componente alfa é o último valor do vetor (assimW:1.0
)
Mas isso produziu a seguinte saída:
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
Toda a ajuda e conselhos serão muito apreciados!
EDIT: eu seiessa questão parece semelhante. No entanto, a resposta aceita estipula:
O resumo é: você precisa ler os valores como flutuadores, não como ints, o que significa que você precisará conectar um CGBitmapContext ao qual desejar. Ou, se você mantiver tudo na área de IC, precisará de outro filtro para ler os dados e imprimir algo com eles.
No entanto, olhando paraPergunta de Justin Mrkva me faz pensar que a obtenção de valores inteiros deve ser possível ... Entre em contato se houver algum erro no meu pensamento.
Obrigado novamente!
EDIT 2: Primeiro de tudo, obrigado a David e jstn por seus comentários. Desculpe, demorou tanto tempo para eu voltar a isso. Eu estava trabalhando dia e noite em um projeto (na verdade, foi o projeto que me levou a esse problema, mas acabei usando uma abordagem totalmente diferente que não utiliza mais o CIAreaHistogram). Agora que finalmente tenho algum tempo em minhas mãos, queria voltar a isso. Mesmo que eu nãonecessidade por si só, ainda quero entender como isso realmente funciona!
Seguindo as sugestões de David Hayward, fiz as seguintes modificações.
- (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]);
}
}
Isso fornece a seguinte saída:
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
Brincar com variações de formatos e como a informação é analisada produz resultados totalmente diferentes e absurdos.
Tenho certeza de que o problema está em não entender corretamente exatamente como os dados de bitmap são representados.
Mais alguma sugestão?