最近朋友圈火爆的军装照H5想必大家还记忆犹新。原理是先提取照片中的人脸,然后用模板合成。官方合成过程据说是天天Ptu提供的技术支持。后端合成后返回给前端显示。形式很新颖,效果很好。整个过程中涉及的人脸识别和图像合成两大核心技术在前端都有相应的解决方案,因此理论上前端也可以完成人脸识别-提取-合成的全过程,实现H5纯前端军事照片效果。前端人脸识别首先要人脸识别,听着听着并不深奥。无非就是利用人脸特征规则对图像进行匹配识别。基本上只能根据内置的规则库进行匹配。这个库的质量决定了识别的质量。通常比较成熟的解决方案是引入机器学习,让程序不断自我修正和完善,进一步提高识别率。机器学习的前端也有库,但是两者的结合还没有找到,所以不要对前端人脸识别的准确率抱有太大的期望。现有的前端人脸识别库并不多。这里我们选择trackingjs,效果相对较好。这个库非常强大。顾名思义,它可以完成各种跟踪图像处理任务,比如人脸识别。这只是其众多功能之一,通过可选插件,还可以准确识别眼睛、鼻子等面部特征的位置。这里我们只使用trackingjs来实现人脸识别。初始化人脸识别任务的代码如下://实例化vartracker=newtracking.ObjectTracker(['face']);//识别回调tracker.on('track',function(event){if(!event.data.length){returnconsole.log('屏幕上没有人脸');}event.data.forEach(function(rect,i){console.log(rect);//单人脸数据})})//配置参数...初始化这样一个人脸识别任务,调用方法如下:tracking.track('#img',tracker);//'#img'参数为目标图像事件。识别回调中选择器的数据为数组形式的人脸数据。如果长度为0,则表示图像中没有人脸或识别失败。如果识别成功,单张人脸数据格式如下:{x:number,//人脸位于原图x轴方向y:nuber,//人脸位于y轴方向原图的轴方向width:number,//人脸区域的宽度height:nubmer//人脸区域的高度}有了这个人脸数据,就很容易从原图中提取这个区域,并且的当然前端使用canvas。例子如下:varimg=document.getElementById("img");varfaceCtx=document.getElementById("mycanvas").getContext('2d');vartheFace=...;//假设我们识别人脸//使用drawImage()方法绘制人脸faceCtx.drawImage(img,theFace.x,theFace.y,theFace.width,theFace.height,0,0,theFace.width,theFace.height);到这里我们就实现了人脸识别+提取,代码量也不多,其实里面有个小坑只有在实践中才会发现,那就是trackingjs的配置,可以参考文档识别相关的4个配置,分别是:setClassifiers(classifiers)setEdgesDensity(edgesDensity)setScaleFactor(scaleFactor)setStepSize(stepSize)看不懂,看不懂,文档里也没有对他们有用的解释。在测试中,我只使用了最后两个配置。翻译过来就是“scaleFactor”和“stepsize”,经过无聊的人工测试,发现这两个参数的有效取值范围分别是1-2和1.1-2,setStepSize不能为1,否则浏览器会卡顿,所以从1.1开始设置值,值超过2也是可以的,但是识别成功的概率很低。通过调整这两个参数,大部分图片都可以成功识别,但是人脸的特写很难识别,可能需要配合。至于另外两个参数,实在是没有耐心继续人肉测试了。有兴趣就自己回去玩吧。前端图像处理经过上一步的识别+提取,我们得到了人脸图像。要达到合成军装照片的效果,我们还需要对人脸图像进行处理,使色调与模板保持一致,以便以后融合在一起,没有任何违和感。以军装照片为例,我们需要对人脸重新上色,达到“旧”旧照片的效果。用PS大家就知道了,但是在前端怎么实现呢?这里需要用到腾讯前端团队出品的AlloyImage。它是一个前端图像处理库,称为前端PS。比如要实现上面的效果,我们只需要这样:this.width,this.height,"#808080").act("高斯模糊",4).act("色相/饱和度调整",22,45,0,true),"overlay").replace(this);}然后就老脸了,很简单,AlloyImage的使用可以说是傻逼,有兴趣的可以花五分钟看官方文档,就不去了在这里详细说一下,然后说说我们的图片处理和别人日常P图的差距,虽然我们已经得到了理想的色调,但是如果我们要将任何人脸与特定的人脸进行对比,有两点模板是必不可少的合成。首先是面部角度校正。如果模板是正的,你的照片是歪的,直接暴力拼接肯定会不一致,所以你需要先识别人脸角度,修正到指定的角度;然后是人脸中心定位,因为人脸识别提取的结果不一定以人脸中心为中心,所以在合成前必须先识别出人脸的中心线,作为与模板定位的依据。然而,这些我们都没有,只能对输入图像提出更高的要求。如果我们输入一张嘴巴歪、眼睛眯的图片,结果只会很尴尬。***图像合成部分更简单。先把处理好的人脸画到画布指定位置,然后在上面铺上抠图人脸透明png模板就完成了。在实际过程中,需要处理一些小问题,比如根据模板的人脸大小将人脸图像缩放到合适的大小;裁剪模板时,边缘要模糊,尽量保留模板原有的面部轮廓,只裁剪五官。即便如此,合成结果还是很容易乱,但是纯前端处理也没有更好的办法。效果已经展示出来了,还是看个例子比较好。该示例提供了三种图像输入源,分别是本地图像、远程图像和内置示例。大部分内置图片都提前在PS里矫正了角度,内置图片会自动匹配我提前调整好的参数,不出意外可以直接识别人脸;如果选择本地图片作为图片源,***选择头部垂直姿势的正面照片,参考内置图片的参数设置调整参数。一次识别失败是正常的,需要多次调整;也可以使用远程图片识别,但是由于canvas受跨域策略的影响,远程图片只能识别,不能提取合成。示例:纯前端军装照片合成(http://refined-x.com/projects/codes/tracking.html)生产需求,但是整个example铺开后,对人脸识别和图像处理技术有了基本的了解,canvas操作的一些细节问题的解决也略微填补了这方面的知识空白,有点获得。
