效果如下: 完整代码:
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( )