置为0.25秒,接着在updateBlur
方法中将_blurFilter.blurRadiusInPixels
设置为4.0f
。
编译并运行程序,多次打开菜单,看看效果如何:
实时模糊
实时模糊涉及到的技术具有一定的难度,有些难点需要解决才行。为了有效的进行实时模糊,我们需要不停(每秒60帧)的截屏、模糊计算和显示。使用GPUImage
每秒中处理60张图片(模糊并显示图片)一点问题都没有。
真正棘手的问题是什么呢?如何实时的截取屏幕图片,信不信由你!
由于截取的屏幕是主用户界面,所有必须使用CPU的主线程来截屏,并将其转换为一幅图片。
提醒:如果事物每秒钟的变化速度在46帧以上,那么人眼就无法识别出来了。这对于开发者来说也是一种解脱——现代处理器在各帧之间可以完成更多的大量工作。
线程中简洁的分支
当运行程序时,会执行大量的指令列表。每一个指令列表都运行在各自的线程中,而我们又可以在多个线程中并发运行各自的指令列表。一个程序在主线程中 开始运行,然后会根据需要,创建新的线程,并在后台执行线程。如果之前你并没有管理过多线程,你可能在写程序的时候总是在主线程中执行指令。
主线程主要处理与用户的交互,以及界面的更新。确保主线程的响应时间是非常关键的。如果在主线程上做了太多的任务,你会明显的感觉到主界面响应迟钝。
如果你曾经使用过Twitter货Facebook,并滚动操作过它里面的内容,你可能已经感觉到后台线程在执行操作了——在滚动的过程中,并不是所有的个人图片立即显示出来,滚动过程中,程序会启动后台线程来获取图片,当图片获取成功之后,再显示到屏幕中。
如果不使用后台线程,那么table view的滚动过程中,如果在主线程上去获取个人图片,会感觉到table view被冻结住了。由于图片的获取需要一些时间,所以最好将这样耗时的操作让后台线程来做,这样就能对用户界面做平滑的操作和响应了。
那么对本文的程序有什么影响呢?之间介绍了,UIView
的截屏APIs操作必须在主线程中运行。这就意味着每次截屏时,整个用户界面都会被冻结中。
对于静态模糊效果时,由于这个截屏操作很快,你不会感觉到界面的冻结。并且只需要截屏一次。然而在实时模糊效果中需要每秒中截屏60次。如果在主线程中做这样频繁的截屏操作,那么animation和transition会变得非常的迟钝。
更糟糕的时,如果用户界面复杂度增加,那么在截屏过程中就需要消耗更多的时间,那么就会导致整个程序无法使用了!
那么怎么办呢!
一些潜在的实时模糊方案
这里有一个关于实时模糊方案:源代码开源的live blur libraries,它通过降低截屏的速度来实现实时模糊效果,并不是使用每秒截屏60次,可能是20、30或者40次。即使看起来没有多大区别,但是你的眼睛还是能发现一定的迟钝——模糊效果并没有跟程序的其它部分同步起来——这样一来,界面看起会没有模糊效果更加的糟糕。
实际上苹果在它们自己的一些程序中处理实时模糊并不存在类似的问题——但是苹果并没有公开相关的API。在iOS 7中UIView
的截屏方法,相比于旧方法,性能有了很大的提升,但还是不能满足实时模糊的需求。
一些开发者利用UIToolbar
的模糊效果来做一些不好的操作。没错,这是有效果的,但是强烈建议不要在程序中使用它们。虽然这不是私有API,但是这并不算是一种可行的方法,苹果也可能会reject你的程序。也就是说在,在之后的iOS 7版本中,并不能保证还能正常使用。
苹果可以在任何时候对UIToolBar
做出修改,或许你的程序就有问题了。在iOS 7.0.3更新中,苹果的修改已经影响到UIToolbar和UINavigationBar了,有些开发者也因此报告出利用相关模糊效果已经失效了!所以最好不要陷入这样潜在的陷阱里面!
一个折中的方法——对视频实时模糊
OK,此时你可能在想,要想在程序中做到实时模糊是不可能的了。那么还有什么方法可以突破限制,做到实时模糊效果呢?
在许多场景中,静态模糊是可以接受的。上一节中,我们对view做适当的修改,让用户看起来是对背景图做的实际模糊处理。当然,这对于静止不动的背景是合适的,并且还可以在模糊背景上实现一些不错的效果。
我们可以做一些实验,看看能不能找到一些效果来实现之前无法做到的实时模糊效果呢?
有一个方法可以试试:对实时视频做模糊处理,虽然截屏是一个非常大的瓶颈,但是GPUImage
非常的强大,它能够对视频进行模糊(无论是来自摄像头的视频或者已经录制好的视频,都没问题)。
利用GPUImage对视频进行模糊处理
利用GPUImage
对视频的模糊处理与图片的模糊处理类似。针对图片,我们实例化一个GPUImagePicture
,然后将其发送给GPUImageiOSBlurFilter
,接着再将其发送给GPUImageView
。
类似的方法,对于视频,我们使用GPUImageVideoCamera
或GPUImageMovie
,将后将其发送给GPUImageiOSBlurFilter
,接着再将其发送给一个GPUImageView
。GPUImageVideoCamera
用于设备中的实时摄像头,而GPUImageMovie
用于已经录制好的视频。
在我们的starter工程中,已经实例化并配置好了GPUImageVideoCamera
。现在的任务是将播放和录制按钮的灰色背景替换为视频的实时滤镜效果。
首先是将此处提供的灰色背景实例UIView
替换为GPUImageView
。完成之后,我们需要调整每个view的contentRect
(基于view的frame)。
这听起来对每个view都需要做大量的工作。为了让任务变得简单,我们创建一个GPUImageView
的子类,并把自定义的代码放进去,以便重用。
打开File/New/File…
,然后选择iOS/Cocoa Touch/Objective-C class
,如下所示:
将类命名为BlurView
,继承自GPUImageView
,如下图所示:
打开ViewController.m
文件,将下面的import添加到文件顶部:
还是在ViewController.m
中,在@implementation
中找到_recordView
和_controlView
的声明,将其修改为BlurView
类型,如下所示:
1
2
3
4
5
6
7
|
BlurView *_recordView;
UIButton *_recordButton;
BOOL _recording;
BlurView *_controlView;
UIButton *_controlButton;
BOOL _playing;
|
然后按照如下代码修改viewDidLoad
方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2 |