本文主要探讨搭建一款Android平台下美颜相机可能需要填的坑,内容会不断更新。。
相机框架
相机框架相对比较简单,现有的开源代码很多,可以很容易的实现拍照和录像的功能。
预览尺寸选择
预览尺寸就是相机显示纹理的尺寸,也是每一帧原始数据的尺寸,一般相对拍照尺寸较低(1080P就算比较高的预览尺寸了)
拍照尺寸选择
拍照尺寸只在拍照时起作用,往往可以调的很高,而且获取数据非常快(例如1300万像素,相当于1080P数据的7倍左右)
拍照:已被弃用的Camera API可以提供takePicture进行拍照,在onPictureTaken(final byte[] data, final Camera camera)中可以获得包括了Exif数据的图片,直接写入到文件就是一张没有做过任何处理的照片,也可以转成bitmap再做处理(图片尺寸就是拍照尺寸),但是很容易出现OOM的问题,例如1300万像素的照片至少占内存50M,分分钟死给你看。
录像:使用MediaRecorder可以进行录像,相机需要在录像模式和预览模式之间切换,使用较为方便
获取每一帧数据:onPreviewFrame(byte[] data, Camera camera)中可以获取到每一帧的原始数据,如果处理不及时下一帧就会被丢弃,帧率并不是固定的(也就是可能比相机预览的速度慢很多),这里的图像大小和设定的预览尺寸相同
Camera2 API
后期会切换到这个API,ImageReader类确实封装的很好,虽然我还没搞清楚怎么获取原始数据
实时滤镜
用CPU来处理图像真的太慢慢慢慢慢慢了,尤其是在移动平台下,因此一定要用GPU来加速处理。
由于是图像处理,OpenGL尚能够胜任,而且兼容性和通用型都比较好,所以不考虑RenderScript和OpenCL,相机的数据可以直接利用GL_TEXTURE_EXTERNAL_OES进行GPU加速的格式转换,在显示层面不需要自己再做YUV420SP/YUV420P到RGB的转换,之后就可以使用GL_TEXTURE_2D来进行各种处理。GPU相对CPU要快很多,举个例子:在Mali400MP1这种渣渣GPU上,高斯模糊可以在720P的图像上连续处理6次依然丝般润滑毫无卡顿之感。
叠加特效后拍照/截屏/离屏渲染
在叠加了滤镜、面具、面部贴纸后,如果要拍照,有两种可能的解决方案:
拍照后离屏渲染:效率较高,但是较为复杂,需要自行管理一个工作线程,因为照片的尺寸远大于预览的纹理尺寸,而且内存开销较大,适合于软件定位为图像处理/专业相机应用时的情况,拍完照片后不影响后续拍照,用户体验可以做的很棒(例如各大国产ROM自带的滤镜功能,拍完后不会感觉到任何卡顿)
直接对Surface截屏:这是最简单粗暴的方法,代码简单,非常鲁棒,内存占用也低(毕竟屏幕分辨率2K已经算高了,也才200万像素),经过测试,Snow相机和FaceU都是采用的这种方法,特点是方便快捷,但是生成的图片尺寸较小(一般就是屏幕分辨率),适合于软件定位为偏社交相机应用的情况,拍完照直接编辑预览。
录屏录像
录屏在Android 5.0之前是没有提供接口的(需要root),如果是5.0及以上版本录屏(直播)就会非常方便,但是如果只是录制相机的预览区域就不同了(对于Surface进行录制)
硬编:硬件编码的CPU占用低,码率可以拉的很高,不卡顿,MediaRecorder可以直接录制视频,但是没法实时处理,在5.0及以上版本也可以录制Surface了,但是封装的太好,使用并不自由。
MediaCodec是一个相对“野生”的API,最常用的硬编格式是”video/avc”,也就是喜闻乐见的h264格式,目前大部分手机都支持硬编(Snow相机、FaceU以及各大直播软件都首选此方案),虽然要求API在4.3以上才能够比较完美的运行,但是不能硬编的手机真的太少了(除了我的破手机)
MediaCodec可以直接对Surface进行录制(参考 Google的grafika),因为我们直接使用了SurfaceTexture做预览,不需要每次都获取原始数据在用BufferQueue喂数据,这也就意味着我们可以很容易的让预览结果和录制视频的结果不同,分辨率也可以不同,例如视频中可以实时打水印,但是预览不显示水印之类的(当然一般是相同的)
软编:软编就是用CPU来进行编码,常见的例如FFMpeg软编,资源占用高,可能卡顿,增大APK体积,但是兼容性很好,还可以一直兼容到原始社会(Android2.3)
图像后期
如果定位专业相机软件,那么图像后期的功能就多了去了,完全可以把整个PS都搬过来,如果是偏向社交的软件,那么后期主要是一些美化,加文字、贴图的效果(当然一键分享到朋友圈是一定一定一定要有的功能)
视频后期/转码
视频后期其实和实时录制比较类似,就是一个解码,加特效再编码的过程,当然分辨率和码率就可以很高很高啦,毕竟不是实时的应用
人脸相关应用
实际上,稳定高效的人脸检测、对齐才是在做一款美颜类APP是会碰到的最大的问题。市场上主流的软件也都是采用第三方的解决方案,例如商汤(ST)、虹软(ArcSoft)、Face++、优图(Tencent)等,虽然实时的人脸识别技术历史悠久,但是最近的直播热好像又让她焕发了新生。
现在人工智能大热,不管什么方向好像深度学习都能取得非常优异的成绩,也正兴起着一股把神经网络搬到移动平台上来的风潮(OpenCL、RenderScript、Vulkan、Metal等,当然也有直接上GPU跑的),神经网络用来处理图像,识别物体的App大家应该也都见过不少。
然而,如果要在线处理,就要保证算法足够高效,在移动平台上好像还没有公认的很好的公开解决方案。OpenCV的LBP做人脸检测其实很好,但是还有待调教,其他的像JDA、npd等都可以考虑。
在Github上转了一圈,找到不少开源项目,有C语言的,Java封装的,Python封装的,居然还有.so语言的,真是让我大开眼界。
个人感觉国内这一块的风气并不是很好,稍微有点小成果就拿去圈钱(@于仕琪老师,多向山老师学学),当然这也好理解,毕竟难度远高于拿着别人的轮子自己调调UI做一个App上线,大家都不容易嘛。
有了人脸的特征点就可以做很多很多事情了,例如换脸肯定就建立在高效的人脸特征点跟踪上,剩下的就是贴个图的事情(例如OpenGL的Blend),如果是脸部贴纸就更轻松了。当然,”美颜2.0”也是建立在人脸识别的基础上(例如大眼小脸),如果没有人脸检测,就只能做做肤色、光线调整什么的,或者来个哈哈镜,功能就会大受限制。
直播推流
直播推流有很多现有的解决方案,可能也并不是美颜相机的重点(是直播App的重点呢,哈哈),但是直播App和美颜相机用到的技术有很大的交集,因此直播推流也会成为后期探索的内容之一(例如硬编录屏推流,软编录像等等)。