从仿射变换到人脸融合:基于OpenCV和Dlib的图像处理实践
在图像处理领域,仿射变换和人脸融合是两个非常有趣且实用的技术。仿射变换可以用于图像的几何变换,而人脸融合则可以创造出令人惊叹的视觉效果。本文将通过两个具体的代码示例,详细介绍如何使用Python、OpenCV和Dlib库实现这些功能。我们将从简单的仿射变换开始,逐步深入到复杂的人脸融合技术。
一、仿射变换:基础入门
(一)仿射变换简介
仿射变换是一种二维坐标到二维坐标的线性变换,它保持了图像的直线性和平行性。通过仿射变换,可以对图像进行平移、旋转、缩放和倾斜等操作。在计算机视觉中,仿射变换常用于图像校正、目标匹配等场景。
(二)代码实现
以下代码展示了如何使用OpenCV实现仿射变换:
import cv2
import numpy as np# 读取图像
img = cv2.imread("zjl.png")
height, width = img.shape[:2]# 定义源点和目标点
mat_src = np.float32([[0, 0], [0, height-1], [width-1, 0]])
mat_dst = np.float32([[0, 0], [100, height-100], [width-100, 100]])# 计算仿射变换矩阵
M = cv2.getAffineTransform(mat_src, mat_dst)# 应用仿射变换
dst = cv2.warpAffine(img, M, (width, height))# 显示结果
imgs = np.hstack([img, dst])
cv2.namedWindow('imgs', cv2.WINDOW_NORMAL)
cv2.imshow("imgs", imgs)
cv2.waitKey(0)
cv2.destroyAllWindows()
(三)代码解析
- 读取图像:使用
cv2.imread
函数读取图像文件。 - 定义源点和目标点:
mat_src
和mat_dst
分别定义了仿射变换的源点和目标点。这些点决定了图像如何被变换。 - 计算仿射变换矩阵:通过
cv2.getAffineTransform
函数计算源点和目标点之间的仿射变换矩阵。 - 应用仿射变换:使用
cv2.warpAffine
函数将仿射变换矩阵应用到图像上,生成变换后的图像。 - 显示结果:将原始图像和变换后的图像并排放置,使用
cv2.imshow
显示结果。
(四)运行结果
运行上述代码后,你将看到原始图像和经过仿射变换后的图像并排显示。仿射变换后的图像可能会出现平移、旋转或缩放的效果,具体取决于你定义的源点和目标点。
二、人脸融合:进阶应用
(一)人脸融合简介
人脸融合是一种将两张人脸图像的特征进行融合的技术,生成一张新的图像,同时保留两张人脸的主要特征。这种技术在娱乐、影视特效等领域有着广泛的应用。实现人脸融合的关键在于精确地检测人脸的关键点,并进行合理的图像变换和融合。
(二)代码实现
以下代码展示了如何使用OpenCV和Dlib实现人脸融合:
import cv2
import numpy as np
import dlib# 定义人脸关键点集合
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))
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_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, color=1)im = np.array([im, im, im]).transpose(1, 2, 0)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 -= c1points2 -= c2s1 = np.std(points1)s2 = np.std(points2)points1 /= s1points2 /= s2U, S, Vt = np.linalg.svd(points1.T * points2)R = (U * Vt).Treturn np.hstack(((s2 / s1) * R, c2.T - (s2 / s1) * R * c1.T))# 获取人脸关键点
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# 修改图像颜色
def normalColor(a, b):ksize = (111, 111)aGauss = cv2.GaussianBlur(a, ksize, 0)bGauss = cv2.GaussianBlur(b, ksize, 0)weight = aGauss / bGausswhere_are_inf = np.isinf(weight)weight[where_are_inf] = 0return b * weight# 加载图像和模型
a = cv2.imread("zjl2.png")
b = cv2.imread("zxc2.png")
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)
bMask = getFacemask(b, bKeyPoints)# 计算仿射变换矩阵并应用
M = getM(aKeyPoints[POINTStupLe], bKeyPoints[POINTStupLe])
dsize = a.shape[:2][::-1]
bMaskWarp = cv2.warpAffine(bMask, M, dsize, borderMode=cv2.BORDER_TRANSPARENT, flags=cv2.WARP_INVERSE_MAP)
bWarp = cv2.warpAffine(b, M, dsize, borderMode=cv2.BORDER_TRANSPARENT, flags=cv2.WARP_INVERSE_MAP)# 颜色校正和融合
mask = np.max([aMask, bMaskWarp], axis=0)
bcolor = normalColor(a, bWarp)
out = a * (1.0 - mask) + bcolor * mask# 显示结果
cv2.imshow("a", a)
cv2.imshow("b", b)
cv2.imshow("out", out / 255)
cv2.waitKey()
cv2.destroyAllWindows()
(三)代码解析
-
人脸关键点检测:
使用Dlib的人脸检测器和关键点检测器,从图像中提取人脸的关键点。这些关键点将用于后续的图像变换和融合。detector = dlib.get_frontal_face_detector() predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat")
-
人脸掩膜生成:
定义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)im = np.array([im, im, im]).transpose(1, 2, 0)im = cv2.GaussianBlur(im, (25, 25), 0)return im
-
计算仿射变换矩阵:
定义getM
函数,计算从一张人脸到另一张人脸的仿射变换矩阵。
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 -= c1points2 -= c2s1 = np.std(points1)s2 = np.std(points2)points1 /= s1points2 /= s2U, S, Vt = np.linalg.svd(points1.T * points2)R = (U * Vt).Treturn np.hstack(((s2 / s1) * R, c2.T - (s2 / s1) * R * c1.T))
-
应用仿射变换:
使用OpenCV的cv2.warpAffine
函数对人脸图像进行仿射变换。M = getM(aKeyPoints[POINTStupLe], bKeyPoints[POINTStupLe]) dsize = a.shape[:2][::-1] bMaskWarp = cv2.warpAffine(bMask, M, dsize, borderMode=cv2.BORDER_TRANSPARENT, flags=cv2.WARP_INVERSE_MAP) bWarp = cv2.warpAffine(b, M, dsize, borderMode=cv2.BORDER_TRANSPARENT, flags=cv2.WARP_INVERSE_MAP)
-
颜色校正和融合:
定义normalColor
函数,将一张图像的颜色调整为与另一张图像相似。然后将两张图像进行融合。def normalColor(a, b):ksize = (111, 111)aGauss = cv2.GaussianBlur(a, ksize, 0)bGauss = cv2.GaussianBlur(b, ksize, 0)weight = aGauss / bGausswhere_are_inf = np.isinf(weight)weight[where_are_inf] = 0return b * weight
-
显示结果:
使用OpenCV的cv2.imshow
函数展示融合后的图像。cv2.imshow("a", a) cv2.imshow("b", b) cv2.imshow("out", out / 255) cv2.waitKey() cv2.destroyAllWindows()
(四)运行结果
运行上述代码后,你将看到两张原始人脸图像和融合后的图像。融合后的图像将同时保留两张人脸的主要特征,看起来更加自然。
三、总结与展望
通过本文的介绍,我们从简单的仿射变换逐步深入到复杂的人脸融合技术。仿射变换是图像处理中的基础操作,而人脸融合则涉及到人脸检测、关键点提取、图像变换和融合等多个步骤。希望本文能够帮助读者更好地理解这些技术,并激发大家在实际项目中进一步探索的灵感。
未来,随着深度学习技术的发展,人脸融合技术将更加智能化和高效化。例如,可以使用深度学习模型来生成更加自然和逼真的融合效果,或者实现实时的人脸融合功能。此外,还可以将人脸融合技术应用于更多领域,如虚拟现实、增强现实等,为用户带来更加丰富的视觉体验。