OpenCv--换脸

引言

在当今数字化时代,图像处理技术的发展日新月异。换脸技术作为其中一项极具趣味性和挑战性的应用,吸引了众多开发者和爱好者的目光。OpenCV 作为一款强大的开源计算机视觉库,为我们实现换脸提供了丰富的工具和方法。本文将深入探讨如何使用 OpenCV 进行换脸操作,从原理到实践,一步步带领大家揭开换脸技术的神秘面纱。

一、换脸技术原理

OpenCV换脸的基本原理是通过​​人脸检测​​定位源人脸和目标人脸的位置,利用​​关键点检测​​(如Dlib的68点模型)标记五官轮廓,然后通过​​仿射变换​​将源人脸对齐到目标人脸的几何结构上,最后将换脸区域与目标图像进行颜色和边缘的无缝混合。整个过程结合了几何变形、颜色校正和智能融合技术,实现逼真的换脸效果。换脸技术的核心在于找到两张人脸之间的对应关系,并将一张脸的特征映射到另一张脸上。

二、关键点检测

人脸关键点检测是计算机视觉中的一项重要技术,用于​​精确定位人脸的五官轮廓和关键特征点​​(如眼睛、眉毛、鼻子、嘴巴、下巴等)。它在人脸识别、表情分析、换脸(Face Swap)、AR滤镜等应用中发挥核心作用。

本文我们通过​Dlib库来实现对人脸的68点检测

python 复制代码
import dlib
#构建人脸检测器
detector = dlib.get_frontal_face_detector()
#读取人脸关键点定位模型
predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat")
#检测人脸
face = detector(img,0)
#返回68个关键点
landmarks = predictor(img, face)

三、仿射变换

图像的几何变换主要包括:平移,旋转,剪切,仿射,透视等

仿射变换​​ 是一种在几何中广泛使用的线性变换方法,它能够保持图像的 ​​平行性​​ 和 ​​直线性​​,但可能改变距离和角度。在计算机视觉和图像处理中,仿射变换常用于 ​​图像校正、旋转、缩放、平移、倾斜(剪切)​​ 等操作。

仿射变换简单的来说就是通过3对坐标点从一个二维坐标系变换到另一个二维坐标系

python 复制代码
# 计算 3 组对应点(源点 → 目标点)
mat_src = np.float32([[0, 0], [0, h-1], [w-1, 0]])     
mat_dst = np.float32([[0, 0], [100, h-100], [w-100, 100]])  

# 计算仿射变换矩阵​
M = cv2.getAffineTransform(mat_src, mat_dst)       
# 仿射变换​
dst = cv2.warpAffine(img, M, (w, h))   

​四、换脸

下面我们通过代码来实现对以下两张图片的换脸处理

首先导入相应的库

python 复制代码
import cv2
import dlib
import numpy as np

创建一个列表,保存脸部不同位置68个关键点模型

python 复制代码
JAW_POINTS=list(range(0,17))
RIGHT_BROW_POINTS=list(range(17,22))
LEFT_BROW_POINTS=list(range(22,27))
NOSE_POINTS=list(range(27,36))
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_BROW_POINTS+LEFT_EYE_POINTS+RIGHT_EYE_POINTS+NOSE_POINTS+MOUTH_POINTS]

POINTStuple=tuple(POINTS)

掩膜函数,生成人脸区域的掩膜

python 复制代码
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)  #填充凸包,数字在0~1之间 0.
    # 单通道im构成3通道im(3,行,列),改变形状(行、列、3)适应OpenCV
    im = np.array([im, im, im]).transpose((1, 2, 0))
    im = cv2.GaussianBlur(im,(25,25), 0)#这个参数比较重要,需要调整
    return im

使用dlib检测人脸并提取68个关键点。

python 复制代码
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

求出b脸仿射变换到a脸的变换矩阵M

python 复制代码
def getM(points1, points2):
    points1 = points1.astype(np.float64) #int8转换为浮点数类型
    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   # 除标准差,计算出归一化的结果

    # 奇异值分解,Singular Value Decomposition
    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))

通过高斯模糊,将图像 b 的颜色风格匹配到图像 a

python 复制代码
def normalColor(a,b):
    ksize=(111,111)
    aGauss=cv2.GaussianBlur(a,ksize,0)
    bGauss=cv2.GaussianBlur(b,ksize,0)
    weight=aGauss/bGauss
    where_are_inf=np.isinf(weight)
    weight[where_are_inf]=0
    return b*weight

主程序

python 复制代码
a=cv2.imread('hl2.jpg')
b=cv2.imread('hl1.jpg')

#构造脸部位置检测器
detector=dlib.get_frontal_face_detector()
#读取人脸关键点定位模型
predictor=dlib.shape_predictor('shape_predictor_68_face_landmarks.dat')

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

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

bMask=getFaceMask(b,bKeyPoints)
cv2.imshow('bMask',bMask)
cv2.waitKey(0)

#求出b脸仿射变换到a脸的变换矩阵M
M=getM(aKeyPoints[POINTStuple],bKeyPoints[POINTStuple])

#将b的脸部(bmask)根据M仿射变换到a上
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(0)

#获取脸部掩膜最大值(两个脸掩膜叠加)
mask=np.max([aMask,bMaskWarp],axis=0)
cv2.imshow('mask',mask)
cv2.waitKey(0)

#使用仿射矩阵M,将b映射到a
bWarp=cv2.warpAffine(b,M,dsize,borderMode=cv2.BORDER_TRANSPARENT,flags=cv2.WARP_INVERSE_MAP)
cv2.imshow('bWrap',bWarp)
cv2.waitKey(0)

得到换脸结果

python 复制代码
#求b图片的仿射到图片a的颜色值,b的颜色值改为a的颜色
bcolor = normalColor(a, bWrap)
cv2.imshow("bcolor",bcolor)
cv2.waitKey()

#图片混合
out = a * (1.0 - mask) + bcolor * mask
# 输出换脸结果
cv2.imshow("a",a)
cv2.imshow("b",bOriginal)
cv2.imshow("out",out/255)
cv2.waitKey()
cv2.destroyAllWindows()

最终得到结果如图所示

五、总结

通过以上步骤,我们利用 OpenCV 成功实现了换脸操作。从人脸检测、特征点提取到人脸对齐和图像融合,每一步都蕴含着计算机视觉技术的精妙之处。然而,目前的换脸技术仍存在一些局限性,如在复杂光照条件下、人脸姿态变化较大时可能效果不佳,以及换脸后的图像可能存在边缘不自然等问题。未来,随着深度学习等技术的不断发展,换脸技术有望在准确性和自然度上取得更大的突破,应用领域也将更加广泛,如影视制作、虚拟现实、娱乐等。

相关推荐
努力犯错玩AI几秒前
全球第二!中国17B开源图像模型HiDream-I1登顶榜单,比肩GPT-4o
人工智能·后端·开源
Elastic 中国社区官方博客1 小时前
Elasticsearch:AI 助理 - 从通才到专才
大数据·数据库·人工智能·神经网络·elasticsearch·搜索引擎·全文检索
newxtc1 小时前
【北交互联-注册/登录安全分析报告】
人工智能·安全·网易易盾·政务·极验
梓羽玩Python1 小时前
这个开源神器终结了AI数据整合的噩梦!一键聚合网页、代码、论文到剪贴板!
人工智能·python·github
3DVisionary1 小时前
3D-DIC技术:煤层开采瓦斯防治的精准监测解决方案
人工智能·计算机视觉·3d·安全生产·3d-dic技术 煤层开采·瓦斯防治 裂隙演化·物理模拟实验 数字图像相关算法
柯西梦回黄鹤楼1 小时前
《Training Language Models to Self-Correct via Reinforcement Learning》全文翻译
人工智能·语言模型·自然语言处理
洛水微寒1 小时前
大型语言模型中中医知识的多模态基准数据集
人工智能·语言模型·自然语言处理
2401_878624791 小时前
opencv 灰度实验
人工智能·opencv·计算机视觉
知来者逆1 小时前
计算机视觉——基于 Yolov8 目标检测与 OpenCV 光流实现目标追踪
深度学习·yolo·目标检测·计算机视觉·yolov8·目标追踪
进来有惊喜2 小时前
OpenCV 图像拼接
人工智能·opencv·计算机视觉