Wie erhalte ich eine aussagekräftige CIAreaHistogram-Ausgabe?
Ich möchte das Histogramm eines @ berechnCGImage
. Ich benutze dasCIAreaHistogram
Built-inCoreImage
filter.
Justin Mrkva hat @ getetwas in ähnlicher Richtung. Er sagt
Ich erhalte das CIImage für das Histogramm selbst, das ich dann durch einen benutzerdefinierten Kernel (siehe Ende des Beitrags) laufe, um die Alpha-Werte auf 1 zu setzen (da sonst der Alpha-Wert aus den Histogramm-Berechnungen vormultipliziert wird) und konvertiere es dann in ein NSBitmapImageRep .
Meine Frage ist: Ist es möglich, die Histogrammdaten abzurufen, ohne einen benutzerdefinierten Kernel erstellen zu müssen? Wenn das so ist, wie
Der folgende Code versucht einfach, das Histogramm zu rendern, ohne die Alpha-Werte zu ändern:
- (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]);
}
}
Geben der Ausgabe (bei Ausführung auf einem Farbfoto):
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
Ich habe versucht mitCIColorMatrix
, um die Alpha-Werte vor dem Rendern auf 1.0 zu setzen:
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"];
Auch wenn das Ausgabeformat ARGB ist, ist die Alpha-Komponente nach dem, was ich aus der Core Image Filter Reference verstehe, der letzte Wert im Vektor (alsoW:1.0
).
Aber dies ergab die folgende Ausgabe:
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
Alle Hilfe und Ratschläge werden sehr geschätzt!
EDIT: Ich weißdiese Frag scheint ähnlich. Die akzeptierte Antwort lautet jedoch:
Das kurze daran ist: Sie müssen die Werte als Float und nicht als Ints lesen, was bedeutet, dass Sie einen CGBitmapContext anschließen müssen, mit dem Sie blitten möchten. Oder wenn Sie alles im CI-Land behalten, benötigen Sie einen weiteren Filter, um die Daten zu lesen und etwas damit auszudrucken.
Jedoch auf der Suche nach Justin Mrkva die Frage lässt mich denken, dass es möglich sein sollte, ganzzahlige Werte zu erhalten ... Bitte lassen Sie mich wissen, wenn ein Fehler in meinem Denken vorliegt.
Danke noch einmal
EDIT 2: Zunächst einmal vielen Dank an David und jstn für ihre Kommentare. Es tut mir leid, dass ich so lange gebraucht habe, um darauf zurückzukommen. Ich habe rund um die Uhr an einem Projekt gearbeitet (tatsächlich hat mich dieses Projekt zu diesem Problem geführt, aber ich habe einen völlig anderen Ansatz gewählt, bei dem CIAreaHistogram nicht mehr verwendet wird). Jetzt, da ich endlich Zeit habe, wollte ich darauf zurückkommen. Auch wenn ich nichtbrauche it per se, ich möchte immer noch verstehen, wie das Ding wirklich funktioniert!
Folgend den Vorschlägen von David Hayward habe ich die folgenden Änderungen vorgenommen.
- (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]);
}
}
Dies ergibt die folgende Ausgabe:
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
Das Spielen mit verschiedenen Formaten und das Analysieren von Informationen führt zu völlig unterschiedlichen und absurden Ergebnissen.
Ich bin mir ziemlich sicher, dass das Problem darin liegt, nicht genau zu verstehen, wie die Bitmap-Daten dargestellt werden.
Irgendwelche weiteren Vorschläge?