Как реализовать быстрые фильтры изображений на платформе iOS - PullRequest
10 голосов
/ 19 августа 2011

Я работаю над приложением iOS, где пользователь может применить определенный набор фотофильтров. Каждый фильтр - это набор действий Photoshop с определенными параметрами. Это действия:

  • Регулировка уровней
  • Яркость / Контрастность
  • Оттенок / Насыщенность
  • Одиночное и многократное наложение

Я повторил все эти действия в своем коде, используя арифметические выражения, проходящие по всем пикселям изображения. Но когда я запускаю свое приложение на iPhone 4, каждый фильтр занимает примерно 3-4 секунды, что довольно много времени для ожидания пользователя. Размер изображения составляет 640 x 640 пикселей, что в 2 раза больше размера моего представления, поскольку оно отображается на дисплее Retina. Я обнаружил, что моя основная проблема - это изменения уровней, которые вызывают функцию pow () C каждый раз, когда мне нужно настроить гамму. Я использую числа с плавающей запятой, а не удваивается, конечно, потому что ARMv6 и ARMv7 медленны с двойными. Пытался включить и отключить Thumb и получил тот же результат.

Пример простейшего фильтра в моем приложении, который работает довольно быстро (2 секунды). Другие фильтры содержат больше выражений и вызовов pow (), что делает их медленными.

https://gist.github.com/1156760

Я видел несколько решений, использующих матричные преобразования Accelerate Framework vDSP для быстрой модификации изображений. Я также видел решения OpenGL ES. Я не уверен, что они способны на мои потребности. Но, возможно, это просто вопрос перевода моего набора изменений в какую-то хорошую матрицу свертки?

Любой совет будет полезен.

Спасибо,
Андрей.

Ответы [ 6 ]

13 голосов
/ 19 августа 2011

Для фильтра в вашем примере кода вы можете использовать таблицу поиска, чтобы сделать ее намного быстрее. Я предполагаю, что ваше входное изображение имеет 8 бит на цвет, и вы конвертируете его в плавающее перед передачей этой функции. Для каждого цвета это дает только 256 возможных значений и, следовательно, только 256 возможных выходных значений. Вы можете предварительно вычислить их и сохранить их в массиве. Это позволит избежать расчета pow() и проверки границ, поскольку вы можете включить их в предварительное вычисление.

Это будет выглядеть примерно так:

unsigned char table[256];
for(int i=0; i<256; i++) {
    float tmp = pow((float)i/255.0f, 1.3f) * 255.0; 
    table[i] = tmp > 255 ? 255 : (unsigned char)tmp;
}

for(int i=0; i<length; ++i)
    m_OriginalPixelBuf[i] = table[m_OriginalPixelBuf[i]];

В этом случае вам нужно всего лишь выполнить pow() 256 раз вместо 3 * 640 * 640 раз. Вы также избежите разветвления, вызванного проверкой границ в вашем основном цикле изображения, что может быть дорогостоящим. Вам также не придется конвертировать в плавающие.

Даже более быстрый способ может состоять в том, чтобы предварительно вычислить таблицу вне программы и просто вставить 256 коэффициентов в код.

Ни одна из перечисленных вами операций не должна требовать свертки или даже умножения матрицы. Все они являются пиксельными операциями, это означает, что каждый выходной пиксель зависит только от одного соответствующего входного пикселя. Вам необходимо учитывать свертку для таких операций, как размытие или резкость, когда несколько входных пикселей влияют на один выходной пиксель.

10 голосов
/ 19 августа 2011

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

Как я уже упоминал в других ответах , я измерил улучшение производительности в 14–28 раз при выполнении операции обработки изображений с использованием OpenGL ES вместо ЦП. Вы можете использовать инфраструктуру Accelerate для более быстрой манипуляции с изображениями на процессоре (я думаю, что Apple заявляет, что здесь возможно увеличение в ~ 4-5 раз), но это будет не так быстро, как OpenGL ES. Однако это может быть проще в реализации, поэтому я иногда использовал для этого Accelerate поверх OpenGL ES.

iOS 5.0 также переносит Core Image с рабочего стола, что дает вам хорошую оболочку для такого рода настроек изображения на GPU. Тем не менее, существуют некоторые ограничения для реализации iOS Core Image, которых нет при работе с шейдерами OpenGL ES 2.0 напрямую.

Я представляю пример фильтра изображений шейдера OpenGL ES 2.0 в моей статье здесь . Самым сложным в такой обработке является настройка лесов OpenGL ES. Используя мой пример приложения, вы сможете извлечь этот установочный код и применить к нему свои собственные фильтры. Чтобы упростить это, я создал инфраструктуру с открытым исходным кодом под названием GPUImage который обрабатывает все взаимодействия с OpenGL ES для вас. Он имеет почти каждый фильтр, который вы перечислили выше, и большинство из них работает менее чем за 2,5 мс для кадра видео 640x480 на iPhone 4, поэтому они работают намного быстрее, чем все, что обрабатывается в ЦП.

3 голосов
/ 19 августа 2011

Я на самом деле хотел сделать все это сам, но нашел Фильтры изображений Сильверберга .Вы можете применять различные фильтры изображений типа Instagram к вашим изображениям.Это намного лучше, чем другие фильтры изображений - GLImageProcessing или Cimg.

Также проверьте Instagram Image Filters на iPhone .

Надеюсь, это поможет ...

3 голосов
/ 19 августа 2011

Как я уже сказал в комментарии, вы должны также опубликовать этот вопрос на официальных форумах разработчиков Apple.

Кроме этого, одна очень быстрая проверка: вы звоните pow( ) или powf( )?Даже если ваши данные равны float, вызов pow( ) даст вам математическую библиотеку с двойной точностью, которая значительно медленнее, чем вариант с одинарной точностью powf( ) (и вам придется платить за дополнительные преобразования междуfloat и double также).

И вторая проверка: вы профилировали свои фильтры в инструментах?Вы на самом деле знаете , где тратится время выполнения, или вы догадываетесь?

2 голосов
/ 17 июля 2013

Начиная с iOS 5 и выше, вы можете использовать фильтры Core Image для настройки хорошего диапазона параметров изображения.

Например, чтобы настроить контраст, этот код работает как шарм:

    - (void)setImageContrast:(float)contrast forImageView:(UIImageView *)imageView {

    if (contrast > MIN_CONTRAST && contrast < MAX_CONTRAST) {
        CIImage *inputImage = [[CIImage alloc] initWithImage:imageView.image];
        CIFilter *exposureAdjustmentFilter = [CIFilter filterWithName:@"CIColorControls"];
        [exposureAdjustmentFilter setDefaults];
        [exposureAdjustmentFilter setValue:inputImage forKey:@"inputImage"];
        [exposureAdjustmentFilter setValue:[NSNumber numberWithFloat:contrast] forKey:@"inputContrast"]; //default = 1.00
//        [exposureAdjustmentFilter setValue:[NSNumber numberWithFloat:1.0f] forKey:@"inputSaturation"]; //default = 1.00
//        [exposureAdjustmentFilter setValue:[NSNumber numberWithFloat:0.0f] forKey:@"inputBrightness"];
        CIImage *outputImage = [exposureAdjustmentFilter valueForKey:@"outputImage"];
        CIContext *context = [CIContext contextWithOptions:nil];
        imageView.image = [UIImage imageWithCGImage:[context createCGImage:outputImage fromRect:outputImage.extent]];
    }

}

NB. Значение по умолчанию для контраста - 1,0 (максимальное рекомендуемое значение - 4,0).
Кроме того, здесь рассчитывается контраст на изображении imageView, поэтому повторный вызов этого метода приведет к накоплению контраста.Это означает, что если вы сначала вызовете этот метод со значением контрастности 2.0, а затем снова со значением контрастности 3.0, вы получите исходное изображение со значением контрастности, увеличенным на 6,0 (2,0 * 3,0), а не на 5,0.

Проверьте документацию Apple для получения дополнительных фильтров и параметров.

Чтобы получить список всех доступных фильтров и параметров в коде, просто запустите этот цикл:

NSArray* filters = [CIFilter filterNamesInCategories:nil];
for (NSString* filterName in filters)
{
    NSLog(@"Filter: %@", filterName);
    NSLog(@"Parameters: %@", [[CIFilter filterWithName:filterName] attributes]);
}
0 голосов
/ 28 мая 2012

Это старая ветка, но я получил ее по другой ссылке на SO, поэтому люди все еще читают ее.

В iOS 5 Apple добавила поддержку Core Image и приличное количество Core imageфильтры.Я почти уверен, что все упомянутые OP доступны

Core Image использует OpenGL шейдеры под крышками, так что это действительно быстро.Однако намного проще в использовании, чем OpenGL.Если вы еще не работаете в OpenGL и просто хотите применить фильтры к объектам CGImage или UIIMage, лучше использовать фильтры Core Image.

...