看起来我摸了好多天,事实上我是摸了很多天。你以为我会摸很多天,结果我确实摸了很多天,这不就相当于没有摸了嘛!(算了这个梗太老了,一点都不好笑。)

本来觉得是不难的东西结果由于踩了很多坑结果搞了好久才搞出来,勉强算是知道怎么开头做这个表情合成了,那就这样,一步一步。

(参考论文

Liu, Zicheng & Shan, Ying & Zhang, Zhengyou. (2001). Expressive expression mapping with ratio images. 271-276. 10.1145/.383289. )

其实基本思路很简单,先找一个真实的无表情人脸和那个人的有表情人脸作为基础人脸。接着准备好要进行变形的那个人的无表情人脸。

接着我们在这些人脸上做出大量的标记点,标记出脸框眼睛眉毛等等的部分,然后对比基础的两个人脸,通过给每对标记点进行向量相减便能得到人脸上的部位在做表情时发生的变化。

然后我们找到目标人脸,将目标人脸的无表情标记与基础人脸的无表情标记进行简单对齐,通常来说人的无表情状态应该是相似的。然后使用刚才相减得到的变形向量对目标人脸的标记进行逆运算,便可以得到变化后的目标人脸标记。

最后我们使用目标人脸有表情的标记矩阵对无表情的目标人脸进行变形便可以得到带表情的人脸了,也就完成了表情映射。那接下来一步一步。

(下图是测试时对文章内的小姐姐进行人工挑眉操作)

二.进行表情标记

使用Matlab来进行表情标记是表情合成的第一步,我们需要将最能圈出人的表情的部分圈出来。这个过程可以是手工的,也可以使用机器自动化操作,在这里我手工进行了尝试。

第一步是使用imresize函数把准备好的图像转换为一样的大小,这样待会标记出来的点的坐标才不用再进行转换。

然后写好用于标记点的函数,使用ginput函数可以使我们在图像窗口中进行坐标的选定,选到的点会显示出来且并入返回矩阵中,若使用右键点击则会终止选定。

剩下的两个函数用于显示已经选好的标记点和将标记点进行连线。

最后的就是体力活耐心标定了,这里可以将脸的各个部位储存为不同的矩阵方便将来修改(至少把脸型分开),然后在标定表情时要注意如果是同一个人的表情可以先把之前标好的点显示出来再点新的点,甚至直接在旧的点上稍加修改,尽量不要使其在与表情无关的地方(例如脸耳朵之类的)有太大变化。这样最终合成的表情更加自然。

还有一点很自然,标定的点越多到时合成的效果就会越理想,但是要保证几张图片的点数量相等且顺序相同。还有要注意的就是标记的时候不要使点和部位太近,尽可能的是框住脸上部位,尽可能点在普通的皮肤(浅色区块)而不是眉毛的黑色区块之类的,这样会使最后的变形阶段不会产生很夸张的面部变形。还有一点就是建议把脸的轮廓(图像的轮廓应该也可以)圈一次,些标记点不用参与运算但是在后面变形时可以有效保证图像不会过度变形。

(下图是如论文类的实例对两张作为基础脸的小哥和无表情的小姐姐进行了标识)

三.向量计算及变形

获得上面的表情矩阵后就要来进行表情变形了。

首先我们把上面基础脸的表情矩阵点相减,得到偏移矩阵。接着把这个偏移矩阵作用于目标无表情脸上,就能得到目标的有表情矩阵,我们现在还不知道得到的表情矩阵到底效果如何,只能先期待是可以的。

接下来将刚才的目标脸矩阵组成一个大的矩阵(直接相连就可以),也就是要得到无表情脸的全脸矩阵和刚算出来的有表情脸的全脸矩阵作为接下来的参数。

然后我们使用fitgeotrans函数进行基于控制点(也就是我们得到的标记点)的图像变形,具体的使用官方文档里有,主要是变形模式选择'lwm',权重参数需要微调但是建议从官方推荐的12开始测试,这个参数主要是影响变形的强度,太小的话会过度变形,太大的话又会出不了效果。接下来刚才的矩阵我们把无表情的作为第一参数,有表情的作为第二参数。

这样就能得到一个PiecewiseLinearTransformation2d对象。然后使用imwarp函数依据这个变形对象输出得到的图像,warp途中可能会警告有些像素值被变形到画布外了,不用在意。看看怎么样吧。

(下图是表情变形后的图片与对于得到的矩阵)

这样也就得到了最终的图像了,因为一开始在对齐步骤时我们把图片进行过缩放,所以就像上面图片的比例是不正确的,但是图片的分辨率是和小哥图一样的。那么结尾再重新用imresize把图片转换为原图的分辨率就好。

然后最后使用imwrite把图片矩阵写回文件中,传统的表情合成就是这样子的了。

(下面是最终图片)

很明显效果还不理想,首先是有些变形方面的问题,这个我估计只要更细心地标记图片,增加不会变化的图片的标记点数量可以解决,再仔细调整权重参数可以解决。

除了变形出现的问题外还有一个问题就是人在做表情(例如这次的皱眉)是会有皱纹的,但是这里并没有出现皱纹,这使得表情看起来还不够可信,这个如果做得出来的话就是下一篇的内容了。

踩了很多坑不知道下次如何呢,摸了。