基于Python的人脸互换系统设计与实现
数据可视化 Final Project
目录
数据可视化 Final Project 1
- 项目介绍 1
1.1. 人脸互换(face swap) 2
1.2 人脸融合(face morph) 2
1.3 本征脸(eigen face) 2 - 算法结构与处理过程 2
2.1 人脸变换 2
2.1.1 人脸关键点检测 2
2.1.2 计算凸包 3
2.1.3 德劳内(Delaunay)三角划分 3
2.1.4 进行仿射变换 3
2.1.5 无缝融合 3
2.2 人脸融合 3
2.2.1 人脸关键点检测 3
2.2.2 定义融合度 4
2.2.3 采样点加权 4
2.2.4 德劳内三角划分 4
2.2.5 图像融合 4
2.3 本征脸 5
2.3.1 数据预处理 5
2.3.2 主成分分析 5
2.3.3 获得本征脸 5 - 代码结构 5
3.1 人脸互换 5
3.2 人脸融合 6
3.3 本征脸人脸 6
3.4 GUI 部分 6 - 开发环境 6
- 可执行文件及使用的数据集 7
5.1 数据集 7
5.2 可执行文件及运行方式 7 - 项目成果与反思 8
6.1 项目成果 8
6.1.1 人脸互换 8
6.1.2 人脸融合 8
6.1.3 本征脸 9
6.2 项目思考与改进 10
6.1.1 人脸互换 10
6.1.1 人脸融合 10
6.2.3 本征脸 10 - 小组成员工作内容 10
4.开发环境
在本次项目中,算法几接口 API 都是由 pyhton3.5(python3.6)完成的,其中还使用了
openCV 库。GUI 使用 pyqt 完成。API 使用 face++人脸关键点接口。
1.1.人脸互换(face swap)
人脸互换部分主要实现的功能是,给定任意两张人脸图片,通过一系列操作,使两个人的脸部交换,这部分需要的问题有:
1.不同的人的脸部结构千差万别,同一个人也会因为角度、面部表情的不同而导致差别,即如何实现不同图片的人脸对齐;
2.不同人脸的肤色、光照不同,即不同图片的面部亮度不同,在换脸后如何与整体亮度统一;
3.不同人脸的纹理不同,比如老人的皱纹等,如何实现换脸后纹理的统一。
1.2人脸融合(face morph)
在人脸融合部分,我们需要实现给定任意两张人脸图片和融合度α,通过一系列操作,实现两个人脸的融合。这一部分的困难在于:
1.人脸结构的检测与分割。对于给定的人脸图片,人脸的结构差异很大。
2.人脸融合度的构建。对于给定的融合度 α,如何对两张图片的人脸取样与映射。
1.3本征脸(eigen face)
在这一部分,需要对较大的数据集(几百张,几千张人脸图片)进行处理,通过主成分分析的方法,得到一定数量的人脸主成分。这一部分的主要困难在于数据集的预处理, 我们需要将不同图片中的人脸对齐,才能进行后续的处理。
2.算法结构与处理过程
2.1人脸变换
2.1.1人脸关键点检测
实现人脸变换的第一步,便是人脸关键点的检测,得到图片中的人脸的结构。在这里,我们利用旷视face++的API 来定位人脸关键的集合{V1,V2,…,Vn},其中关键点的数量可以选择 83 或者 106.
2.1.2计算凸包
在获取人脸关键点集合后,我们需要计算这些关键点的凸包(convex hull)(凸包是一个计算几何(图形学)中的概念:在一个实数向量空间 V 中,对于给定集合 X,所有包含X 的凸集的交集 S 被称为 X 的凸包。X 的凸包可以用 X 内所有点(X1,…Xn)的凸组合来构造.)在这里,我们计算凸包是为了获取这些人脸关键点组成的一个人脸区域。
2.1.3德劳内(Delaunay)三角划分
在获得凸包以后,我们对凸包内的人脸关键点进行德劳内三角的划分。德劳内三角划分能将我们的凸包区域进行分割,本文转载自http://www.biyezuopin.vip/onews.asp?id=14906并且更易于保留人脸的细节部分,并且因为获取仿射变换需要原图片和目标图片的各三个点,正好对应于原图和目标图的对应的德劳内三角。
2.1.4进行仿射变换
在获得原图片和目标图图片的德劳内三角以后,我们需要寻找两张图对应的三角形对,对这样的每一对三角形,我们可以计算得到一个仿射函数。这个仿射函数将被用于三角形对之间的仿射变换。重复这个操作,直到所有区域都操作完毕,我们得到了人脸的位置变换。
2.1.5无缝融合
在上述人脸仿射变换后,我们得到人脸结构和位置的变换,但我们没有对人脸区域亮度进行调整,这样会造成人脸区域和其他区域的颜色协调的问题。所以最后我们用 opencv 的无缝融合函数seamlessClone()来实现无缝融合操作。
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'mainPage.ui'
#
# Created by: PyQt5 UI code generator 5.10.1
#
# WARNING! All changes made in this file will be lost!
from morphGUI import *
from swapGUI import *
from eigenGUI import *
class Ui_MainPage(object):
#打开融合脸界面的函数
def startMorph(self):
self.morph=Ui_Morph()
self.morph.show()
#打开换脸界面的函数
def startSwap(self):
self.Swap=Ui_Swap()
self.Swap.show()
#打开生成特征脸的函数
def startEigen(self):
self.Eigen=Ui_Eigen()
self.Eigen.show()
#打开主界面的函数
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(718, 493)
MainWindow.setStyleSheet("background-color: rgb(2, 136, 209);")
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.label = QtWidgets.QLabel(self.centralwidget)
self.label.setGeometry(QtCore.QRect(40, 180, 231, 91))
self.label.setStyleSheet("font: 75 40pt \"Microsoft YaHei UI\";\n"
"color: rgb(255, 255, 255);")
self.label.setObjectName("label")
self.graphicsView = QtWidgets.QGraphicsView(self.centralwidget)
self.graphicsView.setGeometry(QtCore.QRect(0, 450, 731, 41))
self.graphicsView.setStyleSheet("background-color: rgb(255, 255, 255);")
self.graphicsView.setObjectName("graphicsView")
self.label_2 = QtWidgets.QLabel(self.centralwidget)
self.label_2.setGeometry(QtCore.QRect(40, 260, 401, 61))
self.label_2.setStyleSheet("font: 25 12pt \"Microsoft YaHei UI\";\n"
"text-decoration: underline;\n"
"color: rgb(255, 255, 255);\n"
"color: rgb(225, 225, 225);")
self.label_2.setObjectName("label_2")
self.pushButton = QtWidgets.QPushButton(self.centralwidget)
self.pushButton.setGeometry(QtCore.QRect(470, 170, 141, 34))
self.pushButton.setStyleSheet("QPushButton{background-color:#16A085;border:none;color:#ffffff;font: 25 9pt \"Microsoft YaHei UI\";}"
"QPushButton:hover{background-color:#333333;}")
self.pushButton.clicked.connect(self.startMorph)
self.pushButton.setObjectName("pushButton")
self.pushButton_2 = QtWidgets.QPushButton(self.centralwidget)
self.pushButton_2.setGeometry(QtCore.QRect(470, 250, 141, 34))
self.pushButton_2.setStyleSheet("QPushButton{background-color:#16A085;border:none;color:#ffffff;font: 25 9pt \"Microsoft YaHei UI\";}"
"QPushButton:hover{background-color:#333333;}")
self.pushButton_2.clicked.connect(self.startSwap)
self.pushButton_2.setObjectName("pushButton_2")
self.pushButton_3 = QtWidgets.QPushButton(self.centralwidget)
self.pushButton_3.setGeometry(QtCore.QRect(470, 320, 141, 34))
self.pushButton_3.setStyleSheet("QPushButton{background-color:#16A085;border:none;color:#ffffff;font: 25 9pt \"Microsoft YaHei UI\";}"
"QPushButton:hover{background-color:#333333;}")
self.pushButton_3.setObjectName("pushButton_3")
self.pushButton_3.clicked.connect(self.startEigen)
self.graphicsView_2 = QtWidgets.QGraphicsView(self.centralwidget)
self.graphicsView_2.setGeometry(QtCore.QRect(0, 0, 731, 41))
self.graphicsView_2.setStyleSheet("background-color: rgb(2, 136, 209);\n"
"border:none")
self.graphicsView_2.setObjectName("graphicsView_2")
MainWindow.setCentralWidget(self.centralwidget)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
#对主界面部件加上文字
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.label.setText(_translate("MainWindow", "Face#"))
self.label_2.setText(_translate("MainWindow", "Better Codes. Better Faces"))
self.pushButton.setText(_translate("MainWindow", "Face Morphing"))
self.pushButton_2.setText(_translate("MainWindow", "Face Swap"))
self.pushButton_3.setText(_translate("MainWindow", "EigenFace"))
class MyWindow(QtWidgets.QWidget, Ui_MainPage):
def __init__(self):
super(MyWindow, self).__init__()
self.setupUi(self)
#启动该文件,会启动GUI画面
if __name__=="__main__":
import sys
app=QtWidgets.QApplication(sys.argv)
widget = QtWidgets.QMainWindow()
login = Ui_MainPage()
login.setupUi(widget)
widget.show()
sys.exit(app.exec_())