思路:
1. 面部皱纹纹理。变老后的皱纹并不是实时绘制,而是需要先准备一系列皱纹纹理,然后将皱纹纹理和正常面部纹理融合。
2.由于检测的人脸姿态多变,有的头正颈直,有的歪头,有的仰头,而皱纹纹理都是头正颈直的,所以还需要对皱纹纹理做合适的变形,而非旋转,旋转的话匹配精度不够。本文采用的是移动最小二乘法图像变形(mls)算法。
3.由于涉及到mls变形算法,所以需要控制点。本文采用的是提取人77个特征点,由于标准77个特征点主要分布在脸颊、眉毛、眼睛、鼻子、嘴巴,为了保证变形更精准,所以又计算增补了部分额头控制点,共计77个特征点作为变形控制点。
步骤:
1.准备几张面部皱纹的图,并标注人脸特征点

面部皱纹图人脸关键点,一共81个点
public static final float[] OLD_FACE = {62.0f, 296.0f, 62.0f, 362.0f, 76.0f, 430.0f, 97.0f, 505.0f, 133.0f...........};
人脸关键点位置分布图

人脸关键点采集
人脸关键点识别一般可以采用Dlib或者 Stasm + OpenCV,
使用Dlib的话可以参照face_landmark_detection 来获取人脸68个关键点,不依赖于OpenCV,但是需要61M的模型文件,同时也没有额头部分的标注。
使用Stasm可以参考示例minimal 使用它可以获取77个人脸关键点, 只需要OpenCV的几个xml的模型文件, 体积比dlib的模型小,比较适合移动端设备使用,所以我选择了这个。
SeetaFace2也是一个可行的方案,可以参考SeetaFace2 可以实现人脸81个关键点识别,不依赖于OpenCV,效果也不错,不过相比于Stasm,SeetaFace2不会标注人额头上的关键点。
最小二乘法
最小二乘法(又称最小平方法)是一种数学优化技术。它通过最小化误差的平方和寻找数据的最佳函数匹配。利用最小二乘法可以简便地求得未知的数据,并使得这些求得的数据与实际数据之间误差的平方和为最小。最小二乘法还可用于曲线拟合。其他一些优化问题也可通过最小化能量或最大化熵用最小二乘法来表达。
在图像处理领域paper:《Image Deformation Using Moving Least Squares》利用移动最小二乘的原理实现了图像的相关变形,而且这篇paper的引用率非常高,可以说是图像变形算法的经典算法,Siggraph上面的paper。

变老实现
1. 通过OpenCV+Stasm获取原始图像人脸关键点数据

2. 将图片切割成若干个网格,得到原始网格点

3.最小二乘法,得到变形后的网格点

最小二乘法,输入:
原始网格点:将图像切割成areaW * areaH 的网格区域
控制点:就是上面提供的81个人脸关键点。
目标控制点:原始图通过stasm得到的的人脸关键点。
输出:变形后的网格点
4.现在我们已经有了原始网格点、变形后的网格点,接下来就计算顶点纹理坐标和绘制索引,使用VBO绘制图元,绘制出经过变形的老人皱纹图,然后与原始图融合,得到最终变老效果。
4.1计算顶点数据

4.2计算绘制索引

4.3创建FloatBuffer和ShortBuffer,供后面使用

5.融合,变老shader

可以看到有两个2d 纹理
inputImageTexture:代表原图纹理
inputImageTexture2 :代表变形后的皱纹纹理
这一步就是对两层进行融合计算,内建函数mix混合,intensity代表皱纹透明度
mediump vec4 outputColor = vec4(base.rgb * (overlay.a * (base.rgb / base.a) + (2.0 * overlay.rgb * (1.0 - (base.rgb / base.a)))) + overlay.rgb * (1.0 - base.a) + base.rgb * (1.0 - overlay.a), base.a);\n"
6、VBO绘制

5.最终效果


网友评论