- 效果如下:
- 完整代码:
import cv2
import dlib
import numpy as np
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
""" 求出b脸仿射变换到a脸的变换矩阵M,此处用到的算法难以理解,大家可直接跳过 """
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 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图相同 """
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
a = cv2.imread("dlrb_3.jpg")
b = cv2.imread("zly.jpg")
detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat")
aKeyPoints = getKeyPoints(a)
bKeyPoints = getKeyPoints(b)
bOriginal = b.copy()
aMask = getFaceMask(a, aKeyPoints)
cv2.imshow('aMask', aMask)
cv2.waitKey()
bMask = getFaceMask(b, bKeyPoints)
cv2.imshow('bMask', bMask)
cv2.waitKey()
"""求出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()
"""获取脸部最大值(两个脸模板香加)"""
mask = np.max([aMask, bMaskWarp], axis=0)
cv2.imshow("mask", mask)
cv2.waitKey()
""" 使用仿射矩阵M,将b映射到a """
bWrap = cv2.warpAffine(b, M, dsize, borderMode=cv2.BORDER_TRANSPARENT, flags=cv2.WARP_INVERSE_MAP)
cv2.imshow("bWrap", bWrap)
cv2.waitKey()
""" 求b图片的仿射到图片a的颜色值,b的颜色值改为a的颜色 """
bcolor = normalColor(a, bWrap)
cv2.imshow("bcolor", bcolor)
cv2.waitKey()
""" ===========step8:换脸(mask区域用bcolor,非mask区城用a)============= """
out = a * (1.0 - mask) + bcolor * mask
cv2.imshow("a", a)
cv2.imshow("b", bOriginal)
cv2.imshow("out", out/255)
cv2.waitKey()
cv2.destroyAllWindows()