攝像頭實時換臉,上網課老師都不認識我了,哈哈

專注的阿熊發表於2022-03-18

# -*- coding: utf-8 -*-

import cv2

import dlib

import numpy as np

detector = dlib.get_frontal_face_detector()  # dlib 的正向人臉檢測器

predictor = dlib.shape_predictor(r'shape_predictor_68_face_landmarks.dat')  # dlib 的人臉形狀檢測器

def get_image_size(image):

     """

     獲取圖片大小(高度 , 寬度)

     :param image: image

     :return: (高度 , 寬度)

     """

     image_size = (image.shape[0], image.shape[1])

     return image_size

def get_face_landmarks(image, face_detector, shape_predictor):

     """

     獲取人臉標誌, 68 個特徵點

     :param image: image

     :param face_detector: dlib.get_frontal_face_detector

     :param shape_predictor: dlib.shape_predictor

     :return: np.array([[],[]]), 68 個特徵點

     """

     dets = face_detector(image, 1)

     shape = shape_predictor(image, dets[0])

     face_landmarks = np.array([[p.x, p.y] for p in shape.parts()])

     return face_landmarks

def get_face_mask(image_size, face_landmarks):

     """

     獲取人臉掩模

     :param image_size: 圖片大小

     :param face_landmarks: 68 個特徵點

     :return: image_mask, 掩模圖片

     """

     mask = np.zeros(image_size, dtype=np.uint8)

     points = np.concatenate([face_landmarks[0:16], face_landmarks[26:17:-1]])

     cv2.fillPoly(img=mask, pts=[points], color=255)

     return mask

def get_affine_image(image1, image2, face_landmarks1, face_landmarks2):

     """

     獲取圖片 1 仿射變換後的圖片

     :param image1: 圖片 1, 要進行仿射變換的圖片

     :param image2: 圖片 2, 外匯跟單gendan5.com 只要用來獲取圖片大小,生成與之大小相同的仿射變換圖片

     :param face_landmarks1: 圖片 1 的人臉特徵點

     :param face_landmarks2: 圖片 2 的人臉特徵點

     :return: 仿射變換後的圖片

     """

     three_points_index = [18, 8, 25]

     M = cv2.getAffineTransform(face_landmarks1[three_points_index].astype(np.float32),

                                face_landmarks2[three_points_index].astype(np.float32))

     dsize = (image2.shape[1], image2.shape[0])

     affine_image = cv2.warpAffine(image1, M, dsize)

     return affine_image.astype(np.uint8)

def get_mask_center_point(image_mask):

     """

     獲取掩模的中心點座標

     :param image_mask: 掩模圖片

     :return: 掩模中心

     """

     image_mask_index = np.argwhere(image_mask > 0)

     miny, minx = np.min(image_mask_index, axis=0)

     maxy, maxx = np.max(image_mask_index, axis=0)

     center_point = ((maxx + minx) // 2, (maxy + miny) // 2)

     return center_point

def get_mask_union(mask1, mask2):

     """

     獲取兩個掩模掩蓋部分的並集

     :param mask1: mask_image, 掩模 1

     :param mask2: mask_image, 掩模 2

     :return: 兩個掩模掩蓋部分的並集

     """

     mask = np.min([mask1, mask2], axis=0)  # 掩蓋部分並集

     mask = ((cv2.blur(mask, (5, 5)) == 255) * 255).astype(np.uint8)  # 縮小掩模大小

     mask = cv2.blur(mask, (3, 3)).astype(np.uint8)  # 模糊掩模

     return mask

def skin_color_adjustment(im1, im2, mask=None):

     """

     膚色調整

     :param im1: 圖片 1

     :param im2: 圖片 2

     :param mask: 人臉 mask. 如果存在,使用人臉部分均值來求膚色變換系數;否則,使用高斯模糊來求膚色變換系數

     :return: 根據圖片 2 的顏色調整的圖片 1

     """

     if mask is None:

         im1_ksize = 55

         im2_ksize = 55

         im1_factor = cv2.GaussianBlur(im1, (im1_ksize, im1_ksize), 0).astype(np.float)

         im2_factor = cv2.GaussianBlur(im2, (im2_ksize, im2_ksize), 0).astype(np.float)

     else:

         im1_face_image = cv2.bitwise_and(im1, im1, mask=mask)

         im2_face_image = cv2.bitwise_and(im2, im2, mask=mask)

         im1_factor = np.mean(im1_face_image, axis=(0, 1))

         im2_factor = np.mean(im2_face_image, axis=(0, 1))

     im1 = np.clip((im1.astype(np.float) * im2_factor / np.clip(im1_factor, 1e-6, None)), 0, 255).astype(np.uint8)

     return im1

def main():

     im1 = cv2.imread('1.png')  # face_image

     im1 = cv2.resize(im1, (600, im1.shape[0] * 600 // im1.shape[1]))

     landmarks1 = get_face_landmarks(im1, detector, predictor)  # 68_face_landmarks

     if landmarks1 is None:

         print('{}: 檢測不到人臉 '.format(image_face_path))

         exit(1)

     im1_size = get_image_size(im1)  # 臉圖大小

     im1_mask = get_face_mask(im1_size, landmarks1)  # 臉圖人臉掩模

     cam = cv2.VideoCapture(0)

     while True:

         ret_val, im2 = cam.read()  # camera_image

         landmarks2 = get_face_landmarks(im2, detector, predictor)  # 68_face_landmarks

         if landmarks2 is not None:

             im2_size = get_image_size(im2)  # 攝像頭圖片大小

             im2_mask = get_face_mask(im2_size, landmarks2)  # 攝像頭圖片人臉掩模

             affine_im1 = get_affine_image(im1, im2, landmarks1, landmarks2)  # im1 (臉圖)仿射變換後的圖片

             affine_im1_mask = get_affine_image(im1_mask, im2, landmarks1, landmarks2)  # im1 (臉圖)仿射變換後的圖片的人臉掩模

             union_mask = get_mask_union(im2_mask, affine_im1_mask)  # 掩模合併

             affine_im1 = skin_color_adjustment(affine_im1, im2, mask=union_mask)  # 膚色調整

             point = get_mask_center_point(affine_im1_mask)  # im1 (臉圖)仿射變換後的圖片的人臉掩模的中心點

             seamless_im = cv2.seamlessClone(affine_im1, im2, mask=union_mask, p=point, flags=cv2.NORMAL_CLONE)  # 進行泊松融合

             cv2.imshow('seamless_im', seamless_im)

         else:

             cv2.imshow('seamless_im', im2)

         if cv2.waitKey(1) == 27:  # Esc 退出

             break

     cv2.destroyAllWindows()

if __name__ == '__main__':

     main()


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69946337/viewspace-2872576/,如需轉載,請註明出處,否則將追究法律責任。

相關文章