Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
hackassin
GitHub Repository: hackassin/learnopencv
Path: blob/master/FaceMaskOverlay/lib/utils/transforms.py
3443 views
1
# ------------------------------------------------------------------------------
2
# Copyright (c) Microsoft
3
# Licensed under the MIT License.
4
# Created by Tianheng Cheng([email protected]), Yang Zhao
5
# ------------------------------------------------------------------------------
6
7
import cv2
8
import torch
9
import scipy
10
import scipy.misc
11
import numpy as np
12
13
14
MATCHED_PARTS = {
15
"300W": ([1, 17], [2, 16], [3, 15], [4, 14], [5, 13], [6, 12], [7, 11], [8, 10],
16
[18, 27], [19, 26], [20, 25], [21, 24], [22, 23],
17
[32, 36], [33, 35],
18
[37, 46], [38, 45], [39, 44], [40, 43], [41, 48], [42, 47],
19
[49, 55], [50, 54], [51, 53], [62, 64], [61, 65], [68, 66], [59, 57], [60, 56]),
20
"AFLW": ([1, 6], [2, 5], [3, 4],
21
[7, 12], [8, 11], [9, 10],
22
[13, 15],
23
[16, 18]),
24
"COFW": ([1, 2], [5, 7], [3, 4], [6, 8], [9, 10], [11, 12], [13, 15], [17, 18], [14, 16], [19, 20], [23, 24]),
25
"WFLW": ([0, 32], [1, 31], [2, 30], [3, 29], [4, 28], [5, 27], [6, 26], [7, 25], [8, 24], [9, 23], [10, 22],
26
[11, 21], [12, 20], [13, 19], [14, 18], [15, 17], # check
27
[33, 46], [34, 45], [35, 44], [36, 43], [37, 42], [38, 50], [39, 49], [40, 48], [41, 47], # elbrow
28
[60, 72], [61, 71], [62, 70], [63, 69], [64, 68], [65, 75], [66, 74], [67, 73],
29
[55, 59], [56, 58],
30
[76, 82], [77, 81], [78, 80], [87, 83], [86, 84],
31
[88, 92], [89, 91], [95, 93], [96, 97])}
32
33
34
def fliplr_joints(x, width, dataset='aflw'):
35
"""
36
flip coords
37
"""
38
matched_parts = MATCHED_PARTS[dataset]
39
# Flip horizontal
40
x[:, 0] = width - x[:, 0]
41
42
if dataset == 'WFLW':
43
for pair in matched_parts:
44
tmp = x[pair[0], :].copy()
45
x[pair[0], :] = x[pair[1], :]
46
x[pair[1], :] = tmp
47
else:
48
for pair in matched_parts:
49
tmp = x[pair[0] - 1, :].copy()
50
x[pair[0] - 1, :] = x[pair[1] - 1, :]
51
x[pair[1] - 1, :] = tmp
52
return x
53
54
55
def get_3rd_point(a, b):
56
direct = a - b
57
return b + np.array([-direct[1], direct[0]], dtype=np.float32)
58
59
60
def get_dir(src_point, rot_rad):
61
sn, cs = np.sin(rot_rad), np.cos(rot_rad)
62
63
src_result = [0, 0]
64
src_result[0] = src_point[0] * cs - src_point[1] * sn
65
src_result[1] = src_point[0] * sn + src_point[1] * cs
66
67
return src_result
68
69
70
def get_affine_transform(
71
center, scale, rot, output_size,
72
shift=np.array([0, 0], dtype=np.float32), inv=0):
73
if not isinstance(scale, np.ndarray) and not isinstance(scale, list):
74
print(scale)
75
scale = np.array([scale, scale])
76
77
scale_tmp = scale * 200.0
78
src_w = scale_tmp[0]
79
dst_w = output_size[0]
80
dst_h = output_size[1]
81
82
rot_rad = np.pi * rot / 180
83
src_dir = get_dir([0, src_w * -0.5], rot_rad)
84
dst_dir = np.array([0, dst_w * -0.5], np.float32)
85
86
src = np.zeros((3, 2), dtype=np.float32)
87
dst = np.zeros((3, 2), dtype=np.float32)
88
src[0, :] = center + scale_tmp * shift
89
src[1, :] = center + src_dir + scale_tmp * shift
90
dst[0, :] = [dst_w * 0.5, dst_h * 0.5]
91
dst[1, :] = np.array([dst_w * 0.5, dst_h * 0.5]) + dst_dir
92
93
src[2:, :] = get_3rd_point(src[0, :], src[1, :])
94
dst[2:, :] = get_3rd_point(dst[0, :], dst[1, :])
95
96
if inv:
97
trans = cv2.getAffineTransform(np.float32(dst), np.float32(src))
98
else:
99
trans = cv2.getAffineTransform(np.float32(src), np.float32(dst))
100
101
return trans
102
103
104
def crop_v2(img, center, scale, output_size, rot=0):
105
trans = get_affine_transform(center, scale, rot, output_size)
106
107
dst_img = cv2.warpAffine(
108
img, trans, (int(output_size[0]), int(output_size[1])),
109
flags=cv2.INTER_LINEAR
110
)
111
112
return dst_img
113
114
115
def get_transform(center, scale, output_size, rot=0):
116
"""
117
General image processing functions
118
"""
119
# Generate transformation matrix
120
h = 200 * scale
121
t = np.zeros((3, 3))
122
t[0, 0] = float(output_size[1]) / h
123
t[1, 1] = float(output_size[0]) / h
124
t[0, 2] = output_size[1] * (-float(center[0]) / h + .5)
125
t[1, 2] = output_size[0] * (-float(center[1]) / h + .5)
126
t[2, 2] = 1
127
if not rot == 0:
128
rot = -rot # To match direction of rotation from cropping
129
rot_mat = np.zeros((3, 3))
130
rot_rad = rot * np.pi / 180
131
sn, cs = np.sin(rot_rad), np.cos(rot_rad)
132
rot_mat[0, :2] = [cs, -sn]
133
rot_mat[1, :2] = [sn, cs]
134
rot_mat[2, 2] = 1
135
# Need to rotate around center
136
t_mat = np.eye(3)
137
t_mat[0, 2] = -output_size[1]/2
138
t_mat[1, 2] = -output_size[0]/2
139
t_inv = t_mat.copy()
140
t_inv[:2, 2] *= -1
141
t = np.dot(t_inv, np.dot(rot_mat, np.dot(t_mat, t)))
142
return t
143
144
145
def transform_pixel(pt, center, scale, output_size, invert=0, rot=0):
146
# Transform pixel location to different reference
147
t = get_transform(center, scale, output_size, rot=rot)
148
if invert:
149
t = np.linalg.inv(t)
150
new_pt = np.array([pt[0] - 1, pt[1] - 1, 1.]).T
151
new_pt = np.dot(t, new_pt)
152
return new_pt[:2].astype(int) + 1
153
154
155
def transform_preds(coords, center, scale, output_size):
156
157
for p in range(coords.size(0)):
158
coords[p, 0:2] = torch.tensor(transform_pixel(coords[p, 0:2], center, scale, output_size, 1, 0))
159
return coords
160
161
162
def crop(img, center, scale, output_size, rot=0):
163
center_new = center.clone()
164
165
# Preprocessing for efficient cropping
166
ht, wd = img.shape[0], img.shape[1]
167
sf = scale * 200.0 / output_size[0]
168
if sf < 2:
169
sf = 1
170
else:
171
new_size = int(np.math.floor(max(ht, wd) / sf))
172
new_ht = int(np.math.floor(ht / sf))
173
new_wd = int(np.math.floor(wd / sf))
174
if new_size < 2:
175
return torch.zeros(output_size[0], output_size[1], img.shape[2]) \
176
if len(img.shape) > 2 else torch.zeros(output_size[0], output_size[1])
177
else:
178
img = cv2.resize(img, (new_wd, new_ht), interpolation=cv2.INTER_LINEAR)
179
center_new[0] = center_new[0] * 1.0 / sf
180
center_new[1] = center_new[1] * 1.0 / sf
181
scale = scale / sf
182
183
# Upper left point
184
ul = np.array(transform_pixel([0, 0], center_new, scale, output_size, invert=1))
185
# Bottom right point
186
br = np.array(transform_pixel(output_size, center_new, scale, output_size, invert=1))
187
188
# Padding so that when rotated proper amount of context is included
189
pad = int(np.linalg.norm(br - ul) / 2 - float(br[1] - ul[1]) / 2)
190
if not rot == 0:
191
ul -= pad
192
br += pad
193
194
new_shape = [br[1] - ul[1], br[0] - ul[0]]
195
if len(img.shape) > 2:
196
new_shape += [img.shape[2]]
197
198
new_img = np.zeros(new_shape, dtype=np.float32)
199
200
# Range to fill new array
201
new_x = max(0, -ul[0]), min(br[0], len(img[0])) - ul[0]
202
new_y = max(0, -ul[1]), min(br[1], len(img)) - ul[1]
203
# Range to sample from original image
204
old_x = max(0, ul[0]), min(len(img[0]), br[0])
205
old_y = max(0, ul[1]), min(len(img), br[1])
206
new_img[new_y[0]:new_y[1], new_x[0]:new_x[1]] = img[old_y[0]:old_y[1], old_x[0]:old_x[1]]
207
208
if not rot == 0:
209
# Remove padding
210
new_img = scipy.misc.imrotate(new_img, rot)
211
new_img = new_img[pad:-pad, pad:-pad]
212
new_img = cv2.resize(
213
new_img, (output_size[0], output_size[1]), interpolation=cv2.INTER_LINEAR
214
)
215
return new_img
216
217
218
def generate_target(img, pt, sigma, label_type='Gaussian'):
219
# Check that any part of the gaussian is in-bounds
220
tmp_size = sigma * 3
221
ul = [int(pt[0] - tmp_size), int(pt[1] - tmp_size)]
222
br = [int(pt[0] + tmp_size + 1), int(pt[1] + tmp_size + 1)]
223
if (ul[0] >= img.shape[1] or ul[1] >= img.shape[0] or
224
br[0] < 0 or br[1] < 0):
225
# If not, just return the image as is
226
return img
227
228
# Generate gaussian
229
size = 2 * tmp_size + 1
230
x = np.arange(0, size, 1, np.float32)
231
y = x[:, np.newaxis]
232
x0 = y0 = size // 2
233
# The gaussian is not normalized, we want the center value to equal 1
234
if label_type == 'Gaussian':
235
g = np.exp(- ((x - x0) ** 2 + (y - y0) ** 2) / (2 * sigma ** 2))
236
else:
237
g = sigma / (((x - x0) ** 2 + (y - y0) ** 2 + sigma ** 2) ** 1.5)
238
239
# Usable gaussian range
240
g_x = max(0, -ul[0]), min(br[0], img.shape[1]) - ul[0]
241
g_y = max(0, -ul[1]), min(br[1], img.shape[0]) - ul[1]
242
# Image range
243
img_x = max(0, ul[0]), min(br[0], img.shape[1])
244
img_y = max(0, ul[1]), min(br[1], img.shape[0])
245
246
img[img_y[0]:img_y[1], img_x[0]:img_x[1]] = g[g_y[0]:g_y[1], g_x[0]:g_x[1]]
247
return img
248
249