minchul commited on
Commit
d435aa8
·
verified ·
1 Parent(s): 6d3414e

Upload directory

Browse files
aligners/differentiable_face_aligner/aligner_helper.py ADDED
@@ -0,0 +1,97 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import numpy as np
3
+ import cv2
4
+ from skimage import transform as trans
5
+ import cv2
6
+
7
+
8
+ def split_network_output(align_out):
9
+ anchor_bbox_pred, anchor_cls_pred, anchor_ldmk_pred, merged, _ = align_out
10
+ bbox, cls, ldmk = torch.split(merged, [4, 2, 10], dim=1)
11
+ return ldmk, bbox, cls
12
+
13
+
14
+ def get_cv2_affine_from_landmark(ldmks, reference_ldmk, image_width, image_height, ):
15
+ assert ldmks.ndim == 2 # batchdim
16
+ assert ldmks.shape[1] == 10
17
+ assert isinstance(ldmks, torch.Tensor)
18
+
19
+ assert reference_ldmk.ndim == 2
20
+ assert reference_ldmk.shape[0] == 5
21
+ assert reference_ldmk.shape[1] == 2
22
+ assert isinstance(reference_ldmk, np.ndarray)
23
+
24
+ to_img_size = np.array([[[image_width, image_height]]])
25
+ ldmks = ldmks.view(ldmks.shape[0], 5, 2).detach().cpu().numpy()
26
+ ldmks = ldmks * to_img_size
27
+ transforms = []
28
+ for ldmk in ldmks:
29
+ tform = trans.SimilarityTransform()
30
+ tform.estimate(ldmk, reference_ldmk)
31
+ M = tform.params[0:2, :]
32
+ transforms.append(M)
33
+ transforms = np.stack(transforms, axis=0)
34
+ return transforms
35
+
36
+
37
+ def cv2_param_to_torch_theta(cv2_tfms, image_width, image_height, output_width, output_height):
38
+ # https://github.com/wuneng/WarpAffine2GridSample
39
+ """4.Affine Transformation Matrix to theta"""
40
+ assert cv2_tfms.ndim == 3 # N, 2, 3
41
+ assert cv2_tfms.shape[1] == 2
42
+ assert cv2_tfms.shape[2] == 3
43
+
44
+ srcs = np.array([[0, 0], [0, 1], [1, 1]], dtype=np.float32)
45
+ srcs = np.expand_dims(srcs, axis=0).repeat(cv2_tfms.shape[0], axis=0)
46
+ dsts = np.matmul(srcs, cv2_tfms[:, :, :2].transpose(0, 2, 1)) + cv2_tfms[:, :, 2:3].transpose(0, 2, 1)
47
+
48
+ # normalize to [-1, 1]
49
+ srcs = srcs / np.array([[[image_width, image_height]]]) * 2 - 1
50
+ dsts = dsts / np.array([[[output_width, output_height]]]) * 2 - 1
51
+
52
+ thetas = []
53
+ for src, dst in zip(srcs, dsts):
54
+ theta = trans.estimate_transform("affine", src=dst, dst=src).params[:2]
55
+ thetas.append(theta)
56
+ thetas = np.stack(thetas, axis=0)
57
+ thetas = torch.from_numpy(thetas).float()
58
+ return thetas
59
+
60
+
61
+ def adjust_ldmks(ldmks, thetas):
62
+ inv_thetas = inv_matrix(thetas).to(ldmks.device).float()
63
+ _ldmks = torch.cat([ldmks, torch.ones((ldmks.shape[0], 5, 1)).to(ldmks.device)], dim=2)
64
+ ldmk_aligned = (((_ldmks) * 2 - 1) @ inv_thetas.permute(0,2,1)) / 2 + 0.5
65
+ return ldmk_aligned
66
+
67
+
68
+ def inv_matrix(theta):
69
+ # torch batched version
70
+ assert theta.ndim == 3
71
+ a, b, t1 = theta[:, 0,0], theta[:, 0,1], theta[:, 0,2]
72
+ c, d, t2 = theta[:, 1,0], theta[:, 1,1], theta[:, 1,2]
73
+ det = a * d - b * c
74
+ inv_det = 1.0 / det
75
+ inv_mat = torch.stack([
76
+ torch.stack([d * inv_det, -b * inv_det, (b * t2 - d * t1) * inv_det], dim=1),
77
+ torch.stack([-c * inv_det, a * inv_det, (c * t1 - a * t2) * inv_det], dim=1)
78
+ ], dim=1)
79
+ return inv_mat
80
+
81
+ def reference_landmark():
82
+ return np.array([[38.29459953, 51.69630051],
83
+ [73.53179932, 51.50139999],
84
+ [56.02519989, 71.73660278],
85
+ [41.54930115, 92.3655014],
86
+ [70.72990036, 92.20410156]])
87
+
88
+
89
+ def draw_ldmk(img, ldmk):
90
+ if ldmk is None:
91
+ return img
92
+ colors = [(0, 255, 0), (255, 0, 0), (0, 0, 255), (255, 255, 0), (0, 255, 255), (255, 0, 255)]
93
+ img = img.copy()
94
+ for i in range(5):
95
+ color = colors[i]
96
+ cv2.circle(img, (int(ldmk[i*2] * img.shape[1]), int(ldmk[i*2+1] * img.shape[0])), 1, color, 4)
97
+ return img