leonelhs commited on
Commit
9f66e14
·
1 Parent(s): 8e7e652
Files changed (3) hide show
  1. utils/common.py +44 -0
  2. utils/face_align.py +103 -0
  3. utils/transform.py +116 -0
utils/common.py ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from numpy.linalg import norm as l2norm
2
+
3
+ class Face(dict):
4
+
5
+ def __init__(self, d=None, **kwargs):
6
+ super().__init__()
7
+ if d is None:
8
+ d = {}
9
+ if kwargs:
10
+ d.update(**kwargs)
11
+ for k, v in d.items():
12
+ setattr(self, k, v)
13
+
14
+ def __setattr__(self, name, value):
15
+ if isinstance(value, (list, tuple)):
16
+ value = [self.__class__(x)
17
+ if isinstance(x, dict) else x for x in value]
18
+ elif isinstance(value, dict) and not isinstance(value, self.__class__):
19
+ value = self.__class__(value)
20
+ super(Face, self).__setattr__(name, value)
21
+ super(Face, self).__setitem__(name, value)
22
+
23
+ __setitem__ = __setattr__
24
+
25
+ def __getattr__(self, name):
26
+ return None
27
+
28
+ @property
29
+ def embedding_norm(self):
30
+ if self.embedding is None:
31
+ return None
32
+ return l2norm(self.embedding)
33
+
34
+ @property
35
+ def normed_embedding(self):
36
+ if self.embedding is None:
37
+ return None
38
+ return self.embedding / self.embedding_norm
39
+
40
+ @property
41
+ def sex(self):
42
+ if self.gender is None:
43
+ return None
44
+ return 'M' if self.gender==1 else 'F'
utils/face_align.py ADDED
@@ -0,0 +1,103 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import cv2
2
+ import numpy as np
3
+ from skimage import transform as trans
4
+
5
+
6
+ arcface_dst = np.array(
7
+ [[38.2946, 51.6963], [73.5318, 51.5014], [56.0252, 71.7366],
8
+ [41.5493, 92.3655], [70.7299, 92.2041]],
9
+ dtype=np.float32)
10
+
11
+ def estimate_norm(lmk, image_size=112,mode='arcface'):
12
+ assert lmk.shape == (5, 2)
13
+ assert image_size%112==0 or image_size%128==0
14
+ if image_size%112==0:
15
+ ratio = float(image_size)/112.0
16
+ diff_x = 0
17
+ else:
18
+ ratio = float(image_size)/128.0
19
+ diff_x = 8.0*ratio
20
+ dst = arcface_dst * ratio
21
+ dst[:,0] += diff_x
22
+ tform = trans.SimilarityTransform()
23
+ tform.estimate(lmk, dst)
24
+ M = tform.params[0:2, :]
25
+ return M
26
+
27
+ def norm_crop(img, landmark, image_size=112, mode='arcface'):
28
+ M = estimate_norm(landmark, image_size, mode)
29
+ warped = cv2.warpAffine(img, M, (image_size, image_size), borderValue=0.0)
30
+ return warped
31
+
32
+ def norm_crop2(img, landmark, image_size=112, mode='arcface'):
33
+ M = estimate_norm(landmark, image_size, mode)
34
+ warped = cv2.warpAffine(img, M, (image_size, image_size), borderValue=0.0)
35
+ return warped, M
36
+
37
+ def square_crop(im, S):
38
+ if im.shape[0] > im.shape[1]:
39
+ height = S
40
+ width = int(float(im.shape[1]) / im.shape[0] * S)
41
+ scale = float(S) / im.shape[0]
42
+ else:
43
+ width = S
44
+ height = int(float(im.shape[0]) / im.shape[1] * S)
45
+ scale = float(S) / im.shape[1]
46
+ resized_im = cv2.resize(im, (width, height))
47
+ det_im = np.zeros((S, S, 3), dtype=np.uint8)
48
+ det_im[:resized_im.shape[0], :resized_im.shape[1], :] = resized_im
49
+ return det_im, scale
50
+
51
+
52
+ def transform(data, center, output_size, scale, rotation):
53
+ scale_ratio = scale
54
+ rot = float(rotation) * np.pi / 180.0
55
+ #translation = (output_size/2-center[0]*scale_ratio, output_size/2-center[1]*scale_ratio)
56
+ t1 = trans.SimilarityTransform(scale=scale_ratio)
57
+ cx = center[0] * scale_ratio
58
+ cy = center[1] * scale_ratio
59
+ t2 = trans.SimilarityTransform(translation=(-1 * cx, -1 * cy))
60
+ t3 = trans.SimilarityTransform(rotation=rot)
61
+ t4 = trans.SimilarityTransform(translation=(output_size / 2,
62
+ output_size / 2))
63
+ t = t1 + t2 + t3 + t4
64
+ M = t.params[0:2]
65
+ cropped = cv2.warpAffine(data,
66
+ M, (output_size, output_size),
67
+ borderValue=0.0)
68
+ return cropped, M
69
+
70
+
71
+ def trans_points2d(pts, M):
72
+ new_pts = np.zeros(shape=pts.shape, dtype=np.float32)
73
+ for i in range(pts.shape[0]):
74
+ pt = pts[i]
75
+ new_pt = np.array([pt[0], pt[1], 1.], dtype=np.float32)
76
+ new_pt = np.dot(M, new_pt)
77
+ #print('new_pt', new_pt.shape, new_pt)
78
+ new_pts[i] = new_pt[0:2]
79
+
80
+ return new_pts
81
+
82
+
83
+ def trans_points3d(pts, M):
84
+ scale = np.sqrt(M[0][0] * M[0][0] + M[0][1] * M[0][1])
85
+ #print(scale)
86
+ new_pts = np.zeros(shape=pts.shape, dtype=np.float32)
87
+ for i in range(pts.shape[0]):
88
+ pt = pts[i]
89
+ new_pt = np.array([pt[0], pt[1], 1.], dtype=np.float32)
90
+ new_pt = np.dot(M, new_pt)
91
+ #print('new_pt', new_pt.shape, new_pt)
92
+ new_pts[i][0:2] = new_pt[0:2]
93
+ new_pts[i][2] = pts[i][2] * scale
94
+
95
+ return new_pts
96
+
97
+
98
+ def trans_points(pts, M):
99
+ if pts.shape[1] == 2:
100
+ return trans_points2d(pts, M)
101
+ else:
102
+ return trans_points3d(pts, M)
103
+
utils/transform.py ADDED
@@ -0,0 +1,116 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import cv2
2
+ import math
3
+ import numpy as np
4
+ from skimage import transform as trans
5
+
6
+
7
+ def transform(data, center, output_size, scale, rotation):
8
+ scale_ratio = scale
9
+ rot = float(rotation) * np.pi / 180.0
10
+ #translation = (output_size/2-center[0]*scale_ratio, output_size/2-center[1]*scale_ratio)
11
+ t1 = trans.SimilarityTransform(scale=scale_ratio)
12
+ cx = center[0] * scale_ratio
13
+ cy = center[1] * scale_ratio
14
+ t2 = trans.SimilarityTransform(translation=(-1 * cx, -1 * cy))
15
+ t3 = trans.SimilarityTransform(rotation=rot)
16
+ t4 = trans.SimilarityTransform(translation=(output_size / 2,
17
+ output_size / 2))
18
+ t = t1 + t2 + t3 + t4
19
+ M = t.params[0:2]
20
+ cropped = cv2.warpAffine(data,
21
+ M, (output_size, output_size),
22
+ borderValue=0.0)
23
+ return cropped, M
24
+
25
+
26
+ def trans_points2d(pts, M):
27
+ new_pts = np.zeros(shape=pts.shape, dtype=np.float32)
28
+ for i in range(pts.shape[0]):
29
+ pt = pts[i]
30
+ new_pt = np.array([pt[0], pt[1], 1.], dtype=np.float32)
31
+ new_pt = np.dot(M, new_pt)
32
+ #print('new_pt', new_pt.shape, new_pt)
33
+ new_pts[i] = new_pt[0:2]
34
+
35
+ return new_pts
36
+
37
+
38
+ def trans_points3d(pts, M):
39
+ scale = np.sqrt(M[0][0] * M[0][0] + M[0][1] * M[0][1])
40
+ #print(scale)
41
+ new_pts = np.zeros(shape=pts.shape, dtype=np.float32)
42
+ for i in range(pts.shape[0]):
43
+ pt = pts[i]
44
+ new_pt = np.array([pt[0], pt[1], 1.], dtype=np.float32)
45
+ new_pt = np.dot(M, new_pt)
46
+ #print('new_pt', new_pt.shape, new_pt)
47
+ new_pts[i][0:2] = new_pt[0:2]
48
+ new_pts[i][2] = pts[i][2] * scale
49
+
50
+ return new_pts
51
+
52
+
53
+ def trans_points(pts, M):
54
+ if pts.shape[1] == 2:
55
+ return trans_points2d(pts, M)
56
+ else:
57
+ return trans_points3d(pts, M)
58
+
59
+ def estimate_affine_matrix_3d23d(X, Y):
60
+ ''' Using least-squares solution
61
+ Args:
62
+ X: [n, 3]. 3d points(fixed)
63
+ Y: [n, 3]. corresponding 3d points(moving). Y = PX
64
+ Returns:
65
+ P_Affine: (3, 4). Affine camera matrix (the third row is [0, 0, 0, 1]).
66
+ '''
67
+ X_homo = np.hstack((X, np.ones([X.shape[0],1]))) #n x 4
68
+ P = np.linalg.lstsq(X_homo, Y)[0].T # Affine matrix. 3 x 4
69
+ return P
70
+
71
+ def P2sRt(P):
72
+ ''' decompositing camera matrix P
73
+ Args:
74
+ P: (3, 4). Affine Camera Matrix.
75
+ Returns:
76
+ s: scale factor.
77
+ R: (3, 3). rotation matrix.
78
+ t: (3,). translation.
79
+ '''
80
+ t = P[:, 3]
81
+ R1 = P[0:1, :3]
82
+ R2 = P[1:2, :3]
83
+ s = (np.linalg.norm(R1) + np.linalg.norm(R2))/2.0
84
+ r1 = R1/np.linalg.norm(R1)
85
+ r2 = R2/np.linalg.norm(R2)
86
+ r3 = np.cross(r1, r2)
87
+
88
+ R = np.concatenate((r1, r2, r3), 0)
89
+ return s, R, t
90
+
91
+ def matrix2angle(R):
92
+ ''' get three Euler angles from Rotation Matrix
93
+ Args:
94
+ R: (3,3). rotation matrix
95
+ Returns:
96
+ x: pitch
97
+ y: yaw
98
+ z: roll
99
+ '''
100
+ sy = math.sqrt(R[0,0] * R[0,0] + R[1,0] * R[1,0])
101
+
102
+ singular = sy < 1e-6
103
+
104
+ if not singular :
105
+ x = math.atan2(R[2,1] , R[2,2])
106
+ y = math.atan2(-R[2,0], sy)
107
+ z = math.atan2(R[1,0], R[0,0])
108
+ else :
109
+ x = math.atan2(-R[1,2], R[1,1])
110
+ y = math.atan2(-R[2,0], sy)
111
+ z = 0
112
+
113
+ # rx, ry, rz = np.rad2deg(x), np.rad2deg(y), np.rad2deg(z)
114
+ rx, ry, rz = x*180/np.pi, y*180/np.pi, z*180/np.pi
115
+ return rx, ry, rz
116
+