Как изменить минимальное или максимальное значение CIFilter в основном образе?

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

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

Может быть, будет приятно увидеть следующий рисунок:

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

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

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


person mf mf    schedule 24.04.2013    source источник


Ответы (2)


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 может быть контекстом CPU или GPU (EAGL). Точки описывают тоновую кривую. X — входное значение, Y — выходное значение. В этом примере мы уменьшаем наклон, тем самым уменьшая контраст. С тем же успехом вы могли бы сохранить наклон таким же, но отрезать крайности, уменьшив ваши максимумы и минимумы.

Вот некоторые измерения при обработке 100 изображений на iPad mini (в среднем четыре показания на настройку). Вы увидите, что графический процессор не является волшебной палочкой, и около 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    

обновить

Для окна и уровня корректировки с нулевыми значениями для входных данных за пределами диапазона окна, вы хотите добиться чего-то вроде этого:

введите здесь описание изображения

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, поэтому в любом случае вам придется немного увеличить, чтобы d.x = c.x*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"];

Инвертировать результат

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

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

введите здесь описание изображения

фильтр1 CIToneCurve

введите здесь описание изображения

фильтр2 CIColorControls

введите здесь описание изображения

фильтр3 CIColorPosterize

введите здесь описание изображения

фильтр4 CIColorInvert

введите здесь описание изображения

фильтр5 CIDarkenBlendMode

введите здесь описание изображения

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

person foundry    schedule 25.04.2013
comment
На самом деле я хочу применить линейную формулу для каждого значения серых необработанных данных, и когда значение выходит за пределы окна, я хочу установить его равным нулю. Таким образом, входными данными являются значение окна и уровня, а выходными данными являются вычисленные значения. Вы когда-нибудь делали что-то подобное? - person mf mf; 15.06.2013
comment
Прекрасный пример и ответ. Спасибо вам. - person mf mf; 16.06.2013

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

person ganesh manoj    schedule 25.04.2013