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

我的像素化image processingalgorithm有点问题。

我从一开始就把图像加载到unsigned char*types的数组中,然后在需要的时候修改这些数据并更新图像。 这个更新需要很长时间。 这是我如何做到的:

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

一切正常,但处理一个大的图像是非常缓慢的。 我试着在后台线程上运行这个,但是没有帮助。

所以基本上这要花太长的时间。 有没有人有任何想法如何改善?

正如其他人所build议的那样,为了在这些移动设备上拥有任何体面的处理性能,您需要将这项工作从CPU转移到GPU。

为此,我为iOS创build了一个名为GPUImage的开源框架 ,使得这种加速的image processing变得相对简单。 它确实需要OpenGL ES 2.0支持,但是过去几年销售的每一个iOS设备都有这个数据(统计数据显示,该领域的所有iOS设备都达到了97%)。

作为该框架的一部分,我捆绑的初始filter之一是像素化filter。 SimpleVideoFilter示例应用程序演示了如何使用这个控制器,通过一个控制处理图像中像素宽度的滑块:

像素化滤镜应用的屏幕截图

此滤镜是具有以下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 ); } 

在我的基准testing中,像这样的基于GPU的filter比iOS上的图像和video的CPU等效处理例程快6-24倍。 上面链接的框架应该可以合理地容易地join到应用程序中,并且源代码可以自由地供您自定义,但是您认为合适。

如何使用名为CIPixellateCore Imagefilter? 这是我如何实现它的代码片段。 你可以玩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 Filter Tutorial和一个可用的filter列表 。

更新#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; }]; 

对于像image processing这样的计算密集型任务来说,iPhone并不是一个好的设备。 如果您希望提高显示非常高分辨率图像的性能(可能同时执行一些image processing任务),请查看使用CATiledLayer 。 它是用平铺块显示内容,所以你可以只显示/处理内容数据在个别瓷砖上的需要。

我同意@Xorlev。 我唯一希望的是(假设你正在使用大量的浮点操作),你正在为arm6构build和使用拇指isa。 在这种情况下编译不带-mthumb选项,性能可能会提高。

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