1、安装环境:

# 文本附件百度云盘有安装包请自行下载
pip install dlib-19.23.0-cp39-cp39-win_amd64.whl
pip install opencv-python

2、代码:

import cv2
import dlib
import numpy as np
# 图像叠加
def img_overlayer(img,img_fg,pos_fg,bk_fg):
    
    #把前景图变换为灰度
    fg_gray = cv2.cvtColor(img_fg,cv2.COLOR_BGR2GRAY)
    h_gf,w_fg = np.shape(fg_gray)
    
    # 获取前景图的mask 有图部分为 1 背景部分为 0 
    if bk_fg == 255:
        mask_fg = fg_gray<250
    elif bk_fg == 0:
        mask_fg = fg_gray>5
    
    mask_fg = mask_fg[:,:,np.newaxis]
    not_mask_fg = ~mask_fg
    
    # 截取背景图
    bk = img[pos_fg[1]:pos_fg[1]+h_gf,pos_fg[0]:pos_fg[0]+w_fg]
    
    img_overlayer = bk*not_mask_fg + img_fg*mask_fg
    img[pos_fg[1]:pos_fg[1]+h_gf,pos_fg[0]:pos_fg[0]+w_fg] = img_overlayer
    return img
    


def add_cnter_eye(img,center_eye,parts):
    # 计算左眼的区域
    pos_left = min(parts[37].x,parts[41].x)-3
    pos_right = max(parts[38].x,parts[40].x)+3
    scale = np.abs((pos_right-pos_left))/center_eye.shape[1]

    img_center_eye_overlayer = cv2.resize(center_eye,(int(center_eye.shape[0]*scale),int(center_eye.shape[1]*scale)))
    img = img_overlayer(img,img_center_eye_overlayer,(pos_left,parts[37].y-3),bk_fg=255)
    
    # 计算右眼的区域
    pos_left = min(parts[43].x,parts[47].x)-3
    pos_right = max(parts[44].x,parts[46].x)+3
    scale = np.abs((pos_right-pos_left))/center_eye.shape[1]

    img_center_eye_overlayer = cv2.resize(center_eye,(int(center_eye.shape[0]*scale),int(center_eye.shape[1]*scale)))
    img = img_overlayer(img,img_center_eye_overlayer,(pos_left,parts[43].y-3),bk_fg=255)
    return img
    
def add_cartoon_eye(img,img_left_eye,img_right_eye,parts):   
    # 计算左眼的区域
    pos_left = parts[36].x-3
    pos_up = min(parts[37].y,parts[38].y)-3
    pos_right = parts[39].x+3
    pos_down = max(parts[40].y,parts[41].y)+3
    
    img_left_eye_overlayer = cv2.resize(img_left_eye,(pos_right-pos_left,pos_down-pos_up))
    img = img_overlayer(img,img_left_eye_overlayer,(pos_left,pos_up),bk_fg=0)
    # 计算右眼的区域
    pos_left = parts[42].x-3
    pos_up = min(parts[43].y,parts[44].y)-3
    pos_right = parts[45].x+3
    pos_down = max(parts[46].y,parts[47].y)+3
    
    img_right_eye_overlayer = cv2.resize(img_right_eye,(pos_right-pos_left,pos_down-pos_up))
    
    img = img_overlayer(img,img_right_eye_overlayer,(pos_left,pos_up),bk_fg=0)
    return img
    
def add_glasses(img,img_glasses,parts):
    
    # 获取眼镜图像大小
    w_glass = np.shape(img_glasses)[1]
    h_glass = np.shape(img_glasses)[0]
    
    # 计算缩放尺度
    scale = np.abs(parts[36].x-5 -parts[45].x-5)/w_glass
    
    # 眼镜图像缩放
    resize_glasses = cv2.resize(img_glasses,(int(w_glass*scale),int(h_glass*scale)))

    # 计算眼镜图像的起始位置(左上坐标)
    pos_glass = (parts[36].x-5,parts[36].y-int(h_glass*scale/2.0))
    
    # 图像叠加
    img_out = img_overlayer(img,resize_glasses,pos_glass,bk_fg=255)
    return img_out
    
def add_hat(img,img_hat,parts):
    

    # 获取帽子图像大小
    w_hat = np.shape(img_hat)[1]
    h_hat = np.shape(img_hat)[0]
    
    # 计算脸的宽度
    face_w = int(parts[16].x - parts[0].x)

    # 计算缩放尺度
    scale = face_w/w_hat
    
    # 帽子图像缩放
    resize_hat = cv2.resize(img_hat,(int(w_hat*scale*(1.2)),int(h_hat*scale*(1.2))))
    
    # 计算帽子图像的起始位置(左上坐标)
    pos_hat = (parts[0].x-int(face_w*0.1), max(0,int(parts[19].y-resize_hat.shape[0])))
    
    # 图像叠加
    img_out = img_overlayer(img,resize_hat,pos_hat,bk_fg=255)
    return img_out

    
if __name__ == "__main__":
    # 创建人脸检测器
    det_face = dlib.get_frontal_face_detector()

    # 加载标志点检测器
    det_landmark = dlib.shape_predictor("shape_predictor_68_face_landmarks_GTX.dat")  # 68
   
    # 打开摄像头
    cap = cv2.VideoCapture(0)

    t_left_eye = cv2.imread("left-eye.bmp")
    t_right_eye = cv2.imread("right-eye.bmp")
    center_eye = cv2.imread("center-eye.bmp")
    img_glasses = cv2.imread("glasses.bmp")
    img_hat1 = cv2.imread("hat1.bmp")
    img_hat2 = cv2.imread("hat2.bmp")
    
    # 显示脸部框与 68个关键点
    flag_base = 1
    
    # 1:眼睛 2:卡通眼  3:中心眼
    flag_eyes = 0
    
    # 1: 帽子1  2:帽子2
    flag_hat = 0
    
    while True:
        # 读取一帧图像
        success, img = cap.read()

        # 转换为灰度
        gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

        # 检测人脸区域
        face_rects = det_face(gray, 0)

        for ret in face_rects:
            # 标志点检测
            landmarks = det_landmark(gray, ret)
            
            parts = landmarks.parts()
            
            if flag_base==1:
                # 画出人脸区域
                cv2.rectangle(img, (ret.left(),ret.top()), (ret.right(),ret.bottom()), (255, 0, ), 3)
                # 画出 关键点
                for part in landmarks.parts():
                    pt = (part.x,part.y)
                    cv2.circle(img, pt, 2, (0,0,255),-1)

            
            if flag_eyes ==1:
                img = add_glasses(img,img_glasses,parts)
            elif flag_eyes ==2:
                img = add_cartoon_eye(img,t_left_eye,t_right_eye,parts)
            elif flag_eyes ==3:
                img = add_cnter_eye(img,center_eye,parts)
                
            if flag_hat ==1:
                img = add_hat(img,img_hat1,parts)
            elif flag_hat ==2:
                img= add_hat(img,img_hat2,parts)
            
            
            
        # 显示检测结果
        cv2.imshow("Face",img)

        key = cv2.waitKey(1) & 0xFF
        
        # 按q退出
        if key == ord('q'):
            break 
        
        #  b 切换基本显示
        if key == ord('b'):
            key  = 0
            if flag_base==1:
                flag_base =0
            else:
                flag_base = 1
        
        
        # 按e切换眼睛的显示方式
        if key == ord('e'):
            key  = 0
            if flag_eyes==3:
                flag_eyes = 0
            else:
                flag_eyes = flag_eyes+1
                flag_base = 0
        
        
        # 按h 切换帽子
        if key == ord('h'):
            key  = 0
            if flag_hat==2:
                flag_hat = 0
            else:
                flag_hat = flag_hat+1
                
        
    
    cap.release()