OpneCV与dlib-换脸


使用OpenCV与dlib进行换脸是一个复杂但有趣的过程,它涉及人脸检测、特征点提取、图像变换和融合等多个步骤。以下是一个基于OpenCV和dlib实现换脸技术的概述:

一、环境准备

首先,需要安装OpenCV和dlib库。这两个库都是Python中常用的图像处理库,其中OpenCV提供了丰富的图像处理函数,而dlib则专注于机器学习和图像处理中的高级算法。

二、基本原理

OpenCV与dlib在换脸技术中的应用,主要基于计算机视觉和图像处理的相关原理。以下是对这一过程中涉及的关键知识与原理的详细解释:

1.人脸检测

  • 原理:使用预训练的模型(如dlib的正面人脸检测器)在图像中检测人脸区域。

OpenCV与dlib的作用:

  • OpenCV提供图像读取、预处理和显示等功能。
  • dlib则专注于人脸检测,提供高效且准确的人脸检测器。

2.特征点提取

  • 原理:在检测到的人脸区域内,使用特征点提取算法(如dlib的68点特征提取模型)提取关键特征点。
    这些特征点通常位于人脸的眼角、嘴角、鼻尖等显著位置,用于后续的人脸对齐和图像变换。

OpenCV与dlib的作用:

  • OpenCV提供图像处理函数,如灰度转换、边缘检测等,为特征点提取做准备。
  • dlib的68点特征提取模型能够准确地提取人脸特征点,为后续的图像变换提供基础。

3.图像变换与对齐

  • 原理:使用仿射变换或透视变换等图像变换算法,将源人脸的特征点区域变换到目标人脸的相应位置。
    仿射变换可以保持图像的直线性和平行性,适用于人脸的初步对齐。
    透视变换则能够处理更复杂的图像变换,如人脸的旋转和缩放。

OpenCV与dlib的作用:

  • OpenCV提供仿射变换和透视变换等图像变换函数。
  • dlib的特征点提取为图像变换提供了必要的输入信息。

三、基本步骤

1.加载人脸检测器和特征点预测模型

  • 使用dlib加载正面人脸检测器和68个特征点预测模型。这些模型用于检测图像中的人脸并提取关键特征点。

2.读取人脸图片

  • 使用OpenCV的imread函数读取两张要进行换脸的图片。

3.获取人脸的特征点

  • 将图像转换为灰度图,并使用dlib的人脸检测器检测人脸区域。然后,使用特征点预测模型提取人脸的68个特征点。这些特征点对应面部的特定位置,如眼睛、鼻子、嘴巴等。
    仿射变换三角形
  • 对每个三角形进行仿射变换,将其从源图像(即要移植脸部特征的图片)变换到目标图像(即脸部特征的目标图片)中的相应位置。这是实现换脸的关键步骤之一。

4.脸部轮廓掩模

  • 在仿射变换之后,使用凸包算法构建目标人脸区域的凸包,并生成一个掩模(mask)。这个掩模用于后续的无缝克隆步骤中,以确保换脸后的图像看起来更加自然。

四、代码实现

1.导入库

import cv2
import dlib
import numpy as np

cv2:OpenCV库,用于图像处理和计算机视觉任务。
dlib:一个包含机器学习算法和工具的库,这里用于面部特征点检测。
numpy:一个用于科学计算的库,提供了大量的数学函数和操作数组的工具。

2.定义面部特征点

JAM_POINTS = list(range(0, 17))
RIGHT_BROW_POINTS = list(range(17, 22))
LEFT_BROW_POINTS = list(range(22, 27))
NOSE_POINT = list(range(27, 35))
RIGHT_EYE_POINTS = list(range(36, 42))
LEFT_EYE_POINTS = list(range(42, 48))
MOUTH_POINTS = list(range(48, 61))
FACE_POINTS = list(range(17, 68))
#  关键点集
POINTS = [LEFT_BROW_POINTS + RIGHT_EYE_POINTS + LEFT_EYE_POINTS + RIGHT_BROW_POINTS + NOSE_POINT + MOUTH_POINTS]
# 处理元组,后续使用方便
POINTStuple = tuple(POINTS)

定义多个面部特征点的集合,如眉毛、眼睛、鼻子、嘴巴等。
POINTS变量包含了用于生成面部掩膜的特征点集合。

3.定义特征函数

(1)getFaceMask函数

def getFaceMask(im, keyPoints):     # 根据关键点获取掩膜
    im = np.zeros(im.shape[:2], dtype=np.float64)
    for p in POINTS:
        points = cv2.convexHull(keyPoints[p])   # 获取凸包
        cv2.fillConvexPoly(im, points, color=1)  # 填充凸包,数字在1~2之间
    # 单通道im构成3通道im(3,行,列),改变形状(行、列、3)适应0penCV
    im = np.array([im, im, im]).transpose((1, 2, 0))
    im = cv2.GaussianBlur(im, (33, 33), 0)
    return im
  • 根据给定的面部特征点生成一个面部掩膜。
  • 使用cv2.convexHull获取特征点的凸包,然后用cv2.fillConvexPoly填充凸包,生成掩膜。
  • 对掩膜进行高斯模糊处理,以减少边缘的锯齿效应。

(2)getM函数

def getM(points1, points2):
    points1 = points1.astype(np.float64)    # int转换为浮点数
    points2 = points2.astype(np.float64)

    c1 = np.mean(points1, axis=0)   #归一化:(数值-均值)/标准差
    c2 = np.mean(points2, axis=0)
    points1 -= c1   # 减去均值
    points2 -= c2
    s1 = np.std(points1)    # 方差计算标准差
    s2 = np.std(points2)

    points1 /= s1   # 除标准差,计算归一化结果
    points2 /= s2

    # 奇异值分解
    U, S, Vt = np.linalg.svd(points1.T * points2)
    R = (U * Vt).T  # 通过U和Vt找到R
    return np.hstack(((s2 / s1) * R, c2.T - (s2 / s1) * R * c1.T))

  • 计算两个面部特征点集合之间的仿射变换矩阵。
  • 首先对特征点进行归一化处理,然后使用奇异值分解(SVD)找到最佳仿射变换矩阵。

(3)getKeyPoints函数

def getKeyPoints(im):   # 获取关键点
    rects = detector(im, 1)  # 获取人脸方框的位置
    shape = predictor(im, rects[0])
    s = np.matrix([[p.x, p.y] for p in shape.parts()])
    return s
  • 使用dlib的面部检测器和特征点预测器获取图像的面部特征点。

(4)normalColor函数

def normalColor(a, b):
    ksize = (155, 155)
    aGauss = cv2.GaussianBlur(a, ksize, 0)  # 对a进行高斯滤波
    bGauss = cv2.GaussianBlur(b, ksize, 0)
    weight = aGauss / bGauss    # 计算目标图像调整颜色的权重值,存在0除警告,可忽略。
    where_are_inf = np.isinf(weight)
    weight[where_are_inf] = 0
    return b * weight
  • 调整图像的颜色,使其与目标图像的颜色相匹配。
  • 通过计算两个图像的高斯模糊版本之间的比例来实现。

4.数据预处理

a = cv2.imread('xz.png')
b = cv2.imread('yy.png')

detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor('shape_predictor_68_face_landmarks.dat')

aKeyPoints = getKeyPoints(a)    # 获取关键点
bKetPoints = getKeyPoints(b)

bOriginal = b.copy()

aMask = getFaceMask(a, aKeyPoints)  # 获取掩膜
cv2.imshow('aMask', aMask)
cv2.waitKey()

bMask = getFaceMask(b, bKetPoints)
cv2.imshow('bMask', bMask)

  1. 使用cv2.imread读取两张图像。
  2. 初始化dlib的面部检测器和68点特征点预测器。
  3. 对两张图像分别获取面部特征点,并生成对应的面部掩膜。

5.仿射变换

M = getM(aKeyPoints[POINTStuple], bKetPoints[POINTStuple])

dsize = a.shape[:2][::-1]

bMaskWarp = cv2.warpAffine(bMask, M, dsize, borderMode=cv2.BORDER_TRANSPARENT, flags=cv2.WARP_INVERSE_MAP)
cv2.imshow('bMaskWarp', bMaskWarp)
cv2.waitKey()

mask = np.max([aMask, bMaskWarp], axis=0)
cv2.imshow('mask', mask)
cv2.waitKey()


  • 使用getM函数计算从图像b到图像a的仿射变换矩阵。
  • 使用cv2.warpAffine函数将图像b的面部(包括掩膜)根据仿射变换矩阵变换到图像a的坐标系中。

6.生成并显示图像

bWarp = cv2.warpAffine(b, M, dsize, borderMode=cv2.BORDER_TRANSPARENT, flags=cv2.WARP_INVERSE_MAP)
cv2.imshow('bWarp', bWarp)
cv2.waitKey()

# 求b图片的仿射到图片a的颜色值,b的颜色值改为a的颜色
bbolor = normalColor(a, bWarp)
cv2.imshow('bcolor', bbolor)
cv2.waitKey()

out = a * (1.0 - mask) + bbolor * mask
cv2.imshow('a', a)
cv2.imshow('b', b)
cv2.imshow('out', out/255)
cv2.waitKey()
cv2.destroyAllWindows()

  • 使用掩膜将变换后的图像b的颜色与图像a进行融合。
  • 在掩膜区域使用图像b的颜色,在非掩膜区域使用图像a的颜色。
  • 显示原始图像、变换后的图像和最终的换脸结果。

五、总结

使用OpenCV和dlib进行换脸是一个具有挑战性的任务,但它也是一个非常有趣和实用的应用。这里我们通过定义一系列特征函数,来对两张人图片进行操作,并将最后获得的结果进行融合展示,为大家展示了OpenCV与dlib库的联合使用。

我们可以通过修改高斯核函数的核大小来实现高质量的换脸效果。
注意:
核的宽度和高度都必须大于0。
核的宽度和高度都必须是奇数。

猜你喜欢

转载自blog.csdn.net/2301_77698138/article/details/143100253
今日推荐