import numpy as np
import time
import os
import cv2
import kmodel
from utils import transparentOverlay

os.environ['KMP_DUPLICATE_LIB_OK']='True'

# 加载预先训练好的模型
# my_model = kmodel.load_trained_model('yuan_model_mac')
# 加载自己训练好的模型(测试时取消下面行的注释)
my_model = kmodel.load_trained_model('my_model')

# 创建人脸检测器
face_cascade = cv2.CascadeClassifier('cascades/haarcascade_frontalface_default.xml')

# 加载摄像头
camera = cv2.VideoCapture(0)

# 加载一个太阳眼镜图像
sunglasses = cv2.imread('sunglass.png', cv2.IMREAD_UNCHANGED)

# 死循环
while True:
    time.sleep(0.1)

    # 从摄像头获取一张图像
    (_, frame) = camera.read()
    frame = cv2.flip(frame, 1)
    frame2 = np.copy(frame)
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

    # 检测所有的人脸
    faces = face_cascade.detectMultiScale(gray, 1.25, 6)

    # 对每一个检测到的人脸
    for (x, y, w, h) in faces:

        # 只包含人脸的图像
        gray_face = gray[y:y+h, x:x+w]
        color_face = frame[y:y+h, x:x+w]

        # 将人脸图像的值 normalize 在 [0, 1] 之间
        gray_normalized = gray_face / 255

        # 缩放灰度图人脸到 96x96 匹配网络的输入
        original_shape = gray_face.shape # A Copy for future reference
        face_resized = cv2.resize(gray_normalized, (96, 96), interpolation = cv2.INTER_AREA)
        face_resized = face_resized.reshape(1, 96, 96, 1)

        # 预测关键点坐标
        keypoints = my_model.predict(face_resized)

        # 将关键点坐标的值从 [-1, 1] 之间转换为 [0, 96] 之间
        keypoints = keypoints * 48 + 48

        # 缩放彩色图人脸到 96x96 匹配关键点
        face_resized_color = cv2.resize(color_face, (96, 96), interpolation = cv2.INTER_AREA)
        face_resized_color2 = np.copy(face_resized_color)

        # 将网络输出的30个值配对为15个tuple对
        points = []
        for i, co in enumerate(keypoints[0][0::2]):
            points.append((co, keypoints[0][1::2][i]))

        # 按照关键点的 left_eyebrow_outer_end_x[7], right_eyebrow_outer_end_x[9]确定眼镜的宽度
        sunglass_width = int((points[7][0]-points[9][0])*1.1)

        # 按照关键点的 nose_tip_y[10], right_eyebrow_inner_end_y[8]确定眼镜的高度
        sunglass_height = int((points[10][1]-points[8][1])/1.1)
        sunglass_resized = cv2.resize(sunglasses, (sunglass_width, sunglass_height), interpolation = cv2.INTER_CUBIC)
        face_resized_color = transparentOverlay(face_resized_color, sunglass_resized , pos=(int(points[9][0]),int(points[9][1])), scale = 1)

        # 将覆盖了眼镜的 face_resized_color 图像转为摄像头捕捉到的原始图像中的大小
        frame[y:y+h, x:x+w] = cv2.resize(face_resized_color, original_shape, interpolation = cv2.INTER_CUBIC)

        # 在人脸图像中显示关键点坐标
        for keypoint in points:
            cv2.circle(face_resized_color2, keypoint, 1, (0,255,0), 1)

        frame2[y:y+h, x:x+w] = cv2.resize(face_resized_color2, original_shape, interpolation = cv2.INTER_CUBIC)

        # 显示加了眼镜的图像
        cv2.imshow("With Glass", frame)
        # 显示添加了关键点的图像
        cv2.imshow("With Keypoints", frame2)

    # 当 'q' 键被点击, 退出循环
    if cv2.waitKey(1) & 0xFF == ord("q"):
        break

# 释放摄像头, 关闭窗口
camera.release()
cv2.destroyAllWindows()