iOS上的快速模糊

21

我在尝试模糊我的iOS应用程序屏幕的某个部分时遇到了麻烦。请查看图像以更好地了解我的尝试。

BlurBox

只有“BlurBox”中的内容需要模糊,其他内容可以清晰可见。因此,如果您查看表视图,则仅在BlurBox下方的内容会变得模糊(即使您滚动)。其余内容将保持清晰。
我的第一种方法是每隔0.01秒调用UIGraphicsGetImageFromCurrentImageContext()来获取BlurBox下的所有图层并将其压缩成一个图像。然后对该图像进行模糊处理,并在其上方显示出来。
我尝试过的模糊方法有:

https://github.com/tomsoft1/StackBluriOS

https://github.com/coryleach/UIImageAdjust

https://github.com/esilverberg/ios-image-filters

https://github.com/cmkilger/CKImageAdditions

[layer setRasterizationScale:0.25];
[layer setShouldRasterize:YES];

除了一些自定义尝试之外,我还研究了苹果的GLImageProcessing,但我认为它对我在这里要做的事情有点过度。

问题在于它们都太慢了。该应用程序不会上架到应用商店,因此我可以使用任何私有/未文档化的框架。

我想到的一个有点离谱的想法是覆盖我使用的所有组件(UITableViewCells、UITableView等)的drawRect方法,并在运行时独立地模糊每个组件。然而,这需要一些时间,这听起来甚至可行吗?


更新:

我尝试使用如下的CIFilters:

CIImage *inputImage = [[CIImage alloc] initWithImage:[self screenshot]];

CIFilter *blurFilter = [CIFilter filterWithName:@"CIGaussianBlur"];
[blurFilter setDefaults];
[blurFilter setValue: inputImage forKey: @"inputImage"];
[blurFilter setValue: [NSNumber numberWithFloat:10.0f]
                           forKey:@"inputRadius"];


CIImage *outputImage = [blurFilter valueForKey: @"outputImage"];

CIContext *context = [CIContext contextWithOptions:nil];

self.bluredImageView.image = [UIImage imageWithCGImage:[context createCGImage:outputImage fromRect:outputImage.extent]];

这个确实能够工作,但是速度非常慢。:(
我发现有些实现只会对从磁盘加载的图像进行模糊处理。如果我传入使用UIGraphicsGetImageFromCurrentImageContext()创建的UIImage,则无法工作。你有任何想法吗?

更新:

我已尝试patel的建议,如下所示:

CALayer *backgroundLayer = [CALayer layer];

CIFilter *blurFilter = [CIFilter filterWithName:@"CIGaussianBlur"];
[blurFilter setDefaults];
backgroundLayer.backgroundFilters = [NSArray arrayWithObject:blurFilter];

[[self.view layer] addSublayer:backgroundLayer];

然而,它不起作用 :(

自添加赏金以来的最新更新:

我已成功使用TomSoft1的stackblur将BlurBox正确运作,因为他添加了在飞行中将图像规范化为RGBA格式(32位/像素)的能力。但它仍然相当慢。

我有一个计时器每0.03s调用一次更新,以获取BlurBox下方的图像,对该图像进行模糊处理,并在屏幕上显示出来。我需要在BlurBox上提高“fps”的帮助。


1
CIBoxBlur 在 iOS 上不存在。请尝试使用 CIGaussianBlur - epatel
зіҹзі•...еҲҡеҲҡеҸ‘зҺ°CIGaussianBlurеңЁiOS 5дёҠд№ҹдёҚеӯҳеңЁгҖӮ - epatel
1
GIGaussianBlur确实可以工作,但速度非常慢。 - random
啊...我正在查看内置类别。 - epatel
1
只是提一下,StackBluriOS 不支持 iOS 6.0。 - geekay
5个回答

41
我建议使用Brad Larson的GPUImage,它完全由GPU支持,可用于各种图像处理效果。它非常快速,甚至在他的演示应用程序中,他可以从相机进行实时视频处理,帧率非常出色。

https://github.com/BradLarson/GPUImage

我写了一段代码,可以应用基本的盒子模糊效果,使图像的上下三分之一模糊,但保留图像中间的清晰。他的库非常广泛,包含几乎所有想象得到的图像滤镜效果。
GPUImagePicture *stillImageSource = [[GPUImagePicture alloc] initWithImage:[self screenshot]];

GPUImageTiltShiftFilter *boxBlur = [[GPUImageTiltShiftFilter alloc] init];
        boxBlur.blurSize = 0.5;

[stillImageSource addTarget:boxBlur];

[stillImageSource processImage];

UIImage *processedImage = [stillImageSource imageFromCurrentlyProcessedOutput];

6
我建议使用GPUImageUIElement作为需要模糊的项目的输入。如果您想仅模糊UI元素的某一部分,可以修改GPUImageGaussianSelectiveBlurFilter以涵盖矩形区域而不是圆形区域。 - Brad Larson
1
在与我的老板交谈后,我担心我将无法使用这个能让我的生活变得轻松10000倍的神奇库。我们可以使用外部“类”,但不能使用完整的库。据说是一些法律问题。然而,我认为我可以使用Brad的代码作为抽象我需要的部分的起点。这非常有帮助,谢谢。+150建议和+2^56给@BradLarson开源这个神奇的代码。 - random
13
@cory - 这似乎是一个奇怪的限制,因为在许可证方面,在使用少量类和全部框架之间实际上没有真正的区别。我想你可以从框架中挑选出需要的类,比如 GPUImageOutput、GPUImageUIElement、GPUImageFilter 和修改后的 GPUImageSelectiveBlurFilter(以及一些依赖项),将它们直接构建到你的应用程序中。这样就可以避免使用框架作为静态库的问题。我以前从来没有遇到过任何关于代码的问题,因为我不在意人们如何使用它或从中获利。 - Brad Larson
1
@cory - 单独的类应该可以自己使用,只要您引入适当的超类和一两个支持元素即可。您不需要从中提取任何内容。如果您不熟悉OpenGL ES 2.0,则其中有很多脚手架代码可能很难拆分。 - Brad Larson
@BradLarson 是的,请提供一个“GPUImageUIElement”的示例,谢谢! - strange
显示剩余5条评论

8
虽然回答有点晚了,您可以使用Core Image滤镜。它很慢的原因是这行代码。
CIContext *context = [CIContext contextWithOptions:nil];

在苹果的文档中,为了获得最佳的核心图像性能,首先要注意不要每次渲染都创建一个CIContext对象。上下文存储了大量的状态信息,重用它们更加高效。我的个人解决方案是为核心图像上下文创建一个单例。因此,我只创建了一个实例。我的代码在GitHub上的演示项目中。

https://github.com/KyleLopez/DemoCoreImage

随意使用它,或者找到其他您喜欢的解决方案。我发现CoreImage中最慢的部分是上下文,之后的图像处理非常快。


感谢您的回复,随着iOS7的即将到来,我认为这个问题几乎已经过时了,但是我看了看您的项目,它非常有帮助。 - random
2
很抱歉,这不是导致它变慢的原因。我已经对这种模糊操作进行了分析,渲染模糊图像占用了99.9%的时间。制作上下文所需的时间甚至都没有显示出来。 - w0mbat
根据苹果文档,CoreImage上下文似乎支持CPU和GPU渲染。有上下文选项可以禁用软件渲染器(CPU),从而强制上下文使用GPU。 - sang
你一定要尝试回收CIContext - 不这样做会造成巨大的性能开销。@w0mbat提出的性能损失在模糊而不是上下文创建中的观察是误导人的。这很可能是真的,但是模糊需要花费时间的原因是它需要进行大量设置(例如加载和编译用于模糊的着色器)。如果您重复使用上下文,则模糊将不需要重新创建着色器,应该可以运行得更快。 - Gavin Maclean

1
我没有测试过,但我想知道是否可以在您想要模糊框的位置放置一个CALayer,然后找到一个有用的CIFilter,并将其设置在CALayerbackgroundFilters上。只是一个想法。
请参见CALayer.backgroundFilters

可能需要使用compositingFilter - epatel
读了更多,似乎API已经存在,但不起作用... 真糟糕。 - epatel
你有其他想法可以尝试吗? - random
3
iOS 上的 CALayer 不支持背景、合成和滤镜等过滤器,除非仅仅是将指针存储到滤镜中。 - Jesse Gumpo

0
你可以尝试使用苹果核心图像滤镜(CIFilter)的函数集。它们需要iOS 5,所以你可能无法使用它们。
我不确定它是否比你尝试过的方法更快,但我过去在项目中使用过它,它效果很好。如果你可以截取出想要模糊的屏幕部分,将其放入图像中,通过滤镜处理,然后在屏幕上适当位置重新显示它,那应该可以实现。
我曾经使用过这些滤镜来实时更改图像的颜色,而且效果很好。

http://developer.apple.com/library/ios/#DOCUMENTATION/GraphicsImaging/Reference/QuartzCoreFramework/Classes/CIFilter_Class/Reference/Reference.html


你介意分享一下你是如何实现的代码吗?昨天我试了好几个小时,但使用CIFilters始终无法使其正常工作。我注意到,对于我尝试过的某些方法,只有当我传递从磁盘加载的图像时,它才会模糊。如果我尝试传递使用UIGraphicsGet...抓取的图像,则无法正常工作。 - random
我已经更新了我的问题,展示了我如何使用CIFilter。你能检查一下是否正确吗? - random
看起来你已经使用了GIGaussianBlur的CIFilter(从上面的更新中),但速度太慢了。我用了另一个滤镜,但这对你没有帮助,抱歉。 - PaulPerry

0

你有没有尝试过这个库:

https://github.com/gdawg/uiimage-dsp

它使用vDSP/Accelerate框架,似乎很容易使用。
顺便说一下:0.01秒似乎太快了,0.03应该也可以。

如果我将其提起,它仍然落后于刷新率。是的,我已经尝试过gdawg的库。问题在于它无法模糊使用UIGraphicsGet抓取的图像。它只能模糊从磁盘加载的图像。有任何想法为什么会这样? - random
@random UIImage 可以由 CIImage 或 CGImage 支持:但是 gdawg 的库仅支持 CGImage(同样适用于我的当前的 Swift 移植版)。但是,如果您愿意,可以将 CIImage 转换为 CGImage。或者您可以考虑使用我的 renderImagecropped 来保留 CGImage。请参见链接:https://github.com/Coeur/ImageEffects/blob/master/SwiftImageEffects/ImageEffects%2Bextensions.swift - Cœur

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接