Как выполнить быстрый пиксельный фильтр на изображении? - PullRequest
3 голосов
/ 19 февраля 2011

У меня небольшая проблема с алгоритмом обработки пиксельных изображений.

Я загружаю изображение с начала в массив типа unsigned char* После этого при необходимости я изменяю эти данные и должен обновить изображение. Это обновление занимает слишком много времени. Вот как я это делаю:

CGDataProviderRef dataProvider = CGProviderCrateWithData(.....);
CGImageRef cgImage = CGImageCreate(....);
[imageView setImage:[UIImage imageWithCGImage:cgImage]]];

Все работает, но обрабатывать большое изображение очень медленно. Я попытался запустить это в фоновом потоке, но это не помогло.

Так что в основном это занимает слишком много времени. У кого-нибудь есть идеи как его улучшить?

Ответы [ 5 ]

16 голосов
/ 16 февраля 2012

Как уже предлагали другие, вы захотите переложить эту работу с ЦП на ГП, чтобы иметь какую-либо приличную производительность обработки на этих мобильных устройствах.

С этой целью у меня естьсоздал инфраструктуру с открытым исходным кодом для iOS под названием GPUImage , которая упрощает такую ​​ускоренную обработку изображений.Для этого требуется поддержка OpenGL ES 2.0, но каждое устройство iOS, проданное за последние пару лет, имеет это (статистика показывает примерно 97% всех устройств iOS в этой области).

Как часть этой платформы,один из начальных фильтров, которые я включил, является пиксельным.Пример приложения SimpleVideoFilter показывает, как это использовать, с ползунком, который контролирует ширину пикселя в обработанном изображении:

Screenshot of pixellation filter application

Этот фильтр является результатом фрагментного шейдера со следующимКод GLSL:

 varying highp vec2 textureCoordinate;
 uniform sampler2D inputImageTexture;
 uniform highp fractionalWidthOfPixel;

 void main()
 {
    highp vec2 sampleDivisor = vec2(fractionalWidthOfPixel);

    highp vec2 samplePos = textureCoordinate - mod(textureCoordinate, sampleDivisor);
    gl_FragColor = texture2D(inputImageTexture, samplePos );
 }

В моих тестах такие фильтры на основе GPU работают в 6-24 раза быстрее, чем эквивалентные процедуры обработки изображений и видео на iOS в iOS.Вышеприведенная структура должна быть достаточно простой для включения в приложение, а исходный код можно свободно настраивать по своему усмотрению.

3 голосов
/ 24 апреля 2015

Как насчет использования фильтра Core Image с именем CIPixellate? Вот фрагмент кода того, как я это реализовал. Вы можете играть с kCIInputScaleKey, чтобы получить желаемую интенсивность:

// initialize context and image
CIContext *context = [CIContext contextWithOptions:nil];
CIImage *logo = [CIImage imageWithData:UIImagePNGRepresentation([UIImage imageNamed:@"test"])];

// set filter and properties
CIFilter *filter = [CIFilter filterWithName:@"CIPixellate"];
[filter setValue:logo forKey:kCIInputImageKey];
[filter setValue:[[CIVector alloc] initWithX:150 Y:150] forKey:kCIInputCenterKey]; // default: 150, 150
[filter setValue:[NSNumber numberWithDouble:100.0] forKey:kCIInputScaleKey]; // default: 8.0

// render image
CIImage *result = (CIImage *) [filter valueForKey:kCIOutputImageKey];
CGRect extent = result.extent;
CGImageRef cgImage = [context createCGImage:result fromRect:extent];

// result
UIImage *image = [[UIImage alloc] initWithCGImage:cgImage];

Вот официальное Учебное пособие по фильтрам Apple и Список доступных фильтров .

Обновление # 1

Я только что написал метод для выполнения рендеринга в фоновом режиме:

- (void) pixelateImage:(UIImage *) image withIntensity:(NSNumber *) intensity completionHander:(void (^)(UIImage *pixelatedImage)) handler {

    // async task
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

        // initialize context and image
        CIContext *context = [CIContext contextWithOptions:nil];
        CIImage *logo = [CIImage imageWithData:UIImagePNGRepresentation(image)];

        // set filter and properties
        CIFilter *filter = [CIFilter filterWithName:@"CIPixellate"];
        [filter setValue:logo forKey:kCIInputImageKey];
        [filter setValue:[[CIVector alloc] initWithX:150 Y:150] forKey:kCIInputCenterKey]; // default: 150, 150
        [filter setValue:intensity forKey:kCIInputScaleKey]; // default: 8.0

        // render image
        CIImage *result = (CIImage *) [filter valueForKey:kCIOutputImageKey];
        CGRect extent = result.extent;
        CGImageRef cgImage = [context createCGImage:result fromRect:extent];

        // result
        UIImage *image = [[UIImage alloc] initWithCGImage:cgImage];

        // dispatch to main thread
        dispatch_async(dispatch_get_main_queue(), ^{
            handler(image);
        });
    });
}

Назовите это так:

[self pixelateImage:[UIImage imageNamed:@"test"] withIntensity:[NSNumber numberWithDouble:100.0] completionHander:^(UIImage *pixelatedImage) {
    self.logoImageView.image = pixelatedImage;
}];
1 голос
/ 15 декабря 2016

Преобразованный ответ @Kai Burghardt на Swift 3

func pixelateImage(_ image: UIImage, withIntensity intensity: Int) -> UIImage {

    // initialize context and image
        let context = CIContext(options: nil)
        let logo = CIImage(data: UIImagePNGRepresentation(image)!)!
        // set filter and properties
        let filter = CIFilter(name: "CIPixellate")
        filter?.setValue(logo, forKey: kCIInputImageKey)
        filter?.setValue(CIVector(x:150,y:150), forKey: kCIInputCenterKey)
        filter?.setValue(intensity, forKey: kCIInputScaleKey)
        let result = filter?.value(forKey: kCIOutputImageKey) as! CIImage
        let extent = result.extent
        let cgImage = context.createCGImage(result, from: extent)
        // result
        let processedImage = UIImage(cgImage: cgImage!)
        return processedImage

}

вызывая этот код как

self.myImageView.image =  pixelateImage(UIImage(named:"test"),100)
1 голос
/ 19 февраля 2011

iPhone не является отличным устройством для выполнения сложных вычислительных задач, таких как манипулирование изображениями.Если вы хотите повысить производительность при отображении изображений с очень высоким разрешением - возможно, при одновременном выполнении некоторых задач по обработке изображений, изучите использование CATiledLayer .Он предназначен для отображения содержимого в виде фрагментов, чтобы вы могли отображать / обрабатывать данные содержимого только по мере необходимости на отдельных фрагментах.

0 голосов
/ 19 февраля 2011

Я согласен с @Xorlev.Единственное, на что я надеюсь, это (при условии, что вы используете много операций с плавающей запятой), которые вы создаете для arm6 и используете thumb isa.В этом случае компиляция без опции -mthumb и производительность может улучшиться.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...