File size: 3,930 Bytes
0b756df
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
import cv2
import numpy as np
from insightface.utils import face_align
from face_parsing.swap import swap_regions
from utils import add_logo_to_image

swap_options_list = [
    "All face",
    "Age less than",
    "Age greater than",
    "All Male",
    "All Female",
    "Specific Face",
]


def swap_face(whole_img, target_face, source_face, models):
    inswapper = models.get("swap")
    face_enhancer = models.get("enhance", None)
    face_parser = models.get("face_parser", None)
    fe_enable = models.get("enhance_sett", False)

    bgr_fake, M = inswapper.get(whole_img, target_face, source_face, paste_back=False)
    image_size = 128 if not fe_enable else 512
    aimg, _ = face_align.norm_crop2(whole_img, target_face.kps, image_size=image_size)

    if face_parser is not None:
        fp_enable, mi, me, mb = models.get("face_parser_sett")
        if fp_enable:
            bgr_fake, parsed_mask = swap_regions(
                bgr_fake, aimg, face_parser, includes=mi, excludes=me, blur_size=mb
            )

    if fe_enable:
        _, bgr_fake, _ = face_enhancer.enhance(
            bgr_fake, paste_back=True, has_aligned=True
        )
        bgr_fake = bgr_fake[0]
        M /= 0.25

    IM = cv2.invertAffineTransform(M)

    img_white = np.full((aimg.shape[0], aimg.shape[1]), 255, dtype=np.float32)
    bgr_fake = cv2.warpAffine(
        bgr_fake, IM, (whole_img.shape[1], whole_img.shape[0]), borderValue=0.0
    )
    img_white = cv2.warpAffine(
        img_white, IM, (whole_img.shape[1], whole_img.shape[0]), borderValue=0.0
    )
    img_white[img_white > 20] = 255
    img_mask = img_white
    mask_h_inds, mask_w_inds = np.where(img_mask == 255)
    mask_h = np.max(mask_h_inds) - np.min(mask_h_inds)
    mask_w = np.max(mask_w_inds) - np.min(mask_w_inds)
    mask_size = int(np.sqrt(mask_h * mask_w))

    k = max(mask_size // 10, 10)
    img_mask = cv2.erode(img_mask, np.ones((k, k), np.uint8), iterations=1)

    k = max(mask_size // 20, 5)
    kernel_size = (k, k)
    blur_size = tuple(2 * i + 1 for i in kernel_size)
    img_mask = cv2.GaussianBlur(img_mask, blur_size, 0) / 255

    img_mask = np.reshape(img_mask, [img_mask.shape[0], img_mask.shape[1], 1])
    fake_merged = img_mask * bgr_fake + (1 - img_mask) * whole_img.astype(np.float32)
    fake_merged = add_logo_to_image(fake_merged.astype("uint8"))
    return fake_merged


def swap_face_with_condition(
    whole_img, target_faces, source_face, condition, age, models
):
    swapped = whole_img.copy()

    for target_face in target_faces:
        if condition == "All face":
            swapped = swap_face(swapped, target_face, source_face, models)
        elif condition == "Age less than" and target_face["age"] < age:
            swapped = swap_face(swapped, target_face, source_face, models)
        elif condition == "Age greater than" and target_face["age"] > age:
            swapped = swap_face(swapped, target_face, source_face, models)
        elif condition == "All Male" and target_face["gender"] == 1:
            swapped = swap_face(swapped, target_face, source_face, models)
        elif condition == "All Female" and target_face["gender"] == 0:
            swapped = swap_face(swapped, target_face, source_face, models)

    return swapped


def swap_specific(source_specifics, target_faces, whole_img, models, threshold=0.6):
    swapped = whole_img.copy()

    for source_face, specific_face in source_specifics:
        specific_embed = specific_face["embedding"]
        specific_embed /= np.linalg.norm(specific_embed)

        for target_face in target_faces:
            target_embed = target_face["embedding"]
            target_embed /= np.linalg.norm(target_embed)
            cosine_distance = 1 - np.dot(specific_embed, target_embed)
            if cosine_distance > threshold:
                continue
            swapped = swap_face(swapped, target_face, source_face, models)

    return swapped