anyantudre's picture
moved from training repo to inference
caa56d6
from enum import Enum
from functools import reduce
import cv2
import numpy as np
from scipy.ndimage import binary_dilation
from .DeepFakeMask import Mask
def dist(a, b):
x1, y1 = a
x2, y2 = b
return np.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2)
# return np.linalg.norm(a-b)
def get_five_key(landmarks_68):
# get the five key points by using the landmarks
leye_center = (landmarks_68[36] + landmarks_68[39]) * 0.5
reye_center = (landmarks_68[42] + landmarks_68[45]) * 0.5
nose = landmarks_68[33]
lmouth = landmarks_68[48]
rmouth = landmarks_68[54]
leye_left = landmarks_68[36]
leye_right = landmarks_68[39]
reye_left = landmarks_68[42]
reye_right = landmarks_68[45]
out = [
tuple(x.astype("int32"))
for x in [
leye_center,
reye_center,
nose,
lmouth,
rmouth,
leye_left,
leye_right,
reye_left,
reye_right,
]
]
return out
def remove_eyes(image, landmarks, opt):
##l: left eye; r: right eye, b: both eye
if opt == "l":
(x1, y1), (x2, y2) = landmarks[5:7]
elif opt == "r":
(x1, y1), (x2, y2) = landmarks[7:9]
elif opt == "b":
(x1, y1), (x2, y2) = landmarks[:2]
else:
print("wrong region")
mask = np.zeros_like(image[..., 0])
line = cv2.line(mask, (x1, y1), (x2, y2), color=(1), thickness=2)
w = dist((x1, y1), (x2, y2))
dilation = int(w // 4)
if opt != "b":
dilation *= 4
line = binary_dilation(line, iterations=dilation)
return line
def remove_nose(image, landmarks):
(x1, y1), (x2, y2) = landmarks[:2]
x3, y3 = landmarks[2]
mask = np.zeros_like(image[..., 0])
x4 = int((x1 + x2) / 2)
y4 = int((y1 + y2) / 2)
line = cv2.line(mask, (x3, y3), (x4, y4), color=(1), thickness=2)
w = dist((x1, y1), (x2, y2))
dilation = int(w // 4)
line = binary_dilation(line, iterations=dilation)
return line
def remove_mouth(image, landmarks):
(x1, y1), (x2, y2) = landmarks[3:5]
mask = np.zeros_like(image[..., 0])
line = cv2.line(mask, (x1, y1), (x2, y2), color=(1), thickness=2)
w = dist((x1, y1), (x2, y2))
dilation = int(w // 3)
line = binary_dilation(line, iterations=dilation)
return line
class SladdRegion(Enum):
left_eye = 0
right_eye = 1
nose = 2
mouth = 3
# composition
both_eyes = left_eye + right_eye # 4
class SladdMasking(Mask):
# [0, 1, 2, 3, (0, 1), (0, 2), (1, 2), (2, 3), (0, 1, 2), (0, 1, 2, 3)]
# left-eye, right-eye, nose, mouth, ...
ALL_REGIONS = [
SladdRegion.left_eye,
SladdRegion.right_eye,
SladdRegion.nose,
SladdRegion.mouth,
]
REGIONS = [
[SladdRegion.left_eye],
[SladdRegion.right_eye],
[SladdRegion.nose],
[SladdRegion.mouth],
[SladdRegion.left_eye, SladdRegion.right_eye],
[SladdRegion.left_eye, SladdRegion.nose],
[SladdRegion.right_eye, SladdRegion.nose],
[SladdRegion.nose, SladdRegion.mouth],
[SladdRegion.left_eye, SladdRegion.right_eye, SladdRegion.nose],
ALL_REGIONS,
]
def init(self, compose: bool = False, single: bool = True, **kwargs):
# super().__init__(**kwargs)
self.compose = compose
if compose:
self.regions = SladdMasking.REGIONS
else:
self.regions = [reg for reg in SladdMasking.REGIONS if len(reg) == 1]
if single:
self.regions = [self.ALL_REGIONS]
@property
def total(self) -> int:
return len(self.regions)
@staticmethod
def parse(img, reg, landmarks) -> np.ndarray:
five_key = get_five_key(landmarks)
if reg is SladdRegion.left_eye:
mask = remove_eyes(img, five_key, "l")
elif reg is SladdRegion.right_eye:
mask = remove_eyes(img, five_key, "r")
elif reg is SladdRegion.nose:
mask = remove_nose(img, five_key)
elif reg is SladdRegion.mouth:
mask = remove_mouth(img, five_key)
else:
raise ValueError("Invalid region")
# elif reg == SladdRegion4:
# mask = remove_eyes(img, five_key, "b")
return mask
def build_mask(self) -> np.ndarray:
self.init()
h, w = self.face.shape[:2]
# print(len(self.regions))
regs = [self.regions[0][self.idx]]
# if isinstance(reg, int):
# mask = parse(img, reg, landmarks)
masks = [SladdMasking.parse(self.face, reg, self.landmarks) for reg in regs]
mask = reduce(np.maximum, masks)
mask = mask.reshape([mask.shape[0],mask.shape[1], 1])
return mask