CIToneCurve должен быть хорошим для такого рода вещей.
- (UIImage*) applyToneCurveToImage:(UIImage*)image
{
CIContext* context = self.context;
CIImage* ciImage = [[CIImage alloc] initWithImage:image];
CIFilter* filter =
[CIFilter filterWithName:@"CIToneCurve"
keysAndValues:
kCIInputImageKey, ciImage,
@"inputPoint0",[CIVector vectorWithX:0.00 Y:0.3]
,@"inputPoint1",[CIVector vectorWithX:0.25 Y:0.4]
,@"inputPoint2",[CIVector vectorWithX:0.50 Y:0.5]
,@"inputPoint3",[CIVector vectorWithX:0.75 Y:0.6]
,@"inputPoint4",[CIVector vectorWithX:1.00 Y:0.7]
,nil];
CIImage* result = [filter valueForKey:kCIOutputImageKey];
CGImageRef cgImage = [context createCGImage:result
fromRect:[result extent]];
UIImage* filteredImage = [UIImage imageWithCGImage:cgImage];
CGImageRelease(cgImage);
return filteredImage;
}
self.context
может быть процессор или графический процессор (EAGL) контекст. Точки описывают кривую тона. X - входное значение, Y - выходное значение. В этом примере мы уменьшаем наклон, таким образом уменьшая контраст. Вы могли бы так же сохранить уклон одинаковым, но срезать крайности, уменьшая ваши максимумы и минимумы.
Вот несколько измерений, обрабатывающих 100 изображений на iPad mini (в среднем четыре показания за настройку). Вы увидите, что GPU не является волшебной пулей, и около 60-65% времени поглощается только движущимися данными изображения. Эти примеры начинаются и заканчиваются UIImage. Я получаю очень похожие результаты с CGImage.
57x57px png 640x800px jpeg
UIImage->CIImage->UIImage (no filtering)
CPU 0.57s 2.83s
GPU 0.36s 2.83s
UIImage->CIImage->CIFilter->UIImage
CPU 0.75s 4.38s
GPU 0.58s 4.32s
обновление
Для Window and Level корректировки с нулевыми значениями для входов вне диапазона окна, вы хотите добиться чего-то вроде этого:
CGFloat w; //window
CGFloat l; //level
@"inputPoint0",[CIVector vectorWithX:0.0 Y:0.0]
,@"inputPoint1",[CIVector vectorWithX:l-w/2 Y:0.0]
,@"inputPoint2",[CIVector vectorWithX:l+w/2 Y:1.0]
,@"inputPoint3",[CIVector vectorWithX:l+w/2 Y:0.0]
,@"inputPoint4",[CIVector vectorWithX:1.0 Y:0.0]
На практике Это не будет работать. Точки описывают сплайн-кривую, и она не ведет себя хорошо с резкими изменениями направления, такими как b-c-d. (Также точки c и d (2 и 3) не могут использовать одно и то же значение x, поэтому в любом случае вам придется слегка увеличивать, чтобы dx = cx * 1.01)
Вы можете получить свой результат, если используете мульти -ступенчатый фильтр. Первый фильтр использует CIToneCurve
(это правильный алгоритм окна/уровня, не пытаясь сбить максимальные уровни до нуля).
CIFilter* filter =
[CIFilter filterWithName:@"CIToneCurve"
keysAndValues:
kCIInputImageKey, ciImage,
@"inputPoint0",[CIVector vectorWithX:0.0 Y:0.0]
,@"inputPoint1",[CIVector vectorWithX:l-w/2 Y:0.0]
,@"inputPoint2",[CIVector vectorWithX:l Y:0.5]
,@"inputPoint3",[CIVector vectorWithX:l+w/2 Y:1.0]
,@"inputPoint4",[CIVector vectorWithX:1.0 Y:1.0]
Мы делаем копию фильтра, как нам нужно снова на последнем шаге:
filter2 = [filter copy];
Применить CIColorControls фильтр для максимального контраста и яркости на результат
filter = [CIFilter filterWithName:@"CIColorControls"
keysAndValues:kCIInputImageKey,
[filter valueForKey:kCIOutputImageKey], nil];
[filter setValue:[NSNumber numberWithFloat:-1]
forKey:@"inputBrightness"];
[filter setValue:[NSNumber numberWithFloat:4]
forKey:@"inputContrast"];
Теперь постер в 1-битную палитру
filter = [CIFilter filterWithName:@"CIColorPosterize"
keysAndValues:kCIInputImageKey,
[filter valueForKey:kCIOutputImageKey], nil];
[filter setValue:@2 forKey:@"inputLevels"];
Invert результат
filter = [CIFilter filterWithName:@"CIColorInvert"
keysAndValues:kCIInputImageKey,
[filter valueForKey:kCIOutputImageKey], nil];
Теперь мы используем этот результат в виде маски с окном/выровненных изображениями так, чтобы все максимальные уровни белых получить снижаются до черного.
filter = [CIFilter filterWithName:@"CIDarkenBlendMode"
keysAndValues:kCIInputImageKey,
[ filter valueForKey:kCIOutputImageKey], nil];
[filter setValue:[filter2 valueForKey:kCIOutputImageKey]
forKey:@"inputBackgroundImage"];
оригинальный
filter1 CIToneCurve
filter2 CIColorControls
фильтр3 CIColorPosterize
filter4 CIColorInvert
filter5 CIDarkenBlendMode
Если вы посмотрите на Брэда Ларсона, вы должны найти, что GPUImageLuminanceThresholdFilter
лучше заменит фильтры 2-> 5.
На самом деле я хочу применить [линейную формулу] (http://blogs.mathworks.com/steve/2006/02/17/all-about-pixel-colors-window-level) для каждого значения серого сырья данные, а когда значение вне окна, я хочу установить его в ноль. Таким образом, входы представляют собой значение окна и уровня, а вывод - это вычисленные значения. Вы когда-нибудь делали что-то подобное? –
@MilanoFili, см. Мой обновленный ответ – foundry
Прекрасный пример и ответ. Спасибо вам. –