2013-04-24 3 views
1

Я рисую несколько изображений в оттенках серого в iOS. Значения полутонового изображения имеют минимальный и максимальный значения, например, для 8-битных значений в диапазоне [41, 244].Как изменить минимальное или максимальное значение CIFilter в изображении Core?

Я хочу изменить минимальное значение или максимальное значение. Я хочу знать, как установить фильтр в this list, чтобы изменить минимальное значение и как установить фильтр в this list, чтобы изменить максимальное значение?

Может быть продолжением рисунка будет хорошо видеть:

[1. Чтение исходных данных серого] -> [2. Создать CGImageRef] -> [3. Загрузить ref в GPU]

и к настоящему моменту в iOS 6 можно применять фильтр в графическом процессоре в режиме реального времени. Манипуляция с 1 или 2 очень медленная для меня, потому что через одну секунду я должен сделать 100 изображений. Поэтому мне нужно использовать CIFilter в GPU. Я знаю, как фильтровать изображение. Но какой фильтр может выполнять моя работа?

Некоторые примеры кода хороши для меня.

ответ

4

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 корректировки с нулевыми значениями для входов вне диапазона окна, вы хотите добиться чего-то вроде этого:

enter image description here

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 (это правильный алгоритм окна/уровня, не пытаясь сбить максимальные уровни до нуля).

enter image description here

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

оригинальный

enter image description here

filter1 CIToneCurve

enter image description here

filter2 CIColorControls

enter image description here

фильтр3 CIColorPosterize

enter image description here

filter4 CIColorInvert

enter image description here

filter5 CIDarkenBlendMode

enter image description here

Если вы посмотрите на Брэда Ларсона, вы должны найти, что GPUImageLuminanceThresholdFilter лучше заменит фильтры 2-> 5.

+0

На самом деле я хочу применить [линейную формулу] (http://blogs.mathworks.com/steve/2006/02/17/all-about-pixel-colors-window-level) для каждого значения серого сырья данные, а когда значение вне окна, я хочу установить его в ноль. Таким образом, входы представляют собой значение окна и уровня, а вывод - это вычисленные значения. Вы когда-нибудь делали что-то подобное? –

+0

@MilanoFili, см. Мой обновленный ответ – foundry

+0

Прекрасный пример и ответ. Спасибо вам. –

0

Для каждого эффекта в CIFilter мы имеем минимальное и максимальное значения. Либо мы можем исправить это значение в коде еще, если вы хотите исправить рисование рисунка, мы сделали это, используя UISlider для ползунка с заданными минимальными и максимальными значениями в качестве диапазона этого фильтра, тогда мы можем дать действие этому слайдеру, чтобы при перемещении пользователя эффект также автоматически менялся ,