Как получить значимый вывод CIAreaHistogram?
Я хочу рассчитать гистограммуCGImage
, Я используюCIAreaHistogram
встроенныйCoreImage
фильтр.
Джастин Мрква сделалчто-то похожее, Он говорит:
Я получаю CIImage для самой гистограммы, которую затем запускаю через собственное ядро (см. Конец поста), чтобы установить альфа-значения равными 1 (поскольку в противном случае альфа-значение из вычислений гистограммы предварительно умножается), а затем преобразую его в NSBitmapImageRep.
Мой вопрос:Можно ли получить данные гистограммы без необходимости создания собственного ядра? Если так, то как?
Следующий код просто пытается отобразить гистограмму без изменения значений альфа:
- (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
установить значения альфа на 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, из того, что я понял из справочника по фильтру базовых изображений, альфа-компонент является последним значением в векторе (таким образом,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, вам понадобится другой фильтр, чтобы читать данные и распечатывать их вместе с ними.
Тем не менее, глядя наВопрос Джастина Мрквы заставляет меня думать, что получение целочисленных значений должно быть возможным ... Пожалуйста, дайте мне знать, если в моем мышлении есть ошибка.
Еще раз спасибо!
РЕДАКТИРОВАТЬ 2: Во-первых, спасибо и Дэвид и JSTN за их комментарии. Извините, что я так долго возвращался к этому. Я круглосуточно работал над проектом (на самом деле, именно этот проект привел меня к этой проблеме, но в итоге я использовал совершенно другой подход, который больше не использует CIAreaHistogram). Теперь, когда у меня наконец-то появилось время, я хотел вернуться к этому. Хотя я ненеобходимость само по себе, я все еще хочу понять, как эта штука действительно работает!
Следуя предложениям Дэвида Хейворда, я внес следующие изменения.
- (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
Игра с вариациями форматов и анализом информации дает совершенно разные и абсурдные результаты.
Я совершенно уверен, что проблема заключается в неправильном понимании того, как точечные данные представлены.
Есть еще предложения?