AI换脸是一个娱乐性比较强的应用,这种错位感让人觉得非常有趣。很多人都以为这是什么黑科技,但这里想告诉大家,AI换脸其实很简单。只需要你会一点Python基础,就可以通过本文的notebook笔记实现自己的AI换脸程序。在学习网友matthewearl的基础上,笔者制作了一个新手可操作的notebook笔记,本文就是对这个实验的总体思路和中间结果的介绍。想要上手尝试的朋友,可以发送关键字【notebook】获得笔记代码的链接,毕竟有些平台下不允许发链接。

1 技术路线

如果需要精细化的做人脸相关的工作,获得人脸的轮廓点是一个大前提。在英文文献中,轮廓点检测也被称为 Face Alignment,感兴趣的朋友可以用这个关键词检索到很多相关的技术论文。本文的AI换脸实现就是建立在68个人脸轮廓点(Landmarks)的基础之上。而 Face Alignment 必须依赖一个人脸检测器提供人脸位置的矩形框,即 Face Detection。也就是说,本文所介绍的换脸或者其他精细化人脸操作的基础是 Face Detection + Face Alignment。但是,这两个技术并不需要我们亲自开发,dlib已经提供了效果不错、使用简便的第三方库。




python和AI作图 python ai教程_缩放

AI换脸技术路线图



我们想要将图像B中的人脸放置到目标图像A中,这就需要将B中的人脸变换到A中人脸所在位置,然后截取对应区域并替换。如上图所示,这一步骤可以由OpenCV支持完成。最后,由于两张图像的人脸可能存在光照、色相等方面的不一致,为了替换后更加逼真,所以需要对图像B的颜色进行一些调整。

那么,最大的难点是什么呢?如果一定要找一个难点,那就是动手去做(Just do it)。

2 人脸检测

目标检测(Object Detection)一直都是计算机视觉应用的基础,这也是每次出现新的目标检测算法总能引起很大轰动的原因。完成人脸相关的任务,那自然就是需要人脸检测了。dlib提供了一个人脸检测器,可以使用如下方式获取:

face_detector = dlib.get_frontal_face_detector()

如果你对dlib提供的人脸检测还有使用上的疑惑,可以查看其官方人脸检测说明。对输入的两幅带有人脸的图像进行 Face Detection,就可以获得其中人脸位置的矩形框,效果如下:




python和AI作图 python ai教程_python和AI作图_02

人脸检测效果图



3 轮廓点检测

dlib实现了Kazemi等人2014年发表的《One millisecond face alignment with an ensemble of regression trees》文章中提出的算法,对算法本身感兴趣的朋友,可以点击文章名链接。

这里,我们就直接使用dlib提供的模型文件shape_predictor_68_face_landmarks。下载解压之后,就可以使用以下代码载入

landmark_detector = dlib.shape_predictor(LANDMARK_MODEL_PATH)

关于landmark_detector更多的使用方法,可以访问官网的landmark检测说明。对输入的这两幅图像检测人脸轮廓点的效果如下:




python和AI作图 python ai教程_OpenCV_03

人脸轮廓点检测效果图



需要说明的是,如果你有更好的人脸轮廓点检测算法,完全可以替换掉dlib提供的程序。不过,新手刚开始还是需要先把这个流程走一遍。

4 源人脸图像变换

需要将上图中右边的人脸放到左边图像的人脸处,但很显然,两张人脸的大小和位置都不一样。无法直接操作,所以需要进行图像变换,才能将第二幅图中的人脸投影到第一幅中人脸的位置。

现在,我们已经得到了两张人脸上的landmark坐标,那么求解变换就不是一个很难的问题。第一,我们可以在这68个点中选择三个稳定的点构成3个匹配点对,然后利用OpenCV中的接口求解一个仿射变换矩阵。当然,这种方式会导致对轮廓点的利用率很低,而且结果常常不是太稳定。第二,我们可以假设一个特殊的仿射变换 —— 相似变换可以达到目的,那么就能够利用这68个点对完成普氏分析。其流程是,先计算缩放因子,然后求解一个旋转变换,最后再求解平移变换,这样就可以构成一个完整的相似变换:




python和AI作图 python ai教程_OpenCV_04


其中,s为缩放因子,R为旋转矩阵,T为平移矩阵。针对当前输入的两幅图像而言,相似变换矩阵如下:


python和AI作图 python ai教程_python和AI作图_05


这个相似变换有什么用呢?下图就是调用OpenCV的cv2.warpAffine()函数应用该相似变换对源人脸图像B进行变换的结果:


python和AI作图 python ai教程_python展示两幅图_06

相似变换的效果图


对比目标图像A就会发现,warp后的原图像人脸位置与图像A中的人脸位置一致。这样是不是就可以进行替换呢?还有个小问题,即我们只想替换人脸这一局部,而不打算影响其他部分,这就需要生成人脸部的遮罩(Mask)。

5 生成遮罩并粗略替换人脸

可以选择人脸的一些部位轮廓点生成遮罩,这里选择两只眼睛、眉毛、鼻子和嘴巴这几部分组成一个遮罩的区域。生成遮罩的算法可以直接调用OpenCV中的cv2.convexHull()和cv2.fillConvexPoly()这两个函数完成。在两张原始图像上直接生成的遮罩效果如下:


python和AI作图 python ai教程_人脸检测_07

原始图像的人脸遮罩效果图


根据这两个遮罩,可以查看一下图像A和图像B中选中的区域:


python和AI作图 python ai教程_python展示两幅图_08

遮罩选中的原始图区域


从上图中可以看出,这就是我们需要替换的区域,但是很明显,这样的遮罩是不能够直接使用的,因为人脸的位置没有对齐。所以需要对源人脸图像B的遮罩作上面已经求解的相似变换。然后对比图像A和warp图像B的遮罩,取并集形成一个统一的遮罩,这样就能保证遮罩操作的区域是在两幅图像中相同的位置。

目标图像A的遮罩与统一遮罩的对比效果图如下:


python和AI作图 python ai教程_OpenCV_09

目标遮罩和统一遮罩对比图


统一遮罩作用于目标图像A和warp后的源人脸图像B的效果如下:


python和AI作图 python ai教程_OpenCV_10

统一遮罩效果图


到这一步,整个换脸工作就完成了90%了。上图显示的遮罩作用区域内,就可以使用右边的源人脸图像B替换左边的目标人脸图像。虽然可能感觉哪里不对劲,但是先替换看看也没什么损失。


python和AI作图 python ai教程_OpenCV_11

粗略替换效果图


看看上图中的右边图像,人脸确实给替换上了,但是脸色就太诡异了。这种状况并不是少见的特例,反而是大概率会遇到的,因为很难保证任意的两个人脸图像的光照、色相以及对比度等状况完全一致。因此需要对源人脸图像B进行颜色调整。

6 颜色矫正

这里使用一种比较简单的颜色平衡的方法。如果想要将图像B的色调按照图像A来进行调整,那么可以按照如下方程描述进行颜色缩放:


python和AI作图 python ai教程_python和AI作图_12


其中 Ra 和 Rb 这种带小写字母脚标的符号表示通过对 RA 和 RB 这种正常原始图像的高斯模糊化之后的结果。

按照这种方式矫正图像B的颜色之后,效果如下:


python和AI作图 python ai教程_python和AI作图_13

颜色矫正后的效果图


关注上图右边图像的人脸区域,可以发现已经由原来的“偏黄”,转变为与左边人脸处相似的“偏红”。对颜色矫正之后的图像B使用已经生成的统一遮罩,可以得到最终的换脸结果:


python和AI作图 python ai教程_人脸检测_14

最终换脸结果


上面换脸的结果整体看起来还是不错的,没有太大的违和感。但是还是需要说明,这里使用的颜色平衡的方式仍然非常粗糙。如果想要让融合之后的效果更加逼真,可能需要考虑在这方面花费更多的功夫。

说明:如果本文的链接无法点击跳转,可以点击【阅读原文】在博客文章上查看链接。