# coding:utf-8 
'''
created on 2018/9/27

@author:Dxq
'''
from PIL import Image
import os
import scipy.io as scio
import numpy as np
import cv2
import functools
import time
import urllib.request
from common.utils import get_baseInfo_tx

skin_triangles = scio.loadmat("resource/mat/triangle_matrix_skin_nose.mat")['triangle']
triangles = scio.loadmat("resource/mat/triangle_matrix.mat")['triangle']


def time_cal(func):
    @functools.wraps(func)
    def wrapper(*args, **kw):
        t1 = time.time()
        r = func(*args, **kw)  # 先让函数运行一次,防止直接输出，将其赋值给一个变量
        if time.time() - t1 > 0.001:
            print('函数%s执行的时间为：%f' % (func.__name__, time.time() - t1))
        return r

    return wrapper


def get_landmark_dict(file_path, status='local'):
    landmark_dict = get_baseInfo_tx(file_path, status)
    # if landmark_dict['roll'] != 0:
    #     Image.open(file_path).rotate(-landmark_dict['roll']).save(file_path)
    #     landmark_dict = get_baseInfo_tx(file_path)
    return landmark_dict


def get_temp_landmark_dict(file_path):
    mat_file = file_path.split(".")[0] + '.mat'
    if os.path.exists(mat_file):
        landmark_dict = scio.loadmat(mat_file)
    else:
        landmark_dict = get_baseInfo_tx(file_path)
        scio.savemat(mat_file, landmark_dict)
    return landmark_dict


def check_right_eye(points):
    fixed_points = points.copy()
    if points[0][0] < points[1][0]:
        fixed_points[0] = points[4]
        fixed_points[1] = points[3]
        fixed_points[2] = points[2]
        fixed_points[3] = points[1]
        fixed_points[4] = points[0]
        fixed_points[5] = points[7]
        fixed_points[6] = points[6]
        fixed_points[7] = points[5]
    return fixed_points


def check_left_eye(points):
    fixed_points = points.copy()
    if points[0][0] > points[1][0]:
        fixed_points[0] = points[4]
        fixed_points[1] = points[5]
        fixed_points[2] = points[6]
        fixed_points[3] = points[7]
        fixed_points[4] = points[0]
        fixed_points[5] = points[1]
        fixed_points[6] = points[2]
        fixed_points[7] = points[3]
    return fixed_points


def check_face_profile(points):
    # fixed_points = points[16:37]
    # v_x = 2 * points[10][0]
    #
    # left_p = [[v_x - p[0], p[1]] for p in fixed_points[11:][::-1]]
    # right_p = [[v_x - p[0], p[1]] for p in fixed_points[:10][::-1]]
    # merge_p = np.vstack((left_p, fixed_points[10]))
    # merge_p = np.vstack((merge_p, right_p))
    # fixed_points = (fixed_points + merge_p) / 2
    #
    # m1 = get_similarity_matrix(fixed_points, merge_p,True)
    # fixed_points2 = landmark_trans_by_m(points, m1)
    # print(m1)
    return points


def get_points(landmark_dict):
    '''
    :param landmark_dict:
    :return:左眼0-7 左眉8-15 脸16-36 鼻子37-49 嘴50-71 右眉72-79 右眼80-87 88-89左右眼球
    '''

    def _get_eye_center(points):
        eye_center = [(points[0] + points[4])[0] // 2, (points[2] + points[6])[1] // 2]
        return eye_center

    p0 = np.vstack([check_left_eye(landmark_dict['left_eye']), landmark_dict['left_eyebrow']])
    p1 = np.vstack([p0, landmark_dict['face_profile']])
    p2 = np.vstack([p1, landmark_dict['nose']])
    p3 = np.vstack([p2, landmark_dict['mouth']])
    p4 = np.vstack([p3, landmark_dict['right_eyebrow']])
    p5 = np.vstack([p4, check_right_eye(landmark_dict['right_eye'])])
    p6 = np.vstack([p5, [_get_eye_center(landmark_dict['left_eye']), _get_eye_center(landmark_dict['right_eye'])]])
    p6 = check_face_profile(p6)
    return p6, [tuple(p) for p in p6]


def get_similarity_matrix(orange_points, tree_points, fullAffine=False):
    '''
    dst->src 的变换矩阵
    :param dst_points: 目标特征点
    :param src_points: 底图特征点
    :return: matrix
    '''
    m = cv2.estimateRigidTransform(np.array(orange_points), np.array(tree_points), fullAffine)
    if m is None:
        print('异常')
        m = cv2.getAffineTransform(np.float32(orange_points[:3]), np.float32(tree_points[:3]))
    return m


def save_img(img_array, save_name, ifsave):
    if ifsave:
        cv2.imwrite(save_name, img_array)


def landmark_trans_by_m(points, m):
    p1 = np.transpose(points, [1, 0])
    p2 = np.pad(p1, ((0, 1), (0, 0)), 'constant', constant_values=(1, 1))
    p3 = np.matmul(m, p2)
    p4 = np.transpose(p3, [1, 0])
    return p4


def get_measure_triangle():
    return [list(t.astype(np.int32)) for t in triangles]


def get_measure_triangle_skin():
    return [list(t.astype(np.int32)) for t in skin_triangles]


def affine_transform(src, src_tri, dst_tri, size):
    warp_mat = cv2.getAffineTransform(np.float32(src_tri), np.float32(dst_tri))
    # warp_mat = cv2.estimateRigidTransform(np.array(src_tri), np.array(dst_tri), True)
    dst = cv2.warpAffine(src, warp_mat, (size[0], size[1]),
                         None,
                         flags=cv2.INTER_LINEAR,
                         borderMode=cv2.BORDER_REFLECT_101)

    return dst


def morph_triangle(src, dst, img, face_mask, t_src, t_dst, t, base_alpha, step=0):
    # t_src, t_dst, t
    # 分别为特征点的三角形坐标

    r1 = cv2.boundingRect(np.float32([t_src]))
    r2 = cv2.boundingRect(np.float32([t_dst]))
    r = cv2.boundingRect(np.float32([t]))
    # 获取三角形的凸包正方形 格式 xmin,ymin,wid,height

    t1_rect = []
    t2_rect = []
    t_rect = []

    for i in range(0, 3):
        t_rect.append(((t[i][0] - r[0]), (t[i][1] - r[1])))
        t1_rect.append(((t_src[i][0] - r1[0]), (t_src[i][1] - r1[1])))
        t2_rect.append(((t_dst[i][0] - r2[0]), (t_dst[i][1] - r2[1])))
    # 将坐标转换为相对正方形左上角坐标

    mask = np.zeros((r[3], r[2], 3), dtype=np.float32)
    # 包含剖分三角形的正方形区域
    cv2.fillConvexPoly(mask, np.int32(t_rect), (1., 1., 1.))
    # 填充剖分三角形

    img1_rect = src[r1[1]:r1[1] + r1[3], r1[0]:r1[0] + r1[2]]
    img2_rect = dst[r2[1]:r2[1] + r2[3], r2[0]:r2[0] + r2[2]]
    size = (r[2], r[3])

    warp_img_src = affine_transform(img1_rect, t1_rect, t_rect, size)
    warp_img_dst = affine_transform(img2_rect, t2_rect, t_rect, size)
    # alpha = 0.5 if step > 49 else alpha
    if step < 16:
        # print('眼睛')
        alpha = min(1.25 * base_alpha, 1.0)
    elif step < 28:
        # print('鼻子')
        alpha = min(1.0 * base_alpha, 1.0)
    elif step < 40:
        # print('眉毛')
        alpha = min(1.13 * base_alpha, 1.0)
    elif step < 50:
        # print('眉毛')
        alpha = min(1.25 * base_alpha, 1.0)
    else:
        alpha = min(1.0 * base_alpha, 1.0)
    img_rect = (1.0 - alpha) * warp_img_src + alpha * warp_img_dst
    img[r[1]:r[1] + r[3], r[0]:r[0] + r[2]] = img[r[1]:r[1] + r[3], r[0]:r[0] + r[2]] * (1 - mask) + img_rect * mask

    face_mask[r[1]:r[1] + r[3], r[0]:r[0] + r[2]] = face_mask[r[1]:r[1] + r[3], r[0]:r[0] + r[2]] * (
            1 - mask[:, :, 0]) + 255 * mask[:, :, 0]
    return img, face_mask


def affine_triangle(src, dst, t_src, t_dst):
    r1 = cv2.boundingRect(np.float32([t_src]))
    r2 = cv2.boundingRect(np.float32([t_dst]))
    t1_rect = []
    t2_rect = []
    t2_rect_int = []

    for i in range(0, 3):
        t1_rect.append((t_src[i][0] - r1[0], t_src[i][1] - r1[1]))
        t2_rect.append((t_dst[i][0] - r2[0], t_dst[i][1] - r2[1]))
        t2_rect_int.append((t_dst[i][0] - r2[0], t_dst[i][1] - r2[1]))

    mask = np.zeros((r2[3], r2[2], 3), dtype=np.float32)
    cv2.fillConvexPoly(mask, np.int32(t2_rect_int), (1.0, 1.0, 1.0))
    img1_rect = src[r1[1]:r1[1] + r1[3], r1[0]:r1[0] + r1[2]]
    size = (r2[2], r2[3])

    img2_rect = affine_transform(img1_rect, t1_rect, t2_rect, size)
    img2_rect = img2_rect * mask
    # (1620, 280, 3)
    # (800, 0, 820, 1620)
    dst[r2[1]:r2[1] + r2[3], r2[0]:r2[0] + r2[2]] = dst[r2[1]:r2[1] + r2[3], r2[0]:r2[0] + r2[2]] * (
            (1.0, 1.0, 1.0) - mask)

    dst[r2[1]:r2[1] + r2[3], r2[0]:r2[0] + r2[2]] = dst[r2[1]:r2[1] + r2[3], r2[0]:r2[0] + r2[2]] + img2_rect


def morph_img(tree_img, tree_points, orange_img, orange_points, alpha):
    def _get_morph_points(_tree_points, _orange_points, alphas):
        '''
        :param src_points:
        :param dst_points:
        :param alphas: eye_alpha, face_alpha, other_alpha  分别为dst 占据的比例
        :return:
        '''
        eye_alpha, face_alpha, other_alpha = alphas
        _morph_points = (1 - other_alpha) * _tree_points + other_alpha * _orange_points
        other_alpha2 = .5
        _mask_points = (1 - other_alpha2) * _tree_points + other_alpha2 * _orange_points

        eye_points = (1 - eye_alpha) * _tree_points + eye_alpha * _orange_points
        face_points = (1 - face_alpha) * _tree_points + face_alpha * _orange_points

        m1 = get_similarity_matrix(_morph_points[0:8] - _morph_points[88], eye_points[0:8] - eye_points[88])
        _morph_points[0:8] = landmark_trans_by_m(_morph_points[0:8] - _morph_points[88], m1) + _morph_points[88]
        m2 = get_similarity_matrix(_morph_points[80:88] - _morph_points[89], eye_points[80:88] - eye_points[89])
        _morph_points[80:88] = landmark_trans_by_m(_morph_points[80:88] - _morph_points[89], m2) + _morph_points[89]

        m3 = get_similarity_matrix(_morph_points[16:37] - _morph_points[26], face_points[16:37] - face_points[26])
        _morph_points[16:37] = landmark_trans_by_m(_morph_points[16:37] - _morph_points[26], m3) + _morph_points[26]

        return _mask_points, _morph_points,

    tree_img = tree_img.astype(np.float32)
    orange_img = orange_img.astype(np.float32)

    res_img = np.zeros(tree_img.shape, dtype=tree_img.dtype)
    _face_mask = np.zeros(orange_img.shape[:2], dtype=np.uint8)

    mask_points, morph_points_ = _get_morph_points(tree_points, orange_points, alpha[:3])
    # morph_points = dst_points
    # src_point 格式[(),()]
    # 根据88点获取149个三角剖分对应的88点的index
    dt = get_measure_triangle()[47:]
    for i in range(0, len(dt)):
        t1 = []
        t2 = []
        t = []
        for j in range(0, 3):
            t1.append(tree_points[dt[i][j]])
            t2.append(orange_points[dt[i][j]])
            t.append(mask_points[dt[i][j]])

        _, face_maskk = morph_triangle(tree_img, orange_img, res_img, _face_mask, t1, t2, t, alpha[3], i)

    return res_img, morph_points_, face_maskk


def tran_src(tree_img, tree_points, orange_points):
    """
    应用三角仿射转换将模板图人脸轮廓仿射成目标图像人脸轮廓
    :param src_img:
    :param src_points:
    :param dst_points:
    :param face_area:
    :return:
    """
    h, w, c = tree_img.shape
    h -= 1
    w -= 1
    mask_area = cv2.boundingRect(np.float32([orange_points]))
    start_x = max(.9 * mask_area[0], 1)
    start_y = max(.9 * mask_area[1], 1)
    end_x = min(start_x + 1.2 * mask_area[2], w - 10)
    end_y = min(start_y + 1.2 * mask_area[3], h - 10)

    sum_x = start_x + end_x
    sum_y = start_y + end_y
    bound_area = np.int32([
        [start_x, start_y], [end_x, start_y], [end_x, end_y], [start_x, end_y],
        [0, 0], [w, 0], [w, h], [0, h],
        [0.5 * sum_x, start_y], [end_x, 0.5 * sum_y], [0.5 * sum_x, end_y], [start_x, 0.5 * sum_y]
    ])

    tree_list = np.vstack([tree_points, bound_area])
    orange_list = np.vstack([orange_points, bound_area])
    res_img = np.zeros(tree_img.shape, dtype=tree_img.dtype)
    dt = get_measure_triangle()
    for i in range(0, len(dt)):
        t_src = []
        t_dst = []

        for j in range(0, 3):
            t_src.append(tree_list[dt[i][j]])
            t_dst.append(orange_list[dt[i][j]])

        affine_triangle(tree_img, res_img, t_src, t_dst)

    return res_img


def merge_img(orange_img, tree_img, face_mask, orange_points, mat_rate=.88):
    r = cv2.boundingRect(np.float32([orange_points]))

    center = (r[0] + int(r[2] / 2), r[1] + int(int(r[3] / 2)))

    mat = cv2.getRotationMatrix2D(center, 0, mat_rate)
    face_mask = cv2.warpAffine(face_mask, mat, (face_mask.shape[1], face_mask.shape[0]))
    # face_mask = cv2.blur(face_mask, (3, 3))
    # face_mask = cv2.GaussianBlur(face_mask, (27, 27), 1)
    # kernel = np.ones((60, 60), np.uint8)
    # face_mask = cv2.dilate(face_mask, kernel)  # 膨胀
    # face_mask = cv2.erode(face_mask, kernel)  # 腐蚀
    # face_mask = cv2.medianBlur(face_mask, 19)
    res = cv2.seamlessClone(np.uint8(orange_img), np.uint8(tree_img), face_mask, center, 1)
    return res


def toushi_img(orange_img, orange_points, tree_points, yaw=0):
    if abs(yaw) <= 5:
        rate = 0.1
    else:
        rate = min(abs(yaw), 12) / 12
    _tree = rate * tree_points + (1 - rate) * orange_points
    pts1 = np.float32([orange_points[17], orange_points[18], orange_points[34], orange_points[35]])
    pts2 = np.float32([_tree[17], _tree[18], _tree[34], _tree[35]])
    M = cv2.getPerspectiveTransform(pts1, pts2)
    p2 = np.pad(orange_points, ((0, 0), (0, 1)), 'constant', constant_values=(1, 1))
    new_data1 = np.matmul(p2, M.T)
    new_data1 = new_data1 / np.repeat(new_data1[:, 2:3], 3, axis=1)
    new_orange_points = new_data1[:, :2]
    new_orange_img = cv2.warpPerspective(orange_img, M, (2 * orange_img.shape[1], 2 * orange_img.shape[0]))
    return new_orange_img, new_orange_points


def resize_img(img_array, fusion_face_wid):
    img_array = img_array[..., [2, 1, 0, 3]]
    img = Image.fromarray(np.uint8(img_array), "RGBA")
    wid, hei = img.size
    std_face_wid = 257
    fixed_loc = [500, 500]
    # rate = std_face_wid / fusion_face_wid
    # 可优化更合理的对比指标
    rate = max(0.93, std_face_wid / fusion_face_wid)
    img = img.resize([int(rate * wid), int(rate * hei)])
    wid2, hei2 = img.size
    diff_x = abs(int((rate - 1) * fixed_loc[0]))
    diff_y = abs(int((rate - 1) * fixed_loc[1]))
    if wid2 <= wid:
        rr = ((diff_y, wid - wid2 - diff_y), (diff_x, wid - wid2 - diff_x), (0, 0))
        image = np.pad(np.array(img), rr, mode='constant', constant_values=(0, 0))
        img = Image.fromarray(np.uint8(image))
    else:
        img = img.crop([diff_x, diff_y, diff_x + wid, diff_y + hei])

    return img


def get_data_analysis(skin_ori):
    skin_ori_flatten = skin_ori.reshape([-1, 1])
    skin_ori_index = np.flatnonzero(skin_ori_flatten != 0)
    skin_ori_value = skin_ori_flatten[skin_ori_index]

    skin_ori_value_max = np.max(skin_ori_value)
    skin_ori_value_std = np.std(skin_ori_value)
    skin_ori_value_min = np.min(skin_ori_value)
    skin_ori_value_mean = np.mean(skin_ori_value)

    return skin_ori_value_mean, skin_ori_value_std, skin_ori_value_max, skin_ori_value_min


def make_mask(face_mask, t):
    #  t
    # 分别为特征点的三角形坐标
    r = cv2.boundingRect(np.float32([t]))
    # 获取三角形的凸包正方形 格式 xmin,ymin,wid,height

    t_rect = []
    for i in range(0, 3):
        t_rect.append(((t[i][0] - r[0]), (t[i][1] - r[1])))

    # 将坐标转换为相对正方形左上角坐标
    mask = np.zeros((r[3], r[2]), dtype=np.float32)
    # 包含剖分三角形的正方形区域
    cv2.fillConvexPoly(mask, np.int32(t_rect), 1)
    # 填充剖分三角形

    face_mask[r[1]:r[1] + r[3], r[0]:r[0] + r[2]] = face_mask[r[1]:r[1] + r[3], r[0]:r[0] + r[2]] * (
            1 - mask) + 1 * mask
    return face_mask


def get_data_analysis(skin_ori):
    skin_ori_flatten = skin_ori.reshape([-1, 1])
    skin_ori_index = np.flatnonzero(skin_ori_flatten != 0)
    skin_ori_value = skin_ori_flatten[skin_ori_index]

    skin_ori_value_max = np.max(skin_ori_value)
    skin_ori_value_std = np.std(skin_ori_value)
    skin_ori_value_min = np.min(skin_ori_value)
    skin_ori_value_mean = np.mean(skin_ori_value)

    return skin_ori_value_mean, skin_ori_value_std, skin_ori_value_max, skin_ori_value_min


def smooth_light(orange_img, arr_point_tree):
    # 肤色区域
    dt = get_measure_triangle_skin()[47:]
    face_mask2 = np.zeros(orange_img.shape[:2], dtype=np.uint8)
    for i in range(0, len(dt)):
        t = []
        for j in range(0, 3):
            t.append(arr_point_tree[dt[i][j]])

        face_mask = make_mask(face_mask2, t)
    face_mask = np.array(face_mask, np.float32)
    orange_img_hsv = cv2.cvtColor(orange_img, cv2.COLOR_BGR2HSV)

    s = np.array(orange_img_hsv[:, :, 1], np.float32)
    v = np.array(orange_img_hsv[:, :, 2], np.float32)

    s_skin_ori = s * face_mask
    v_skin_ori = v * face_mask

    s_skin_ori_value_mean, s_skin_ori_value_std, s_skin_ori_value_max, s_skin_ori_value_min = get_data_analysis(
        s_skin_ori)

    v_skin_ori_value_mean, v_skin_ori_value_std, v_skin_ori_value_max, v_skin_ori_value_min = get_data_analysis(
        v_skin_ori)

    # 去除不均匀
    # res_img_h = np.clip((h - h_skin_ori_value_mean) / h_skin_ori_value_std * 20 + 50, 16, 230)
    res_img_s = np.clip((s - s_skin_ori_value_mean) / s_skin_ori_value_std * 20 + .95 * s_skin_ori_value_mean, 16, 250)
    res_img_v = np.clip(
        (v - v_skin_ori_value_mean) / v_skin_ori_value_std * .8 * v_skin_ori_value_std + .95 * v_skin_ori_value_mean,
        16, 250)

    # 解决太均匀
    # res_img_s = np.clip(1.1 * res_img_s, 18, 250)
    # res_img_v = np.clip(1.1 * res_img_v, 18, 250)

    # 赋值回原图
    orange_img_hsv[:, :, 1] = res_img_s
    orange_img_hsv[:, :, 2] = res_img_v

    orange_img_hsv2 = cv2.cvtColor(orange_img_hsv, cv2.COLOR_HSV2BGR)

    # 组合成最终图片
    orange_img_hsv = orange_img * (1 - face_mask[:, :, None]) + orange_img_hsv2 * face_mask[:, :, None]
    return np.uint8(orange_img_hsv)


def preprocess(landmark_dict):
    for key in ['left_eye', 'left_eyebrow', 'face_profile', 'nose', 'mouth', 'right_eyebrow', 'right_eye']:
        points = landmark_dict[key]
        num = len(points)
        data = np.zeros([num, 2])
        data[:, 0] = [p[0] for p in points]
        data[:, 1] = [p[1] for p in points]
        landmark_dict[key] = data
    return landmark_dict


def cv2ImreadUrlImg(url):
    resp = urllib.request.urlopen(url)
    image = np.asarray(bytearray(resp.read()), dtype="uint8")
    image = cv2.imdecode(image, cv2.IMREAD_COLOR)
    return image


def make_sure(path):
    fdir = path[:path.rfind('/')]
    if not os.path.exists(fdir):
        os.makedirs(fdir)
    return True


def fusion(orange_path, orange_dict, temp_id='temp1'):
    t0 = time.time()
    orange_dict = preprocess(orange_dict)
    # orange_dict = get_landmark_dict(orange_path)
    file_name = os.path.basename(orange_path).split('.')[0]
    tree_file = "resource/{}/ori.jpg".format(temp_id)
    landmark_dict_tree = get_temp_landmark_dict(tree_file)
    landmark_dict_tree = preprocess(landmark_dict_tree)

    arr_point_tree, list_point_tree = get_points(landmark_dict_tree)
    tree_left_eye_center = arr_point_tree[88]
    tree_right_eye_center = arr_point_tree[89]
    tree = cv2.imread(tree_file, cv2.IMREAD_COLOR)
    tree_center = (tree_right_eye_center + tree_left_eye_center) / 2
    tree_eye_dis = (tree_right_eye_center - tree_left_eye_center)[0]
    # ---------------------------------------------------------#
    arr_point_orange, list_point_orange = get_points(orange_dict)

    # orange = cv2ImreadUrlImg(orange_path)
    orange = cv2.imread(orange_path, cv2.IMREAD_COLOR)
    orange = smooth_light(orange, arr_point_orange)
    t1 = time.time()
    print('1：：：', t1 - t0)

    # orange, arr_point_orange = toushi_img(orange, arr_point_orange, arr_point_tree, yaw=orange_dict['yaw'])
    # arr_point_orange 90*2
    orange_left_eye_center = arr_point_orange[88]
    orange_right_eye_center = arr_point_orange[89]
    orange_center = (orange_right_eye_center + orange_left_eye_center) / 2
    orange_eye_dis = (orange_right_eye_center - orange_left_eye_center)[0]
    # ---------------------------------------------------------#
    # 矫正orange位置与tree对齐
    orange2tree_matrix = get_similarity_matrix(
        orange_points=[orange_left_eye_center, orange_right_eye_center,
                       [orange_center[0], orange_center[1] + orange_eye_dis],
                       [orange_center[0], orange_center[1] - orange_eye_dis]],
        tree_points=[tree_left_eye_center, tree_right_eye_center,
                     [tree_center[0], tree_center[1] + tree_eye_dis],
                     [tree_center[0], tree_center[1] - tree_eye_dis]], fullAffine=False)

    # 矫正后的orange图
    orange_trans = cv2.warpAffine(orange, orange2tree_matrix, (tree.shape[1], tree.shape[0]))

    # 矫正后的orange特征点
    arr_point_orange_trans = landmark_trans_by_m(arr_point_orange, orange2tree_matrix)
    # 将orange目标区域扣取1出来，进行比例重组
    orange_mask_trans, morph_points, orange_mask = morph_img(tree, arr_point_tree, orange_trans, arr_point_orange_trans,
                                                             alpha=[.2, .2, .2, .85])  # 眼睛，脸，other
    # 将Tree进行形变（主要是脸型轮廓）
    tree_trans = tran_src(tree, arr_point_tree, morph_points)
    rgb_img = merge_img(orange_mask_trans, np.uint8(tree_trans), orange_mask, morph_points, .88)
    t2 = time.time()
    print('2：：：', t2 - t1)

    # await gen.sleep(1)
    local_path = "userImg/download/{}/{}_res.png".format(file_name, temp_id)
    local_thum_path = "userImg/download/{}/{}_thum.png".format(file_name, temp_id)
    make_sure(local_path)
    res_img = Image.fromarray(np.uint8(rgb_img[..., [2, 1, 0]]))

    res_img.save(local_path)

    res_img.thumbnail((500, 500))
    res_img.save(local_thum_path)

    t3 = time.time()
    print('3：：：', t3 - t2)
    return local_path, local_thum_path

# coding:utf-8 
'''
created on 2018/9/27

@author:Dxq
'''
from PIL import Image
import os
import scipy.io as scio
import numpy as np
import cv2
import functools
import time
import urllib.request
from common.utils import get_baseInfo_tx

skin_triangles = scio.loadmat("resource/mat/triangle_matrix_skin_nose.mat")['triangle']
triangles = scio.loadmat("resource/mat/triangle_matrix.mat")['triangle']


def time_cal(func):
    @functools.wraps(func)
    def wrapper(*args, **kw):
        t1 = time.time()
        r = func(*args, **kw)  # 先让函数运行一次,防止直接输出，将其赋值给一个变量
        if time.time() - t1 > 0.001:
            print('函数%s执行的时间为：%f' % (func.__name__, time.time() - t1))
        return r

    return wrapper


def get_landmark_dict(file_path, status='local'):
    landmark_dict = get_baseInfo_tx(file_path, status)
    # if landmark_dict['roll'] != 0:
    #     Image.open(file_path).rotate(-landmark_dict['roll']).save(file_path)
    #     landmark_dict = get_baseInfo_tx(file_path)
    return landmark_dict


def get_temp_landmark_dict(file_path):
    mat_file = file_path.split(".")[0] + '.mat'
    if os.path.exists(mat_file):
        landmark_dict = scio.loadmat(mat_file)
    else:
        landmark_dict = get_baseInfo_tx(file_path)
        scio.savemat(mat_file, landmark_dict)
    return landmark_dict


def check_right_eye(points):
    fixed_points = points.copy()
    if points[0][0] < points[1][0]:
        fixed_points[0] = points[4]
        fixed_points[1] = points[3]
        fixed_points[2] = points[2]
        fixed_points[3] = points[1]
        fixed_points[4] = points[0]
        fixed_points[5] = points[7]
        fixed_points[6] = points[6]
        fixed_points[7] = points[5]
    return fixed_points


def check_left_eye(points):
    fixed_points = points.copy()
    if points[0][0] > points[1][0]:
        fixed_points[0] = points[4]
        fixed_points[1] = points[5]
        fixed_points[2] = points[6]
        fixed_points[3] = points[7]
        fixed_points[4] = points[0]
        fixed_points[5] = points[1]
        fixed_points[6] = points[2]
        fixed_points[7] = points[3]
    return fixed_points


def check_face_profile(points):
    # fixed_points = points[16:37]
    # v_x = 2 * points[10][0]
    #
    # left_p = [[v_x - p[0], p[1]] for p in fixed_points[11:][::-1]]
    # right_p = [[v_x - p[0], p[1]] for p in fixed_points[:10][::-1]]
    # merge_p = np.vstack((left_p, fixed_points[10]))
    # merge_p = np.vstack((merge_p, right_p))
    # fixed_points = (fixed_points + merge_p) / 2
    #
    # m1 = get_similarity_matrix(fixed_points, merge_p,True)
    # fixed_points2 = landmark_trans_by_m(points, m1)
    # print(m1)
    return points


def get_points(landmark_dict):
    '''
    :param landmark_dict:
    :return:左眼0-7 左眉8-15 脸16-36 鼻子37-49 嘴50-71 右眉72-79 右眼80-87 88-89左右眼球
    '''

    def _get_eye_center(points):
        eye_center = [(points[0] + points[4])[0] // 2, (points[2] + points[6])[1] // 2]
        return eye_center

    p0 = np.vstack([check_left_eye(landmark_dict['left_eye']), landmark_dict['left_eyebrow']])
    p1 = np.vstack([p0, landmark_dict['face_profile']])
    p2 = np.vstack([p1, landmark_dict['nose']])
    p3 = np.vstack([p2, landmark_dict['mouth']])
    p4 = np.vstack([p3, landmark_dict['right_eyebrow']])
    p5 = np.vstack([p4, check_right_eye(landmark_dict['right_eye'])])
    p6 = np.vstack([p5, [_get_eye_center(landmark_dict['left_eye']), _get_eye_center(landmark_dict['right_eye'])]])
    p6 = check_face_profile(p6)
    return p6, [tuple(p) for p in p6]


def get_similarity_matrix(orange_points, tree_points, fullAffine=False):
    '''
    dst->src 的变换矩阵
    :param dst_points: 目标特征点
    :param src_points: 底图特征点
    :return: matrix
    '''
    m = cv2.estimateRigidTransform(np.array(orange_points), np.array(tree_points), fullAffine)
    if m is None:
        print('异常')
        m = cv2.getAffineTransform(np.float32(orange_points[:3]), np.float32(tree_points[:3]))
    return m


def save_img(img_array, save_name, ifsave):
    if ifsave:
        cv2.imwrite(save_name, img_array)


def landmark_trans_by_m(points, m):
    p1 = np.transpose(points, [1, 0])
    p2 = np.pad(p1, ((0, 1), (0, 0)), 'constant', constant_values=(1, 1))
    p3 = np.matmul(m, p2)
    p4 = np.transpose(p3, [1, 0])
    return p4


def get_measure_triangle():
    return [list(t.astype(np.int32)) for t in triangles]


def get_measure_triangle_skin():
    return [list(t.astype(np.int32)) for t in skin_triangles]


def affine_transform(src, src_tri, dst_tri, size):
    warp_mat = cv2.getAffineTransform(np.float32(src_tri), np.float32(dst_tri))
    # warp_mat = cv2.estimateRigidTransform(np.array(src_tri), np.array(dst_tri), True)
    dst = cv2.warpAffine(src, warp_mat, (size[0], size[1]),
                         None,
                         flags=cv2.INTER_LINEAR,
                         borderMode=cv2.BORDER_REFLECT_101)

    return dst


def morph_triangle(src, dst, img, face_mask, t_src, t_dst, t, base_alpha, step=0):
    # t_src, t_dst, t
    # 分别为特征点的三角形坐标

    r1 = cv2.boundingRect(np.float32([t_src]))
    r2 = cv2.boundingRect(np.float32([t_dst]))
    r = cv2.boundingRect(np.float32([t]))
    # 获取三角形的凸包正方形 格式 xmin,ymin,wid,height

    t1_rect = []
    t2_rect = []
    t_rect = []

    for i in range(0, 3):
        t_rect.append(((t[i][0] - r[0]), (t[i][1] - r[1])))
        t1_rect.append(((t_src[i][0] - r1[0]), (t_src[i][1] - r1[1])))
        t2_rect.append(((t_dst[i][0] - r2[0]), (t_dst[i][1] - r2[1])))
    # 将坐标转换为相对正方形左上角坐标

    mask = np.zeros((r[3], r[2], 3), dtype=np.float32)
    # 包含剖分三角形的正方形区域
    cv2.fillConvexPoly(mask, np.int32(t_rect), (1., 1., 1.))
    # 填充剖分三角形

    img1_rect = src[r1[1]:r1[1] + r1[3], r1[0]:r1[0] + r1[2]]
    img2_rect = dst[r2[1]:r2[1] + r2[3], r2[0]:r2[0] + r2[2]]
    size = (r[2], r[3])

    warp_img_src = affine_transform(img1_rect, t1_rect, t_rect, size)
    warp_img_dst = affine_transform(img2_rect, t2_rect, t_rect, size)
    # alpha = 0.5 if step > 49 else alpha
    if step < 16:
        # print('眼睛')
        alpha = min(1.25 * base_alpha, 1.0)
    elif step < 28:
        # print('鼻子')
        alpha = min(1.0 * base_alpha, 1.0)
    elif step < 40:
        # print('眉毛')
        alpha = min(1.13 * base_alpha, 1.0)
    elif step < 50:
        # print('眉毛')
        alpha = min(1.25 * base_alpha, 1.0)
    else:
        alpha = min(1.0 * base_alpha, 1.0)
    img_rect = (1.0 - alpha) * warp_img_src + alpha * warp_img_dst
    img[r[1]:r[1] + r[3], r[0]:r[0] + r[2]] = img[r[1]:r[1] + r[3], r[0]:r[0] + r[2]] * (1 - mask) + img_rect * mask

    face_mask[r[1]:r[1] + r[3], r[0]:r[0] + r[2]] = face_mask[r[1]:r[1] + r[3], r[0]:r[0] + r[2]] * (
            1 - mask[:, :, 0]) + 255 * mask[:, :, 0]
    return img, face_mask


def affine_triangle(src, dst, t_src, t_dst):
    r1 = cv2.boundingRect(np.float32([t_src]))
    r2 = cv2.boundingRect(np.float32([t_dst]))
    t1_rect = []
    t2_rect = []
    t2_rect_int = []

    for i in range(0, 3):
        t1_rect.append((t_src[i][0] - r1[0], t_src[i][1] - r1[1]))
        t2_rect.append((t_dst[i][0] - r2[0], t_dst[i][1] - r2[1]))
        t2_rect_int.append((t_dst[i][0] - r2[0], t_dst[i][1] - r2[1]))

    mask = np.zeros((r2[3], r2[2], 3), dtype=np.float32)
    cv2.fillConvexPoly(mask, np.int32(t2_rect_int), (1.0, 1.0, 1.0))
    img1_rect = src[r1[1]:r1[1] + r1[3], r1[0]:r1[0] + r1[2]]
    size = (r2[2], r2[3])

    img2_rect = affine_transform(img1_rect, t1_rect, t2_rect, size)
    img2_rect = img2_rect * mask
    # (1620, 280, 3)
    # (800, 0, 820, 1620)
    dst[r2[1]:r2[1] + r2[3], r2[0]:r2[0] + r2[2]] = dst[r2[1]:r2[1] + r2[3], r2[0]:r2[0] + r2[2]] * (
            (1.0, 1.0, 1.0) - mask)

    dst[r2[1]:r2[1] + r2[3], r2[0]:r2[0] + r2[2]] = dst[r2[1]:r2[1] + r2[3], r2[0]:r2[0] + r2[2]] + img2_rect


def morph_img(tree_img, tree_points, orange_img, orange_points, alpha):
    def _get_morph_points(_tree_points, _orange_points, alphas):
        '''
        :param src_points:
        :param dst_points:
        :param alphas: eye_alpha, face_alpha, other_alpha  分别为dst 占据的比例
        :return:
        '''
        eye_alpha, face_alpha, other_alpha = alphas
        _morph_points = (1 - other_alpha) * _tree_points + other_alpha * _orange_points
        other_alpha2 = .5
        _mask_points = (1 - other_alpha2) * _tree_points + other_alpha2 * _orange_points

        eye_points = (1 - eye_alpha) * _tree_points + eye_alpha * _orange_points
        face_points = (1 - face_alpha) * _tree_points + face_alpha * _orange_points

        m1 = get_similarity_matrix(_morph_points[0:8] - _morph_points[88], eye_points[0:8] - eye_points[88])
        _morph_points[0:8] = landmark_trans_by_m(_morph_points[0:8] - _morph_points[88], m1) + _morph_points[88]
        m2 = get_similarity_matrix(_morph_points[80:88] - _morph_points[89], eye_points[80:88] - eye_points[89])
        _morph_points[80:88] = landmark_trans_by_m(_morph_points[80:88] - _morph_points[89], m2) + _morph_points[89]

        m3 = get_similarity_matrix(_morph_points[16:37] - _morph_points[26], face_points[16:37] - face_points[26])
        _morph_points[16:37] = landmark_trans_by_m(_morph_points[16:37] - _morph_points[26], m3) + _morph_points[26]

        return _mask_points, _morph_points,

    tree_img = tree_img.astype(np.float32)
    orange_img = orange_img.astype(np.float32)

    res_img = np.zeros(tree_img.shape, dtype=tree_img.dtype)
    _face_mask = np.zeros(orange_img.shape[:2], dtype=np.uint8)

    mask_points, morph_points_ = _get_morph_points(tree_points, orange_points, alpha[:3])
    # morph_points = dst_points
    # src_point 格式[(),()]
    # 根据88点获取149个三角剖分对应的88点的index
    dt = get_measure_triangle()[47:]
    for i in range(0, len(dt)):
        t1 = []
        t2 = []
        t = []
        for j in range(0, 3):
            t1.append(tree_points[dt[i][j]])
            t2.append(orange_points[dt[i][j]])
            t.append(mask_points[dt[i][j]])

        _, face_maskk = morph_triangle(tree_img, orange_img, res_img, _face_mask, t1, t2, t, alpha[3], i)

    return res_img, morph_points_, face_maskk


def tran_src(tree_img, tree_points, orange_points):
    """
    应用三角仿射转换将模板图人脸轮廓仿射成目标图像人脸轮廓
    :param src_img:
    :param src_points:
    :param dst_points:
    :param face_area:
    :return:
    """
    h, w, c = tree_img.shape
    h -= 1
    w -= 1
    mask_area = cv2.boundingRect(np.float32([orange_points]))
    start_x = max(.9 * mask_area[0], 1)
    start_y = max(.9 * mask_area[1], 1)
    end_x = min(start_x + 1.2 * mask_area[2], w - 10)
    end_y = min(start_y + 1.2 * mask_area[3], h - 10)

    sum_x = start_x + end_x
    sum_y = start_y + end_y
    bound_area = np.int32([
        [start_x, start_y], [end_x, start_y], [end_x, end_y], [start_x, end_y],
        [0, 0], [w, 0], [w, h], [0, h],
        [0.5 * sum_x, start_y], [end_x, 0.5 * sum_y], [0.5 * sum_x, end_y], [start_x, 0.5 * sum_y]
    ])

    tree_list = np.vstack([tree_points, bound_area])
    orange_list = np.vstack([orange_points, bound_area])
    res_img = np.zeros(tree_img.shape, dtype=tree_img.dtype)
    dt = get_measure_triangle()
    for i in range(0, len(dt)):
        t_src = []
        t_dst = []

        for j in range(0, 3):
            t_src.append(tree_list[dt[i][j]])
            t_dst.append(orange_list[dt[i][j]])

        affine_triangle(tree_img, res_img, t_src, t_dst)

    return res_img


def merge_img(orange_img, tree_img, face_mask, orange_points, mat_rate=.88):
    r = cv2.boundingRect(np.float32([orange_points]))

    center = (r[0] + int(r[2] / 2), r[1] + int(int(r[3] / 2)))

    mat = cv2.getRotationMatrix2D(center, 0, mat_rate)
    face_mask = cv2.warpAffine(face_mask, mat, (face_mask.shape[1], face_mask.shape[0]))
    # face_mask = cv2.blur(face_mask, (3, 3))
    # face_mask = cv2.GaussianBlur(face_mask, (27, 27), 1)
    # kernel = np.ones((60, 60), np.uint8)
    # face_mask = cv2.dilate(face_mask, kernel)  # 膨胀
    # face_mask = cv2.erode(face_mask, kernel)  # 腐蚀
    # face_mask = cv2.medianBlur(face_mask, 19)
    res = cv2.seamlessClone(np.uint8(orange_img), np.uint8(tree_img), face_mask, center, 1)
    return res


def toushi_img(orange_img, orange_points, tree_points, yaw=0):
    if abs(yaw) <= 5:
        rate = 0.1
    else:
        rate = min(abs(yaw), 12) / 12
    _tree = rate * tree_points + (1 - rate) * orange_points
    pts1 = np.float32([orange_points[17], orange_points[18], orange_points[34], orange_points[35]])
    pts2 = np.float32([_tree[17], _tree[18], _tree[34], _tree[35]])
    M = cv2.getPerspectiveTransform(pts1, pts2)
    p2 = np.pad(orange_points, ((0, 0), (0, 1)), 'constant', constant_values=(1, 1))
    new_data1 = np.matmul(p2, M.T)
    new_data1 = new_data1 / np.repeat(new_data1[:, 2:3], 3, axis=1)
    new_orange_points = new_data1[:, :2]
    new_orange_img = cv2.warpPerspective(orange_img, M, (2 * orange_img.shape[1], 2 * orange_img.shape[0]))
    return new_orange_img, new_orange_points


def resize_img(img_array, fusion_face_wid):
    img_array = img_array[..., [2, 1, 0, 3]]
    img = Image.fromarray(np.uint8(img_array), "RGBA")
    wid, hei = img.size
    std_face_wid = 257
    fixed_loc = [500, 500]
    # rate = std_face_wid / fusion_face_wid
    # 可优化更合理的对比指标
    rate = max(0.93, std_face_wid / fusion_face_wid)
    img = img.resize([int(rate * wid), int(rate * hei)])
    wid2, hei2 = img.size
    diff_x = abs(int((rate - 1) * fixed_loc[0]))
    diff_y = abs(int((rate - 1) * fixed_loc[1]))
    if wid2 <= wid:
        rr = ((diff_y, wid - wid2 - diff_y), (diff_x, wid - wid2 - diff_x), (0, 0))
        image = np.pad(np.array(img), rr, mode='constant', constant_values=(0, 0))
        img = Image.fromarray(np.uint8(image))
    else:
        img = img.crop([diff_x, diff_y, diff_x + wid, diff_y + hei])

    return img


def get_data_analysis(skin_ori):
    skin_ori_flatten = skin_ori.reshape([-1, 1])
    skin_ori_index = np.flatnonzero(skin_ori_flatten != 0)
    skin_ori_value = skin_ori_flatten[skin_ori_index]

    skin_ori_value_max = np.max(skin_ori_value)
    skin_ori_value_std = np.std(skin_ori_value)
    skin_ori_value_min = np.min(skin_ori_value)
    skin_ori_value_mean = np.mean(skin_ori_value)

    return skin_ori_value_mean, skin_ori_value_std, skin_ori_value_max, skin_ori_value_min


def make_mask(face_mask, t):
    #  t
    # 分别为特征点的三角形坐标
    r = cv2.boundingRect(np.float32([t]))
    # 获取三角形的凸包正方形 格式 xmin,ymin,wid,height

    t_rect = []
    for i in range(0, 3):
        t_rect.append(((t[i][0] - r[0]), (t[i][1] - r[1])))

    # 将坐标转换为相对正方形左上角坐标
    mask = np.zeros((r[3], r[2]), dtype=np.float32)
    # 包含剖分三角形的正方形区域
    cv2.fillConvexPoly(mask, np.int32(t_rect), 1)
    # 填充剖分三角形

    face_mask[r[1]:r[1] + r[3], r[0]:r[0] + r[2]] = face_mask[r[1]:r[1] + r[3], r[0]:r[0] + r[2]] * (
            1 - mask) + 1 * mask
    return face_mask


def get_data_analysis(skin_ori):
    skin_ori_flatten = skin_ori.reshape([-1, 1])
    skin_ori_index = np.flatnonzero(skin_ori_flatten != 0)
    skin_ori_value = skin_ori_flatten[skin_ori_index]

    skin_ori_value_max = np.max(skin_ori_value)
    skin_ori_value_std = np.std(skin_ori_value)
    skin_ori_value_min = np.min(skin_ori_value)
    skin_ori_value_mean = np.mean(skin_ori_value)

    return skin_ori_value_mean, skin_ori_value_std, skin_ori_value_max, skin_ori_value_min


def smooth_light(orange_img, arr_point_tree):
    # 肤色区域
    dt = get_measure_triangle_skin()[47:]
    face_mask2 = np.zeros(orange_img.shape[:2], dtype=np.uint8)
    for i in range(0, len(dt)):
        t = []
        for j in range(0, 3):
            t.append(arr_point_tree[dt[i][j]])

        face_mask = make_mask(face_mask2, t)
    face_mask = np.array(face_mask, np.float32)
    orange_img_hsv = cv2.cvtColor(orange_img, cv2.COLOR_BGR2HSV)

    s = np.array(orange_img_hsv[:, :, 1], np.float32)
    v = np.array(orange_img_hsv[:, :, 2], np.float32)

    s_skin_ori = s * face_mask
    v_skin_ori = v * face_mask

    s_skin_ori_value_mean, s_skin_ori_value_std, s_skin_ori_value_max, s_skin_ori_value_min = get_data_analysis(
        s_skin_ori)

    v_skin_ori_value_mean, v_skin_ori_value_std, v_skin_ori_value_max, v_skin_ori_value_min = get_data_analysis(
        v_skin_ori)

    # 去除不均匀
    # res_img_h = np.clip((h - h_skin_ori_value_mean) / h_skin_ori_value_std * 20 + 50, 16, 230)
    res_img_s = np.clip((s - s_skin_ori_value_mean) / s_skin_ori_value_std * 20 + .95 * s_skin_ori_value_mean, 16, 250)
    res_img_v = np.clip(
        (v - v_skin_ori_value_mean) / v_skin_ori_value_std * .8 * v_skin_ori_value_std + .95 * v_skin_ori_value_mean,
        16, 250)

    # 解决太均匀
    # res_img_s = np.clip(1.1 * res_img_s, 18, 250)
    # res_img_v = np.clip(1.1 * res_img_v, 18, 250)

    # 赋值回原图
    orange_img_hsv[:, :, 1] = res_img_s
    orange_img_hsv[:, :, 2] = res_img_v

    orange_img_hsv2 = cv2.cvtColor(orange_img_hsv, cv2.COLOR_HSV2BGR)

    # 组合成最终图片
    orange_img_hsv = orange_img * (1 - face_mask[:, :, None]) + orange_img_hsv2 * face_mask[:, :, None]
    return np.uint8(orange_img_hsv)


def preprocess(landmark_dict):
    for key in ['left_eye', 'left_eyebrow', 'face_profile', 'nose', 'mouth', 'right_eyebrow', 'right_eye']:
        points = landmark_dict[key]
        num = len(points)
        data = np.zeros([num, 2])
        data[:, 0] = [p[0] for p in points]
        data[:, 1] = [p[1] for p in points]
        landmark_dict[key] = data
    return landmark_dict


def cv2ImreadUrlImg(url):
    resp = urllib.request.urlopen(url)
    image = np.asarray(bytearray(resp.read()), dtype="uint8")
    image = cv2.imdecode(image, cv2.IMREAD_COLOR)
    return image


def make_sure(path):
    fdir = path[:path.rfind('/')]
    if not os.path.exists(fdir):
        os.makedirs(fdir)
    return True


def fusion(orange_path, orange_dict, temp_id='temp1'):
    t0 = time.time()
    orange_dict = preprocess(orange_dict)
    # orange_dict = get_landmark_dict(orange_path)
    file_name = os.path.basename(orange_path).split('.')[0]
    tree_file = "resource/{}/ori.jpg".format(temp_id)
    landmark_dict_tree = get_temp_landmark_dict(tree_file)
    landmark_dict_tree = preprocess(landmark_dict_tree)

    arr_point_tree, list_point_tree = get_points(landmark_dict_tree)
    tree_left_eye_center = arr_point_tree[88]
    tree_right_eye_center = arr_point_tree[89]
    tree = cv2.imread(tree_file, cv2.IMREAD_COLOR)
    tree_center = (tree_right_eye_center + tree_left_eye_center) / 2
    tree_eye_dis = (tree_right_eye_center - tree_left_eye_center)[0]
    # ---------------------------------------------------------#
    arr_point_orange, list_point_orange = get_points(orange_dict)

    # orange = cv2ImreadUrlImg(orange_path)
    orange = cv2.imread(orange_path, cv2.IMREAD_COLOR)
    orange = smooth_light(orange, arr_point_orange)
    t1 = time.time()
    print('1：：：', t1 - t0)

    # orange, arr_point_orange = toushi_img(orange, arr_point_orange, arr_point_tree, yaw=orange_dict['yaw'])
    # arr_point_orange 90*2
    orange_left_eye_center = arr_point_orange[88]
    orange_right_eye_center = arr_point_orange[89]
    orange_center = (orange_right_eye_center + orange_left_eye_center) / 2
    orange_eye_dis = (orange_right_eye_center - orange_left_eye_center)[0]
    # ---------------------------------------------------------#
    # 矫正orange位置与tree对齐
    orange2tree_matrix = get_similarity_matrix(
        orange_points=[orange_left_eye_center, orange_right_eye_center,
                       [orange_center[0], orange_center[1] + orange_eye_dis],
                       [orange_center[0], orange_center[1] - orange_eye_dis]],
        tree_points=[tree_left_eye_center, tree_right_eye_center,
                     [tree_center[0], tree_center[1] + tree_eye_dis],
                     [tree_center[0], tree_center[1] - tree_eye_dis]], fullAffine=False)

    # 矫正后的orange图
    orange_trans = cv2.warpAffine(orange, orange2tree_matrix, (tree.shape[1], tree.shape[0]))

    # 矫正后的orange特征点
    arr_point_orange_trans = landmark_trans_by_m(arr_point_orange, orange2tree_matrix)
    # 将orange目标区域扣取1出来，进行比例重组
    orange_mask_trans, morph_points, orange_mask = morph_img(tree, arr_point_tree, orange_trans, arr_point_orange_trans,
                                                             alpha=[.2, .2, .2, .85])  # 眼睛，脸，other
    # 将Tree进行形变（主要是脸型轮廓）
    tree_trans = tran_src(tree, arr_point_tree, morph_points)
    rgb_img = merge_img(orange_mask_trans, np.uint8(tree_trans), orange_mask, morph_points, .88)
    t2 = time.time()
    print('2：：：', t2 - t1)

    # await gen.sleep(1)
    local_path = "userImg/download/{}/{}_res.png".format(file_name, temp_id)
    local_thum_path = "userImg/download/{}/{}_thum.png".format(file_name, temp_id)
    make_sure(local_path)
    res_img = Image.fromarray(np.uint8(rgb_img[..., [2, 1, 0]]))

    res_img.save(local_path)

    res_img.thumbnail((500, 500))
    res_img.save(local_thum_path)

    t3 = time.time()
    print('3：：：', t3 - t2)
    return local_path, local_thum_path

# coding:utf-8 created on 2018/9/27  @author:Dxq # 先让函数运行一次,防止直接输出，将其赋值给一个变量 # if landmark_dict['roll'] != 0: #     Image.open(file_path).rotate(-landmark_dict['roll']).save(file_path) #     landmark_dict = get_baseInfo_tx(file_path) # fixed_points = points[16:37] # v_x = 2 * points[10][0] # # left_p = [[v_x - p[0], p[1]] for p in fixed_points[11:][::-1]] # right_p = [[v_x - p[0], p[1]] for p in fixed_points[:10][::-1]] # merge_p = np.vstack((left_p, fixed_points[10])) # merge_p = np.vstack((merge_p, right_p)) # fixed_points = (fixed_points + merge_p) / 2 # # m1 = get_similarity_matrix(fixed_points, merge_p,True) # fixed_points2 = landmark_trans_by_m(points, m1) # print(m1) :param landmark_dict:     :return:左眼0-7 左眉8-15 脸16-36 鼻子37-49 嘴50-71 右眉72-79 右眼80-87 88-89左右眼球 dst->src 的变换矩阵     :param dst_points: 目标特征点     :param src_points: 底图特征点     :return: matrix # warp_mat = cv2.estimateRigidTransform(np.array(src_tri), np.array(dst_tri), True) # t_src, t_dst, t # 分别为特征点的三角形坐标 # 获取三角形的凸包正方形 格式 xmin,ymin,wid,height # 将坐标转换为相对正方形左上角坐标 # 包含剖分三角形的正方形区域 # 填充剖分三角形 # alpha = 0.5 if step > 49 else alpha # print('眼睛') # print('鼻子') # print('眉毛') # print('眉毛') # (1620, 280, 3) # (800, 0, 820, 1620) :param src_points:         :param dst_points:         :param alphas: eye_alpha, face_alpha, other_alpha  分别为dst 占据的比例         :return: # morph_points = dst_points # src_point 格式[(),()] # 根据88点获取149个三角剖分对应的88点的index 应用三角仿射转换将模板图人脸轮廓仿射成目标图像人脸轮廓     :param src_img:     :param src_points:     :param dst_points:     :param face_area:     :return: # face_mask = cv2.blur(face_mask, (3, 3)) # face_mask = cv2.GaussianBlur(face_mask, (27, 27), 1) # kernel = np.ones((60, 60), np.uint8) # face_mask = cv2.dilate(face_mask, kernel)  # 膨胀 # face_mask = cv2.erode(face_mask, kernel)  # 腐蚀 # face_mask = cv2.medianBlur(face_mask, 19) # rate = std_face_wid / fusion_face_wid # 可优化更合理的对比指标 #  t # 分别为特征点的三角形坐标 # 获取三角形的凸包正方形 格式 xmin,ymin,wid,height # 将坐标转换为相对正方形左上角坐标 # 包含剖分三角形的正方形区域 # 填充剖分三角形 # 肤色区域 # 去除不均匀 # res_img_h = np.clip((h - h_skin_ori_value_mean) / h_skin_ori_value_std * 20 + 50, 16, 230) # 解决太均匀 # res_img_s = np.clip(1.1 * res_img_s, 18, 250) # res_img_v = np.clip(1.1 * res_img_v, 18, 250) # 赋值回原图 # 组合成最终图片 # orange_dict = get_landmark_dict(orange_path) # ---------------------------------------------------------# # orange = cv2ImreadUrlImg(orange_path) # orange, arr_point_orange = toushi_img(orange, arr_point_orange, arr_point_tree, yaw=orange_dict['yaw']) # arr_point_orange 90*2 # ---------------------------------------------------------# # 矫正orange位置与tree对齐 # 矫正后的orange图 # 矫正后的orange特征点 # 将orange目标区域扣取1出来，进行比例重组 # 眼睛，脸，other # 将Tree进行形变（主要是脸型轮廓） # await gen.sleep(1)