如何在图像上执行快速像素化滤镜?

时间:2011-02-19 05:18:03

标签: iphone ios image-processing

我的像素化图像处理算法有点问题。

我将图像从头开始加载到unsigned char*类型的数组中 之后,在需要时,我会修改此数据并更新图像。 此更新需要很长时间。我就是这样做的:

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

一切正常,但处理大图像的速度很慢。我尝试在后台线程上运行它,但这没有帮助。

所以基本上,这需要太长时间。有谁知道如何改进它?

6 个答案:

答案 0 :(得分:16)

正如其他人所建议的那样,您需要将这项工作从CPU卸载到GPU,以便在这些移动设备上获得任何良好的处理性能。

为此,我创建了an open source framework for iOS called GPUImage,这使得进行这种加速图像处理变得相对简单。它确实需要OpenGL ES 2.0支持,但过去几年销售的每台iOS设备都有此功能(统计数据显示该领域所有iOS设备的97%)。

作为该框架的一部分,我捆绑的初始过滤器之一是像素化过滤器。 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的过滤器比iOS上的图像和视频的等效CPU绑定处理例程快6-24倍。上面链接的框架应该相当容易合并到一个应用程序中,并且源代码可以自由地供您自定义,无论您认为合适。

答案 1 :(得分:3)

使用名为Core Image的{​​{1}}过滤器怎么样? 这是我如何实现它的代码片段。您可以使用CIPixellate来获得所需的强度:

kCIInputScaleKey

以下是官方Apple Filter TutorialList of available Filters

更新#1

我刚写了一个方法来在后台执行渲染工作:

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

这样称呼:

- (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);
        });
    });
}

答案 2 :(得分:1)

iPhone不是一个很好的设备,可以执行图像操作等计算密集型任务。如果您希望提高显示非常高分辨率图像的性能 - 可能在同时执行某些图像处理任务时,请查看使用CATiledLayer。它是以平铺块的形式显示内容,因此您只能根据需要在单个图块上显示/处理内容数据。

答案 3 :(得分:1)

转换@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)

答案 4 :(得分:0)

我同意@Xorlev。我唯一希望的是(假设您正在使用大量浮点运算),您正在为arm6构建并使用thumb isa。在这种情况下,编译时不使用-mthumb选项,性能可能会提高。

答案 5 :(得分:0)

实际上,这很简单。更高的输入比例键意味着更多的像素化。

let filter = CIFilter(name: "CIPixellate")
filter?.setValue(inputImage, forKey: kCIInputImageKey)
filter?.setValue(30, forKey: kCIInputScaleKey)

let pixellatedCIImage = filter?.outputImage

结果是CIImage,您可以使用UIImage将其转换为

UIImage(ciImage: pixellatedCIImage)