效果如下: 完整代码:
import cv2
import dlib
import numpy as npJAW_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 * weighta = 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( )