dlib实现人脸图像换脸:从原理到代码实践
创作时间:
作者:
@小白创作中心
dlib实现人脸图像换脸:从原理到代码实践
引用
CSDN
1.
https://m.blog.csdn.net/m0_64588135/article/details/145996396
本文将详细介绍如何使用dlib库实现人脸图像换脸功能。通过检测人脸关键点、生成掩码、计算仿射变换矩阵、调整颜色等步骤,最终实现两张图像中人脸的替换。文章包含完整的代码示例和运行结果展示,适合有一定编程基础的读者学习和实践。
dlib实现人脸图像换脸
1 换脸准备
1.1 所需库和模型
需要opencv、numpy、dlib库以及68 点人脸关键点检测模型shape_predictor_68_face_landmarks.dat
import cv2
import numpy as np
import dlib
detector = dlib.get_frontal_face_detector()
pred = dlib.shape_predictor('shape_predictor_68_face_landmarks.dat')
1.2 遮罩操作
1.2.1 公式及参数
用于图像处理或计算机图形学中的遮罩操作,通常用于将两张图像或颜色值按遮罩(mask)进行混合。公式如下:out=a×(1.0 − mask)+b×mask
- a:背景图像或颜色值。
- b:前景图像或颜色值。
- mask:遮罩值,范围通常为 [0,1]
- 当 mask=0 时,输出完全来自 a
- 当 mask=1 时,输出完全来自 b。
- 当 mask介于 0 和 1 之间时,输出是 a 和 b 的线性混合。
1.2.2 应用场景
- 图像合成:将前景和背景图像按遮罩混合。
- 颜色调整:通过遮罩控制颜色值的混合比例。
- 透明度处理:遮罩可用于控制透明度,实现渐变效果。
1.3 实现过程
人脸换脸功能可以通过检测人脸关键点、进而生成掩码、再计算仿射变换矩阵、然后调整颜色使两张图像肤色相符、最后根据公式将人脸进行替换
2 实现函数
2.1 人脸区域关键点索引
根据找到人脸换脸的区域,通过68人脸关键点找到换脸区域
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,35)) # 鼻子区域的关键点索引
LEFT_EYE_POINTS = list(range(36,42)) # 左眼区域的关键点索引
RIGHT_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_POINTS + MOUTH_POINTS]
# 将列表转换为元组
POINTStuple = tuple(POINTS)
2.2 获取图像中的人脸关键点
输入图片,返回人脸关键点矩阵
def getkeyoimts(im):
# 使用 dlib 的人脸检测器检测人脸
rects = detector(im, 1)
# 使用 dlib 的预测器获取关键点
shape = pred(im, rects[0])
# 将关键点转换为矩阵形式
s = np.matrix([[p.x, p.y] for p in shape.parts()])
return s
2.3 人脸区域的掩码获取函数
输入图片和图片人脸关键点矩阵,返回图片人脸区域掩码
def getFaceMask(im, keyPoints):
# 创建一个与输入图像大小相同的全零矩阵
im_mask = np.zeros(im.shape[:2], dtype=np.float64)
# 遍历每个关键点区域
for p in POINTS:
# 计算凸包(关键点的凸多边形)
points = cv2.convexHull(keyPoints[p])
# 在掩码上填充凸多边形区域
cv2.fillConvexPoly(im_mask, points, 1)
# 将掩码扩展为三通道
im_mask = np.array([im_mask, im_mask, im_mask]).transpose(1, 2, 0)
# 对掩码进行高斯模糊,使边缘更平滑
im_mask = cv2.GaussianBlur(im_mask, (25, 25), 0)
return im_mask
2.4 仿射变换矩阵
计算仿射变换矩阵,用于将第二张图像对齐到第一张图像。分别输入图片1,2 的人脸关键点位置
def getm(points1, points2):
# 将点转换为浮点型
points1 = points1.astype(np.float64)
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
# 使用奇异值分解(SVD)计算旋转矩阵
u, s, vt = np.linalg.svd(points1.T * points2)
r = (u * vt).T
# 返回仿射变换矩阵
return np.hstack(((s2 / s1) * r, c2.T - (s2 / s1) * r * c1.T))
2.5 图像颜色调整
对图像进行高斯模糊,计算颜色权重并处理无穷大值,调整图像的颜色,使其与另一张图像更匹配,返回调整后的颜色
def normalColor(a, b):
# 定义高斯模糊的核大小
ksize = (111, 111)
# 对图像 a 和 b 进行高斯模糊
aguss = cv2.GaussianBlur(a, ksize, 0)
bguss = cv2.GaussianBlur(b, ksize, 0)
# 计算颜色权重
weight = aguss / bguss
# 处理无穷大值
where_are_inf = np.isinf(weight)
weight[where_are_inf] = 0
# 返回调整后的颜色
return b * weight
3 换脸代码测试
可调整参数a模板图,b换脸图,ksize,
a:
b:
代码展示:
import cv2
import numpy as np
import dlib
JAW_POINTS = list(range(0,17))
RIGHT_BROW_POINTS = list(range(17,22))
LEEFT_BROW_POINTS = list(range(22,27))
NOSE_POINTS = list(range(27,35))
LEFT_EYE_POINTS = list(range(36,42))
RIGHT_EYE_POINTS = list(range(42,48))
MOUTH_POINTS = list(range(48,61))
FACE_POINTS = list(range(17,68))
POINTS = [LEEFT_BROW_POINTS + RIGHT_EYE_POINTS
+ LEFT_EYE_POINTS + RIGHT_BROW_POINTS + NOSE_POINTS + MOUTH_POINTS]
POINTStuple = tuple(POINTS)
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,1)
im = np.array([im,im,im]).transpose(1,2,0)
# ksize
im = cv2.GaussianBlur(im,(25,25),0)
return im
def getm(points1,points2):
points1 = points1.astype(np.float64)
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
return np.hstack(((s2/s1)*r,c2.T -(s2/s1)*r*c1.T))
def getkeyoimts(im):
rects = detector(im,1)
shape = pred(im,rects[0])
s = np.matrix([[p.x, p.y] for p in shape.parts()])
return s
def normalColor (a,b):
ksize = (111,111)
aguss = cv2.GaussianBlur(a,ksize,0)
bguss = cv2.GaussianBlur(b,ksize,0)
weight = aguss/bguss
where_are_inf = np.isinf(weight)
weight[where_are_inf] = 0
return b * weight
a = cv2.imread('lyf1.png')
b = cv2.imread('zly.png')
detector = dlib.get_frontal_face_detector()
pred = dlib.shape_predictor('shape_predictor_68_face_landmarks.dat')
akey = getkeyoimts(a)
bkey = getkeyoimts(b)
b_o = b.copy()
amask = getFaceMask(a,akey)
cv2.imshow('amask',amask)
cv2.waitKey()
bmask = getFaceMask(b, bkey)
cv2.imshow('bmask', bmask)
cv2.waitKey()
m = getm(akey[POINTStuple],bkey[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()
bWarp = cv2.warpAffine(b, m, dsize,
borderMode=cv2.BORDER_TRANSPARENT,
flags=cv2.WARP_INVERSE_MAP)
cv2.imshow("bWarp", bWarp)
cv2.waitKey()
bcolor =normalColor(a,bWarp)
cv2.imshow( "bcolor",bcolor)
cv2.waitKey()
out = a * (1.0 - mask) + bcolor * mask
cv2.imshow( "a" ,a)
cv2.imshow("b",b_o)
cv2.imshow("out",out/255)
cv2.imwrite("out/lyf.png",out)
cv2.waitKey(0)
cv2.destroyAllWindows()
运行结果:
热门推荐
黄山旅游指南:发现中国第一奇山的独特魅力
妇女小组案例丨跳出“母职”焦虑,助全职妈妈找到更多人生可能
学科知识与跨学科学习的整合
宁波的美食有哪些?
摄影摄像技术专业主要学什么?专业课程有哪些?
肺腺癌晚期已经扩散一般能活多久
30岁无背景的普通人考上乡镇公务员,这辈子能达到副处级吗?
3M树脂补牙材料型号详解:从经济型到高端款,这些型号有何区别?
奥伯斯佯谬:夜空为什么是黑的?隐藏着怎样的秘密?
感冒灵颗粒可以和复方氨酚烷胺片一起吃吗
“一日不见,如隔三秋”:成语背后的文化密码
除甲醛的正确姿势:闷放+通风才是科学除醛的硬道理
Git代码提交规范详解:feat、fix、chore等常见类型的意义
如何确定自己是否符合社保一次性补缴条件?2025社保补缴
冬天洗澡注意事项:5个关键点+8种不宜洗澡的情况
孕妇可以吃小番茄圣女果吗?孕妇吃圣女果的诸多好处你知道嘛?
出现这6个症状,可能是白内障!医生提醒:8个预防是关键!
金针奖:452位提名者的音乐理想,记录107首时代金曲的文化密码
法官说法|看房后找别的中介租房,是否构成“跳单”?
氖灯功率介绍
什么是韦尼克脑病?维生素B1缺乏导致的急性脑病
广东一周动态:多地人事调整,经济数据亮眼
“柑橘采摘机器人”、“数字农地一张图”.....这些成果让农业更“聪明”
混合信号PCB接地设计的基本准则
关于抚养的常见法律问题
控制和防止电感器中的磁芯饱和
25000次循环寿命!北大科学家固态电池新突破,实现分钟级快充
彩钢瓦价格是多少?一文详解彩钢瓦选购费用全攻略
喝完咖啡后服用布洛芬?医生提醒:这个时间间隔很重要
清香木的养殖方法与注意事项