表情捕捉驱动另一张脸或者3D人脸是元宇宙一项比较热门的技术,目前已有好多相关的产品出现,应用于如虚拟主播等场景。本人对这项技术进行了思考后,想到photoshop有一项图像自由变形的功能,那么是不是可以基于这样一个功能结合人脸特征点的识别,来实现摄像头捕捉人脸并驱动另一张avatar脸呢?答案应该是可行的。主要思路如下:
当然本篇并不是一下子来实现avatar功能,本篇先来解决一下一个核心功能,那就是以控制点驱动图片的像素运动,这项技术其实早就在一些美颜软件进行了大量的应用,可以对人的五官进行微调,相当于对五官进行了微整形,比如增大眼睛等。效果如下:
“微整形”本质上是通过指定的控制点位置变化来影响周边的像素点的变化,从而达到图像局部变形的效果,我们见到的一些3D动画软件也是这样的原理,即通过骨骼(控制点)绑定周围的平面或点(像素),通过控制骨架的运动,来实现模型的运动。
收到这样的启发,我们如果要控制图像的变化,也可以通过构建控制点对周边像素的影响权重,去实现以少数点控制多数点的目的。
如下图,我们定义了一个控制点,然后把控制点的周边的黑色像素进行与控制点”绑定“,然后定义权重(这里为1的情况),就是实现了控制这个区域任意移动的功能:
如果改变一下权重,会出现这样的效果:
应用在人脸上,就可以实现五官的变形了。
基于以上的思想或原理,我们可以进行算法设计,其实在以前一篇博文中也实现过类似的变形算法——人脸识别有趣应用2——自动增大眼睛效果,本次把这个方法给通用化,适合任意点的控制,及多点的控制。
算法核心如下:
(1)遍历当前图像所有点
(2)对当前点进行分析,获取当前点相对于当前控制点位移的权重
(3)根据权重,和当前点相对当前控制点新旧位置的偏移关系,计算当前点应该有的偏移量
(4)根据当前点的偏移量,改变当前点的像素三个通道的值
主要代码如下:
#遍历各点
for i in range(W):
for j in range(H):
#计算与控制点距离
newdistance=((i-newlocal_x)*(i-newlocal_x)+(j-newlocal_y)*(j-newlocal_y))
new_dist=math.sqrt(newdistance)
if new_dist==0:
u=center_x
v=center_y
else:
#计算当前点的偏移量
u=int(np.floor((i-newlocal_x)+center_x))
v=int(np.floor((j-newlocal_y)+center_y))
if u<=0:
u=0
if v<=0:
v=0
if u>=W:
u=W-1
if v>=H:
v=H-1
#当前点的偏移量乘以影响的权重
du=(i-u)*ratiomap[v][u]
dv=(j-v)*ratiomap[v][u]
#对多个控制点,进行偏移量线性叠加
bimap[j][i][0]=bimap[j][i][0]+du
bimap[j][i][1]=bimap[j][i][1]+dv
当然,要控制局部的图像,如眼睛的大小,我们靠一个控制点是不行的,需要通过更多的控制点,并相互影响来实现局部的变形。具体实现起来,我们是通过逐个计算每个控制点,对每个控制点对图片每个像素的影响进行计算,最终进行线性叠加,得到所有控制点对整个图片的影响值。当然这个算法对python来说可能会存在性能上的问题,本篇注重功能,性能方面可以有比较多的方法,这里暂且不表。
关于权重的实现,我们是通过对每个控制点创建一个与图像等长款的权重图来存储每个像素点的权重值,如果有N个控制点,就有N个权重图:
if auto_ratio:#自动权值创建
ratiomap=np.zeros((H,W))#创建权重图
for i in range(W):
for j in range(H):
distance=((i-center_x)*(i-center_x)+(j-center_y)*(j-center_y))
old_dist=math.sqrt(distance)
#ratio=1
ratio=1-old_dist/R#根据距离大小线性衰减
if ratio<=0:
ratio=0
ratiomap[j][i]=ratio
以上是程序创建自动权重,相当于3D软件自动创建骨架对模型的权重,是通过距离的远近线性方式确定权重的,其实这里可以演化出多种创建权重的公式,可以根据具体项目进行设计调整。
另一种是,根据后期效果的需要,我们可以在其它软件,如ps软件中手工创建精细的权值图,然后读入权值图来实现更加精确的控制!
为了方便起见,我们可以利用opencv里面一些鼠标和监盘交互的功能,来实现动态的进行增加或者删除控制点的功能,方便进行人脸”编辑“:
至此,把python+opencv实现人脸微整形的主要原理及python实现进行了描述,这个功能并不是很复杂,有了这样的功能,给接下来我们用人脸识别特征点去驱动另一张avatar的脸提供了基础,我们会继续进行下一步的工作,完成后公布工作的成果。
本篇所有python代码已经上传至资源库:所有源码
ps:时间仓促多有错误之处,勿喜无喷,错误或改进意见请留言,原创不易,且行且珍惜