AidLux“换脸”案例源码详解 (Python)

“换脸”案例源码详解 (Python)

faceswap_gui.py用于换脸,可与facemovie_gui.py身体互换源码(上一篇文章)对照观看

  1. 打开faceswap_gui换脸案例
  2. 点读取函数
  3. 数学变换方法
  4. 换脸函数
  5. 图像预处理函数
  6. 检测模式函数
  7. 绘制网格函数
  8. 获取关键点及标志的函数(2~8步与“身体互换”相同,未验证是否存在细微差别)
  9. 构建程序的图形化类
  10. 初始化处理函数(首先被调用)
  11. 程序入口

打开facemovie_gui.py换脸案例

在VScode中进入代码编辑状态。

在这里插入图片描述

导入相关库

'''faceswap_gui.py用于examples中的换脸'''

'''
导入基础包作用详解
'''
#导入包介绍开始
#cv2模块是OpenCV 2.0的简写,在计算机视觉项目的开发中,
#OpenCV作为较大众的开源库,拥有了丰富的常用图像处理函数库,
#采用C/C++语言编写,可以运行在Linux/Windows/Mac等操作系统上,能够快速的实现一些图像处理和识别的任务。
import cv2

#math模块提供了许多对浮点数的数学运算函数。
import math

#sys模块包括了一组非常实用的服务,内含很多函数方法和变量,
#用来处理Python运行时配置以及资源,从而可以与前当程序之外的系统环境交互。 
import sys

#NumPy(Numerical Python) 是 Python 语言的一个扩展程序库,
#支持大量的维度数组与矩阵运算,
#此外也针对数组运算提供大量的数学函数库。
#在机器学习算法中大部分都是调用Numpy库来完成基础数值计算的。
import numpy as np
#导入包介绍结束

#BlazeFace是一个非常轻量级的人脸检测器,
#其在许多嵌入式设备中都可以达到超实时的效率
#在一些性能较好的手机gpu中甚至可达亚毫秒级
from blazeface import *

#cvs包是Aid内置的代替cv2的包,基本上cv2支持的函数cvs一样支持,cvs包在X模式下和非X模式下一样执行
#cvs更多详细介绍查看官网文档OpenCVhttps://www.aidlearning.net/showdoc/web/#/5?page_id=45
from cvs import *

# tflite_gpu,GPU加速代码由AID提供,TensorFlow Lite 支持多种硬件加速器。GPU 是设计用来完成高吞吐量的大规模并行工作的。
# 因此,它们非常适合用在包含大量运算符的神经网络上,一些输入张量可以容易的被划分为更小的工作负载且可以同时执行,通常这会导致更低的延迟。
# 在最佳情况下,用 GPU 在实时应用程序上做推理运算已经可以运行的足够快,而这在以前是不可能的
import tflite_gpu
##############################################################################
back_img_path=('models/rs.jpeg','models/wy.jpeg','models/zyx.jpeg','models/monkey.jpg','models/star2.jpg','models/star1.jpg','models/star3.jpg','models/star4.jpg')

#读图
faceimg=cv2.imread(back_img_path[0])
mod=-1
bfirstframe=True

点读取函数

'''
此函数读取点,输入文件路径,输出读取到的点集
'''
def readPoints(path) :
    #初始化一个空的点数组
    points = [];
    
    #读取点集
    with open(path) as file :
        for line in file :
            x, y = line.split()
            points.append((int(x), int(y)))
    
    #返回点
    return points

数学变换方法

'''
此函数应用仿射变换
'''
#ApplyAffineTransform使用srcTri、dstTri、src计算sto
#并输出一副图像的大小。
#应用一个仿射变换,这个变换由srcTri(源三角形)和dstTri(目标三角形)计算出
#输出一幅图像
def applyAffineTransform(src, srcTri, dstTri, size) :
    #仿射变换,又称仿射映射,是指在几何中,一个向量空间进行一次线性变换并接上一个平移,变换为另一个向量空间。
    #仿射变换需要一个M矩阵,但是由于仿射变换比较复杂,一般直接找很难找到这个矩阵,
    #opencv提供了根据变换前后三个点的对应关系来自动求解M的函数,这个函数就是:cv2.GetAffineTransform(src, dst)
    #由给定的一对三角形找出仿射变换,warpMat为仿射变换矩阵
    warpMat = cv2.getAffineTransform( np.float32(srcTri), np.float32(dstTri) )
    
    #将得到的仿射变换应用至源图像
    dst = cv2.warpAffine( src, warpMat, (size[0], size[1]), None, flags=cv2.INTER_LINEAR, borderMode=cv2.BORDER_REFLECT_101 )

    return dst

'''
检查某特定点是否在一个具体矩形内
'''
#判断某点是否在一个矩形内
#一个矩形由对角的两个点(四个坐标数据)组成
def rectContains(rect, point) :
    #原理:point数组中的两个值分别代表该点的x坐标、y坐标
    #rect数组中的四个值分别理解为左上角点的x坐标、左上角点的y坐标、矩形宽、矩形高
    
    #如果某点坐标在矩形左边界以左
    #或在矩形上边界以上
    #则不存在于矩形内
    if point[0] < rect[0] : 
        return False
    elif point[1] < rect[1] : 
        return False

    #如果某点坐标在矩形右边界以右
    #或在矩形下边界以下
    #则不存在于矩形内
    elif point[0] > rect[0] + rect[2] : #rect[0] + rect[2] 即指矩形右边界的x坐标(以下y坐标同理)
        return False
    elif point[1] > rect[1] + rect[3] :
        return False

    #以上可能性排除即可判定点在矩形内
    return True


'''
计算徳洛內三角形
'''
#计算徳洛內三角形
def calculateDelaunayTriangles(rect, points):
    #创建subdiv(细分)
    subdiv = cv2.Subdiv2D(rect);
    
    #将各点插入subdiv
    for p in points:
        subdiv.insert(p) 

    #初始化三角形列表、徳洛內三角形、点集
    triangleList = subdiv.getTriangleList();
    
    delaunayTri = []
    
    pt = []    
    
    #遍历三角形列表中的三角形
    #每个三角形是一个长度为6的数组
    for t in triangleList:      
        #在点集中加入三角形中每个点的x、y坐标
        #append是内置函数,向列表末尾压入元素  
        pt.append((t[0], t[1]))
        pt.append((t[2], t[3]))
        pt.append((t[4], t[5]))
           
        
        pt1 = (t[0], t[1])
        pt2 = (t[2], t[3])
        pt3 = (t[4], t[5])        
        
        if rectContains(rect, pt1) and rectContains(rect, pt2) and rectContains(rect, pt3):
            ind = []
            #根据坐标,从68个人脸检测器得到脸上的面部点
            for j in range(0, 3):
                for k in range(0, len(points)):       
                    #这里参数取1.0,若从三角形得到的点与输入points中各点在x、y坐标上距离均小于1.0,则向ind中加入下标k              
                    if(abs(pt[j][0] - points[k][0]) < 1.0 and abs(pt[j][1] - points[k][1]) < 1.0):
                        ind.append(k)    
            #三点构成一个三角形。
            #这里的三角形列表对应于FaceMorph中的tri.txt
            if len(ind) == 3:                                                
                delaunayTri.append((ind[0], ind[1], ind[2]))
        
        pt = []        
            
    
    return delaunayTri
        
'''
仿射及透明混合
'''
#从img1和img2仿射并进行透明混合,得到img
def warpTriangle(img1, img2, t1, t2) :

    #找到每个三角形(t1、t2)的外接矩形(r1、r2)
    r1 = cv2.boundingRect(np.float32([t1]))
    r2 = cv2.boundingRect(np.float32([t2]))

    #以每个矩形的左上角为基点的偏移点
    #初始化为空列表
    t1Rect = [] 
    t2Rect = []
    t2RectInt = []

    for i in range(0, 3):
        t1Rect.append(((t1[i][0] - r1[0]),(t1[i][1] - r1[1])))
        t2Rect.append(((t2[i][0] - r2[0]),(t2[i][1] - r2[1])))
        t2RectInt.append(((t2[i][0] - r2[0]),(t2[i][1] - r2[1])))


    # 填充三角形,得到遮罩(mask)
    mask = np.zeros((r2[3], r2[2], 3), dtype = np.float32)
    cv2.fillConvexPoly(mask, np.int32(t2RectInt), (1.0, 1.0, 1.0), 16, 0);

    #将变换后的图像应用于小矩形贴片
    img1Rect = img1[r1[1]:r1[1] + r1[3], r1[0]:r1[0] + r1[2]]
    #img2Rect = np.zeros((r2[3], r2[2]), dtype = img1Rect.dtype)
    
    size = (r2[2], r2[3])

    img2Rect = applyAffineTransform(img1Rect, t1Rect, t2Rect, size)
    
    img2Rect = img2Rect * mask

    #将矩形贴片中的三角区域复制到输出图像
    img2[r2[1]:r2[1]+r2[3], r2[0]:r2[0]+r2[2]] = img2[r2[1]:r2[1]+r2[3], r2[0]:r2[0]+r2[2]] * ( (1.0, 1.0, 1.0) - mask )
     
    img2[r2[1]:r2[1]+r2[3], r2[0]:r2[0]+r2[2]] = img2[r2[1]:r2[1]+r2[3], r2[0]:r2[0]+r2[2]] + img2Rect 

换脸函数

'''
换脸
'''

def faceswap(points1,points2,img1,img2):
    


    # # Read images
    # filename1 ='sabina.jpg'
    # filename2 ='bid.jpg' 
    
    # img1 = cv2.imread(filename1);
    # img2 = cv2.imread(filename2);
    img1Warped = np.copy(img2);    
    
    # Read array of corresponding points
    # points1 = readPoints('sabina.txt')
    # points2 = readPoints('bid.txt')    
    
    # 凸包(Convex Hull)是一个计算几何(图形学)中的概念。
    # #在一个实数向量空间V中,对于给定集合X,所有包含X的凸集的交集S被称为X的凸包
    #在二维欧几里得空间中,凸包可想象为一条刚好包著所有点的橡皮圈。
    #用不严谨的话来讲,给定二维平面上的点集,
    # 凸包就是将最外层的点连接起来构成的凸多边形,它能包含点集中所有的点。
    # 寻找凸包
    hull1 = []
    hull2 = []
    #cv2.convexHull是opencv提供的寻找凸包函数
    hullIndex = cv2.convexHull(np.array(points2), returnPoints = False)
          
    for i in range(0, len(hullIndex)):
        hull1.append(points1[int(hullIndex[i])])
        hull2.append(points2[int(hullIndex[i])])
    
    
    # 由凸包边界上的点得到徳洛內三角形
    sizeImg2 = img2.shape    
    rect 
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值