deepsafe commited on
Commit
6f6117b
·
verified ·
1 Parent(s): 5207201

chore: remove non-weight files (batch 7)

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. video/pwtf-dvd/model_code/inference/test_tools/__init__.py +0 -0
  2. video/pwtf-dvd/model_code/inference/test_tools/common.py +0 -122
  3. video/pwtf-dvd/model_code/inference/test_tools/ct/detection/__init__.py +0 -56
  4. video/pwtf-dvd/model_code/inference/test_tools/ct/detection/__pycache__/__init__.cpython-310.pyc +0 -0
  5. video/pwtf-dvd/model_code/inference/test_tools/ct/detection/__pycache__/__init__.cpython-39.pyc +0 -0
  6. video/pwtf-dvd/model_code/inference/test_tools/ct/detection/__pycache__/alignment.cpython-310.pyc +0 -0
  7. video/pwtf-dvd/model_code/inference/test_tools/ct/detection/__pycache__/alignment.cpython-39.pyc +0 -0
  8. video/pwtf-dvd/model_code/inference/test_tools/ct/detection/__pycache__/detector.cpython-310.pyc +0 -0
  9. video/pwtf-dvd/model_code/inference/test_tools/ct/detection/__pycache__/detector.cpython-39.pyc +0 -0
  10. video/pwtf-dvd/model_code/inference/test_tools/ct/detection/__pycache__/utils.cpython-310.pyc +0 -0
  11. video/pwtf-dvd/model_code/inference/test_tools/ct/detection/__pycache__/utils.cpython-39.pyc +0 -0
  12. video/pwtf-dvd/model_code/inference/test_tools/ct/detection/alignment.py +0 -608
  13. video/pwtf-dvd/model_code/inference/test_tools/ct/detection/detector.py +0 -46
  14. video/pwtf-dvd/model_code/inference/test_tools/ct/detection/utils.py +0 -146
  15. video/pwtf-dvd/model_code/inference/test_tools/ct/face_alignment/__init__.py +0 -1
  16. video/pwtf-dvd/model_code/inference/test_tools/ct/face_alignment/basenet.py +0 -107
  17. video/pwtf-dvd/model_code/inference/test_tools/ct/face_alignment/predictor.py +0 -143
  18. video/pwtf-dvd/model_code/inference/test_tools/ct/face_alignment/utils.py +0 -17
  19. video/pwtf-dvd/model_code/inference/test_tools/ct/operations.py +0 -79
  20. video/pwtf-dvd/model_code/inference/test_tools/ct/tracking/__init__.py +0 -0
  21. video/pwtf-dvd/model_code/inference/test_tools/ct/tracking/sort.py +0 -285
  22. video/pwtf-dvd/model_code/inference/test_tools/ct/tracking/tracker.py +0 -27
  23. video/pwtf-dvd/model_code/inference/test_tools/ct/utils.py +0 -5
  24. video/pwtf-dvd/model_code/inference/test_tools/faster_crop_align_xray.py +0 -73
  25. video/pwtf-dvd/model_code/inference/test_tools/supply_writer.py +0 -49
  26. video/pwtf-dvd/model_code/inference/test_tools/utils.py +0 -115
  27. video/pwtf-dvd/model_code/inference/test_tools/warp_for_xray.py +0 -574
  28. video/pwtf-dvd/model_code/inference/utils/__init__.py +0 -7
  29. video/pwtf-dvd/model_code/inference/utils/common.py +0 -80
  30. video/pwtf-dvd/model_code/inference/utils/logger.py +0 -182
  31. video/pwtf-dvd/model_code/inference/utils/model_loader.py +0 -117
  32. video/pwtf-dvd/model_code/inference/utils/plugin_loader.py +0 -69
  33. video/pwtf-dvd/model_code/inference/utils/torch_save.py +0 -9
  34. video/pwtf-dvd/model_code/preprocessing/preprocess.py +0 -258
  35. video/pwtf-dvd/model_code/preprocessing/test_tools/__init__.py +0 -0
  36. video/pwtf-dvd/model_code/preprocessing/test_tools/common.py +0 -122
  37. video/pwtf-dvd/model_code/preprocessing/test_tools/ct/detection/__init__.py +0 -56
  38. video/pwtf-dvd/model_code/preprocessing/test_tools/ct/detection/alignment.py +0 -608
  39. video/pwtf-dvd/model_code/preprocessing/test_tools/ct/detection/detector.py +0 -46
  40. video/pwtf-dvd/model_code/preprocessing/test_tools/ct/detection/utils.py +0 -147
  41. video/pwtf-dvd/model_code/preprocessing/test_tools/ct/face_alignment/__init__.py +0 -1
  42. video/pwtf-dvd/model_code/preprocessing/test_tools/ct/face_alignment/basenet.py +0 -107
  43. video/pwtf-dvd/model_code/preprocessing/test_tools/ct/face_alignment/predictor.py +0 -143
  44. video/pwtf-dvd/model_code/preprocessing/test_tools/ct/face_alignment/utils.py +0 -17
  45. video/pwtf-dvd/model_code/preprocessing/test_tools/ct/operations.py +0 -79
  46. video/pwtf-dvd/model_code/preprocessing/test_tools/ct/tracking/__init__.py +0 -0
  47. video/pwtf-dvd/model_code/preprocessing/test_tools/ct/tracking/sort.py +0 -285
  48. video/pwtf-dvd/model_code/preprocessing/test_tools/ct/tracking/tracker.py +0 -27
  49. video/pwtf-dvd/model_code/preprocessing/test_tools/ct/utils.py +0 -5
  50. video/pwtf-dvd/model_code/preprocessing/test_tools/faster_crop_align_xray.py +0 -73
video/pwtf-dvd/model_code/inference/test_tools/__init__.py DELETED
File without changes
video/pwtf-dvd/model_code/inference/test_tools/common.py DELETED
@@ -1,122 +0,0 @@
1
- import os
2
-
3
- os.environ["KMP_DUPLICATE_LIB_OK"] = "TRUE"
4
-
5
- from .ct.detection.utils import grab_all_frames, get_valid_faces, sample_chunks
6
- from .ct.operations import multiple_tracking
7
- import numpy as np
8
- from .ct.face_alignment import LandmarkPredictor
9
- from .ct.detection import FaceDetector
10
- import cv2
11
- from .utils import flatten,partition
12
-
13
-
14
- detector = FaceDetector(0)
15
- predictor = LandmarkPredictor(0)
16
-
17
-
18
- def get_five(ldm68):
19
- groups = [range(36, 42), range(42, 48), [30], [48], [54]]
20
- points = []
21
- for group in groups:
22
- points.append(ldm68[group].mean(0))
23
- return np.array(points)
24
-
25
-
26
- def get_bbox(mask):
27
- try:
28
- y, x = np.nonzero(mask[..., 0])
29
- return x.min() - 1, y.min() - 1, x.max() + 1, y.max() + 1
30
- except:
31
- return None
32
-
33
-
34
- def get_bigger_box(image, box, scale=0.5):
35
- height, width = image.shape[:2]
36
- box = np.rint(box).astype(np.int)
37
- new_box = box.reshape(2, 2)
38
- size = new_box[1] - new_box[0]
39
- diff = scale * size
40
- diff = diff[None, :] * np.array([-1, 1])[:, None]
41
- new_box = new_box + diff
42
- new_box[:, 0] = np.clip(new_box[:, 0], 0, width - 1)
43
- new_box[:, 1] = np.clip(new_box[:, 1], 0, height - 1)
44
- new_box = np.rint(new_box).astype(np.int)
45
- return new_box.reshape(-1)
46
-
47
-
48
- def process_bigger_clips(clips, dete_res, clip_size, step, scale=0.5):
49
- assert len(clips) % clip_size == 0
50
- detect_results = sample_chunks(dete_res, clip_size, step)
51
- clips = sample_chunks(clips, clip_size, step)
52
- new_clips = []
53
- for i, (frame_clip, record_clip) in enumerate(zip(clips, detect_results)):
54
- tracks = multiple_tracking(record_clip)
55
- for j, track in enumerate(tracks):
56
- new_images = []
57
- for (box, ldm, _), frame in zip(track, frame_clip):
58
- big_box = get_bigger_box(frame, box, scale)
59
- x1, y1, x2, y2 = big_box
60
- top_left = big_box[:2][None, :]
61
- new_ldm5 = ldm - top_left
62
- box = np.rint(box).astype(np.int)
63
- new_box = (box.reshape(2, 2) - top_left).reshape(-1)
64
- feed = LandmarkPredictor.prepare_feed(frame, box)
65
- ldm68 = predictor(feed) - top_left
66
- new_images.append(
67
- (frame[y1:y2, x1:x2], big_box, new_box, new_ldm5, ldm68)
68
- )
69
- new_clips.append(new_images)
70
- return new_clips
71
-
72
-
73
- def post(detected_faces):
74
- return [[face[:4], None, face[-1]] for face in detected_faces]
75
-
76
-
77
- def check(detect_res):
78
- return min([len(faces) for faces in detect_res]) != 0
79
-
80
-
81
- def detect_all(file, sfd_only=False, return_frames=False, max_size=None):
82
- frames = grab_all_frames(file, max_size=max_size, cvt=True)
83
- if not sfd_only:
84
- detect_res = flatten(
85
- [detector.detect(item) for item in partition(frames, 50)]
86
- )
87
- detect_res = get_valid_faces(detect_res, thres=0.5)
88
- else:
89
- raise NotImplementedError
90
-
91
- all_68 = get_lm68(frames, detect_res)
92
- if not return_frames:
93
- return detect_res, all_68
94
- else:
95
- return detect_res, all_68, frames
96
-
97
-
98
- def get_lm68(frames, detect_res):
99
- assert len(frames) == len(detect_res)
100
- frame_count = len(frames)
101
- all_68 = []
102
- for i in range(frame_count):
103
- frame = frames[i]
104
- faces = detect_res[i]
105
- if len(faces) == 0:
106
- res_68 = []
107
- else:
108
- feeds = []
109
- for face in faces:
110
- assert len(face) == 3
111
- box = face[0]
112
- feed = LandmarkPredictor.prepare_feed(frame, box)
113
- feeds.append(feed)
114
- res_68 = predictor(feeds)
115
- assert len(res_68) == len(faces)
116
- for face, l_68 in zip(faces, res_68):
117
- if face[1] is None:
118
- face[1] = get_five(l_68)
119
- all_68.append(res_68)
120
-
121
- assert len(all_68) == len(detect_res)
122
- return all_68
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
video/pwtf-dvd/model_code/inference/test_tools/ct/detection/__init__.py DELETED
@@ -1,56 +0,0 @@
1
- import cv2
2
- from .detector import RetinaFace
3
- from .utils import *
4
-
5
-
6
- def assert_bounded(val, low, up):
7
- return val >= low and val < up
8
-
9
-
10
- def check_valid(face, w, h):
11
- box = face[0]
12
- if box[0] > box[2]:
13
- return False
14
- if box[1] > box[3]:
15
- return False
16
- for idx, bound in zip([0, 1, 2, 3], [w, h, w, h]):
17
- if not assert_bounded(box[idx], 0, bound):
18
- return False
19
- pts = face[1]
20
- for p in pts:
21
- for idx, bound in zip([0, 1], [w, h]):
22
- if not assert_bounded(p[idx], 0, bound):
23
- return False
24
- return True
25
-
26
-
27
- def post_detect(detect_results, scale, w, h):
28
- new_results = []
29
- for frame_faces in detect_results:
30
- new_frame_faces = []
31
- for box, ldm, score in frame_faces:
32
- box = box * scale
33
- ldm = ldm * scale
34
- face = (box, ldm, score)
35
- if check_valid(face, w=w, h=h):
36
- new_frame_faces.append(face)
37
- new_results.append(new_frame_faces)
38
- return new_results
39
-
40
-
41
- class FaceDetector(RetinaFace):
42
- def scale_detect(self, images):
43
- max_res = 1920
44
- h, w = images[0].shape[:2]
45
- if max(h, w) > max_res:
46
- init_scale = max(h, w) / max_res
47
- else:
48
- init_scale = 1
49
- resize_scale = 2 * init_scale
50
- resize_w = int(w / resize_scale)
51
- resize_h = int(h / resize_scale)
52
- detect_input = [cv2.resize(frame, (resize_w, resize_h)) for frame in images]
53
- detect_results = post_detect(
54
- self.detect(detect_input), scale=resize_scale, w=w, h=h,
55
- )
56
- return detect_results
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
video/pwtf-dvd/model_code/inference/test_tools/ct/detection/__pycache__/__init__.cpython-310.pyc DELETED
Binary file (1.89 kB)
 
video/pwtf-dvd/model_code/inference/test_tools/ct/detection/__pycache__/__init__.cpython-39.pyc DELETED
Binary file (1.88 kB)
 
video/pwtf-dvd/model_code/inference/test_tools/ct/detection/__pycache__/alignment.cpython-310.pyc DELETED
Binary file (16.6 kB)
 
video/pwtf-dvd/model_code/inference/test_tools/ct/detection/__pycache__/alignment.cpython-39.pyc DELETED
Binary file (17 kB)
 
video/pwtf-dvd/model_code/inference/test_tools/ct/detection/__pycache__/detector.cpython-310.pyc DELETED
Binary file (1.67 kB)
 
video/pwtf-dvd/model_code/inference/test_tools/ct/detection/__pycache__/detector.cpython-39.pyc DELETED
Binary file (1.66 kB)
 
video/pwtf-dvd/model_code/inference/test_tools/ct/detection/__pycache__/utils.cpython-310.pyc DELETED
Binary file (4.34 kB)
 
video/pwtf-dvd/model_code/inference/test_tools/ct/detection/__pycache__/utils.cpython-39.pyc DELETED
Binary file (4.34 kB)
 
video/pwtf-dvd/model_code/inference/test_tools/ct/detection/alignment.py DELETED
@@ -1,608 +0,0 @@
1
- from itertools import product as product
2
- from math import ceil
3
-
4
- import numpy as np
5
- import torch
6
- import torch.backends.cudnn as cudnn
7
- import torch.nn as nn
8
- import torch.nn.functional as F
9
- import torchvision.models._utils as _utils
10
-
11
-
12
- def conv_bn(inp, oup, stride=1, leaky=0):
13
- return nn.Sequential(
14
- nn.Conv2d(inp, oup, 3, stride, 1, bias=False),
15
- nn.BatchNorm2d(oup),
16
- nn.LeakyReLU(negative_slope=leaky, inplace=True),
17
- )
18
-
19
-
20
- def conv_bn_no_relu(inp, oup, stride):
21
- return nn.Sequential(
22
- nn.Conv2d(inp, oup, 3, stride, 1, bias=False), nn.BatchNorm2d(oup),
23
- )
24
-
25
-
26
- def conv_bn1X1(inp, oup, stride, leaky=0):
27
- return nn.Sequential(
28
- nn.Conv2d(inp, oup, 1, stride, padding=0, bias=False),
29
- nn.BatchNorm2d(oup),
30
- nn.LeakyReLU(negative_slope=leaky, inplace=True),
31
- )
32
-
33
-
34
- def conv_dw(inp, oup, stride, leaky=0.1):
35
- return nn.Sequential(
36
- nn.Conv2d(inp, inp, 3, stride, 1, groups=inp, bias=False),
37
- nn.BatchNorm2d(inp),
38
- nn.LeakyReLU(negative_slope=leaky, inplace=True),
39
- nn.Conv2d(inp, oup, 1, 1, 0, bias=False),
40
- nn.BatchNorm2d(oup),
41
- nn.LeakyReLU(negative_slope=leaky, inplace=True),
42
- )
43
-
44
-
45
- class SSH(nn.Module):
46
- def __init__(self, in_channel, out_channel):
47
- super(SSH, self).__init__()
48
- assert out_channel % 4 == 0
49
- leaky = 0
50
- if out_channel <= 64:
51
- leaky = 0.1
52
- self.conv3X3 = conv_bn_no_relu(in_channel, out_channel // 2, stride=1)
53
-
54
- self.conv5X5_1 = conv_bn(in_channel, out_channel // 4, stride=1, leaky=leaky)
55
- self.conv5X5_2 = conv_bn_no_relu(out_channel // 4, out_channel // 4, stride=1)
56
-
57
- self.conv7X7_2 = conv_bn(
58
- out_channel // 4, out_channel // 4, stride=1, leaky=leaky
59
- )
60
- self.conv7x7_3 = conv_bn_no_relu(out_channel // 4, out_channel // 4, stride=1)
61
-
62
- def forward(self, input):
63
- conv3X3 = self.conv3X3(input)
64
-
65
- conv5X5_1 = self.conv5X5_1(input)
66
- conv5X5 = self.conv5X5_2(conv5X5_1)
67
-
68
- conv7X7_2 = self.conv7X7_2(conv5X5_1)
69
- conv7X7 = self.conv7x7_3(conv7X7_2)
70
-
71
- out = torch.cat([conv3X3, conv5X5, conv7X7], dim=1)
72
- out = F.relu(out)
73
- return out
74
-
75
-
76
- class FPN(nn.Module):
77
- def __init__(self, in_channels_list, out_channels):
78
- super(FPN, self).__init__()
79
- leaky = 0
80
- if out_channels <= 64:
81
- leaky = 0.1
82
- self.output1 = conv_bn1X1(
83
- in_channels_list[0], out_channels, stride=1, leaky=leaky
84
- )
85
- self.output2 = conv_bn1X1(
86
- in_channels_list[1], out_channels, stride=1, leaky=leaky
87
- )
88
- self.output3 = conv_bn1X1(
89
- in_channels_list[2], out_channels, stride=1, leaky=leaky
90
- )
91
-
92
- self.merge1 = conv_bn(out_channels, out_channels, leaky=leaky)
93
- self.merge2 = conv_bn(out_channels, out_channels, leaky=leaky)
94
-
95
- def forward(self, input):
96
- # names = list(input.keys())
97
- input = list(input.values())
98
-
99
- output1 = self.output1(input[0])
100
- output2 = self.output2(input[1])
101
- output3 = self.output3(input[2])
102
-
103
- up3 = F.interpolate(
104
- output3, size=[output2.size(2), output2.size(3)], mode="nearest"
105
- )
106
- output2 = output2 + up3
107
- output2 = self.merge2(output2)
108
-
109
- up2 = F.interpolate(
110
- output2, size=[output1.size(2), output1.size(3)], mode="nearest"
111
- )
112
- output1 = output1 + up2
113
- output1 = self.merge1(output1)
114
-
115
- out = [output1, output2, output3]
116
- return out
117
-
118
-
119
- class MobileNetV1(nn.Module):
120
- def __init__(self):
121
- super(MobileNetV1, self).__init__()
122
- self.stage1 = nn.Sequential(
123
- conv_bn(3, 8, 2, leaky=0.1), # 3
124
- conv_dw(8, 16, 1), # 7
125
- conv_dw(16, 32, 2), # 11
126
- conv_dw(32, 32, 1), # 19
127
- conv_dw(32, 64, 2), # 27
128
- conv_dw(64, 64, 1), # 43
129
- )
130
- self.stage2 = nn.Sequential(
131
- conv_dw(64, 128, 2), # 43 + 16 = 59
132
- conv_dw(128, 128, 1), # 59 + 32 = 91
133
- conv_dw(128, 128, 1), # 91 + 32 = 123
134
- conv_dw(128, 128, 1), # 123 + 32 = 155
135
- conv_dw(128, 128, 1), # 155 + 32 = 187
136
- conv_dw(128, 128, 1), # 187 + 32 = 219
137
- )
138
- self.stage3 = nn.Sequential(
139
- conv_dw(128, 256, 2), # 219 +3 2 = 241
140
- conv_dw(256, 256, 1), # 241 + 64 = 301
141
- )
142
- self.avg = nn.AdaptiveAvgPool2d((1, 1))
143
- self.fc = nn.Linear(256, 1000)
144
-
145
- def forward(self, x):
146
- x = self.stage1(x)
147
- x = self.stage2(x)
148
- x = self.stage3(x)
149
- x = self.avg(x)
150
- # x = self.model(x)
151
- x = x.view(-1, 256)
152
- x = self.fc(x)
153
- return x
154
-
155
-
156
- class ClassHead(nn.Module):
157
- def __init__(self, inchannels=512, num_anchors=3):
158
- super(ClassHead, self).__init__()
159
- self.num_anchors = num_anchors
160
- self.conv1x1 = nn.Conv2d(
161
- inchannels, self.num_anchors * 2, kernel_size=(1, 1), stride=1, padding=0
162
- )
163
-
164
- def forward(self, x):
165
- out = self.conv1x1(x)
166
- out = out.permute(0, 2, 3, 1).contiguous()
167
-
168
- return out.view(out.shape[0], -1, 2)
169
-
170
-
171
- class BboxHead(nn.Module):
172
- def __init__(self, inchannels=512, num_anchors=3):
173
- super(BboxHead, self).__init__()
174
- self.conv1x1 = nn.Conv2d(
175
- inchannels, num_anchors * 4, kernel_size=(1, 1), stride=1, padding=0
176
- )
177
-
178
- def forward(self, x):
179
- out = self.conv1x1(x)
180
- out = out.permute(0, 2, 3, 1).contiguous()
181
-
182
- return out.view(out.shape[0], -1, 4)
183
-
184
-
185
- class LandmarkHead(nn.Module):
186
- def __init__(self, inchannels=512, num_anchors=3):
187
- super(LandmarkHead, self).__init__()
188
- self.conv1x1 = nn.Conv2d(
189
- inchannels, num_anchors * 10, kernel_size=(1, 1), stride=1, padding=0
190
- )
191
-
192
- def forward(self, x):
193
- out = self.conv1x1(x)
194
- out = out.permute(0, 2, 3, 1).contiguous()
195
-
196
- return out.view(out.shape[0], -1, 10)
197
-
198
-
199
- class RetinaFace(nn.Module):
200
- def __init__(self, cfg=None, phase="train"):
201
- """
202
- :param cfg: Network related settings.
203
- :param phase: train or test.
204
- """
205
- super(RetinaFace, self).__init__()
206
- self.phase = phase
207
- backbone = None
208
- if cfg["name"] == "mobilenet0.25":
209
- backbone = MobileNetV1()
210
- elif cfg["name"] == "Resnet50":
211
- import torchvision.models as models
212
-
213
- backbone = models.resnet50(pretrained=cfg["pretrain"])
214
-
215
- self.body = _utils.IntermediateLayerGetter(backbone, cfg["return_layers"])
216
- in_channels_stage2 = cfg["in_channel"]
217
- in_channels_list = [
218
- in_channels_stage2 * 2,
219
- in_channels_stage2 * 4,
220
- in_channels_stage2 * 8,
221
- ]
222
- out_channels = cfg["out_channel"]
223
- self.fpn = FPN(in_channels_list, out_channels)
224
- self.ssh1 = SSH(out_channels, out_channels)
225
- self.ssh2 = SSH(out_channels, out_channels)
226
- self.ssh3 = SSH(out_channels, out_channels)
227
-
228
- self.ClassHead = self._make_class_head(fpn_num=3, inchannels=cfg["out_channel"])
229
- self.BboxHead = self._make_bbox_head(fpn_num=3, inchannels=cfg["out_channel"])
230
- self.LandmarkHead = self._make_landmark_head(
231
- fpn_num=3, inchannels=cfg["out_channel"]
232
- )
233
-
234
- def _make_class_head(self, fpn_num=3, inchannels=64, anchor_num=2):
235
- classhead = nn.ModuleList()
236
- for i in range(fpn_num):
237
- classhead.append(ClassHead(inchannels, anchor_num))
238
- return classhead
239
-
240
- def _make_bbox_head(self, fpn_num=3, inchannels=64, anchor_num=2):
241
- bboxhead = nn.ModuleList()
242
- for i in range(fpn_num):
243
- bboxhead.append(BboxHead(inchannels, anchor_num))
244
- return bboxhead
245
-
246
- def _make_landmark_head(self, fpn_num=3, inchannels=64, anchor_num=2):
247
- landmarkhead = nn.ModuleList()
248
- for i in range(fpn_num):
249
- landmarkhead.append(LandmarkHead(inchannels, anchor_num))
250
- return landmarkhead
251
-
252
- def forward(self, inputs):
253
- out = self.body(inputs)
254
-
255
- # FPN
256
- fpn = self.fpn(out)
257
-
258
- # SSH
259
- feature1 = self.ssh1(fpn[0])
260
- feature2 = self.ssh2(fpn[1])
261
- feature3 = self.ssh3(fpn[2])
262
- features = [feature1, feature2, feature3]
263
-
264
- bbox_regressions = torch.cat(
265
- [self.BboxHead[i](feature) for i, feature in enumerate(features)], dim=1
266
- )
267
- classifications = torch.cat(
268
- [self.ClassHead[i](feature) for i, feature in enumerate(features)], dim=1
269
- )
270
- ldm_regressions = torch.cat(
271
- [self.LandmarkHead[i](feature) for i, feature in enumerate(features)], dim=1
272
- )
273
-
274
- if self.phase == "train":
275
- output = (bbox_regressions, classifications, ldm_regressions)
276
- else:
277
- output = (
278
- bbox_regressions,
279
- F.softmax(classifications, dim=-1),
280
- ldm_regressions,
281
- )
282
- return output
283
-
284
-
285
- # Adapted from https://github.com/Hakuyume/chainer-ssd
286
- def decode(loc, priors, variances):
287
- boxes = torch.cat(
288
- (
289
- priors[:, :2] + loc[:, :2] * variances[0] * priors[:, 2:],
290
- priors[:, 2:] * torch.exp(loc[:, 2:] * variances[1]),
291
- ),
292
- 1,
293
- )
294
- boxes[:, :2] -= boxes[:, 2:] / 2
295
- boxes[:, 2:] += boxes[:, :2]
296
- return boxes
297
-
298
-
299
- def decode_landm(pre, priors, variances):
300
- landms = torch.cat(
301
- (
302
- priors[:, :2] + pre[:, :2] * variances[0] * priors[:, 2:],
303
- priors[:, :2] + pre[:, 2:4] * variances[0] * priors[:, 2:],
304
- priors[:, :2] + pre[:, 4:6] * variances[0] * priors[:, 2:],
305
- priors[:, :2] + pre[:, 6:8] * variances[0] * priors[:, 2:],
306
- priors[:, :2] + pre[:, 8:10] * variances[0] * priors[:, 2:],
307
- ),
308
- dim=1,
309
- )
310
- return landms
311
-
312
-
313
- def py_cpu_nms(dets, thresh):
314
- """Pure Python NMS baseline."""
315
- x1 = dets[:, 0]
316
- y1 = dets[:, 1]
317
- x2 = dets[:, 2]
318
- y2 = dets[:, 3]
319
- scores = dets[:, 4]
320
-
321
- areas = (x2 - x1 + 1) * (y2 - y1 + 1)
322
- order = scores.argsort()[::-1]
323
-
324
- keep = []
325
- while order.size > 0:
326
- i = order[0]
327
- keep.append(i)
328
- xx1 = np.maximum(x1[i], x1[order[1:]])
329
- yy1 = np.maximum(y1[i], y1[order[1:]])
330
- xx2 = np.minimum(x2[i], x2[order[1:]])
331
- yy2 = np.minimum(y2[i], y2[order[1:]])
332
-
333
- w = np.maximum(0.0, xx2 - xx1 + 1)
334
- h = np.maximum(0.0, yy2 - yy1 + 1)
335
- inter = w * h
336
- ovr = inter / (areas[i] + areas[order[1:]] - inter)
337
-
338
- inds = np.where(ovr <= thresh)[0]
339
- order = order[inds + 1]
340
-
341
- return keep
342
-
343
-
344
- class PriorBox(object):
345
- def __init__(self, cfg, image_size=None, phase="train"):
346
- super(PriorBox, self).__init__()
347
- self.min_sizes = cfg["min_sizes"]
348
- self.steps = cfg["steps"]
349
- self.clip = cfg["clip"]
350
- self.image_size = image_size
351
- self.feature_maps = [
352
- [ceil(self.image_size[0] / step), ceil(self.image_size[1] / step)]
353
- for step in self.steps
354
- ]
355
- self.name = "s"
356
-
357
- def forward(self):
358
- anchors = []
359
- for k, f in enumerate(self.feature_maps):
360
- min_sizes = self.min_sizes[k]
361
- for i, j in product(range(f[0]), range(f[1])):
362
- for min_size in min_sizes:
363
- s_kx = min_size / self.image_size[1]
364
- s_ky = min_size / self.image_size[0]
365
- dense_cx = [
366
- x * self.steps[k] / self.image_size[1] for x in [j + 0.5]
367
- ]
368
- dense_cy = [
369
- y * self.steps[k] / self.image_size[0] for y in [i + 0.5]
370
- ]
371
- for cy, cx in product(dense_cy, dense_cx):
372
- anchors += [cx, cy, s_kx, s_ky]
373
-
374
- # back to torch land
375
- output = torch.Tensor(anchors).view(-1, 4)
376
- if self.clip:
377
- output.clamp_(max=1, min=0)
378
- return output
379
-
380
-
381
- cfg_mnet = {
382
- "name": "mobilenet0.25",
383
- "min_sizes": [[16, 32], [64, 128], [256, 512]],
384
- "steps": [8, 16, 32],
385
- "variance": [0.1, 0.2],
386
- "clip": False,
387
- "loc_weight": 2.0,
388
- "gpu_train": True,
389
- "batch_size": 32,
390
- "ngpu": 1,
391
- "epoch": 250,
392
- "decay1": 190,
393
- "decay2": 220,
394
- "image_size": 640,
395
- "pretrain": True,
396
- "return_layers": {"stage1": 1, "stage2": 2, "stage3": 3},
397
- "in_channel": 32,
398
- "out_channel": 64,
399
- }
400
-
401
- cfg_re50 = {
402
- "name": "Resnet50",
403
- "min_sizes": [[16, 32], [64, 128], [256, 512]],
404
- "steps": [8, 16, 32],
405
- "variance": [0.1, 0.2],
406
- "clip": False,
407
- "loc_weight": 2.0,
408
- "gpu_train": True,
409
- "batch_size": 24,
410
- "ngpu": 4,
411
- "epoch": 100,
412
- "decay1": 70,
413
- "decay2": 90,
414
- "image_size": 840,
415
- "pretrain": False,
416
- "return_layers": {"layer2": 1, "layer3": 2, "layer4": 3},
417
- "in_channel": 256,
418
- "out_channel": 256,
419
- }
420
-
421
-
422
- def check_keys(model, pretrained_state_dict):
423
- ckpt_keys = set(pretrained_state_dict.keys())
424
- model_keys = set(model.state_dict().keys())
425
- used_pretrained_keys = model_keys & ckpt_keys
426
- assert len(used_pretrained_keys) > 0, "load NONE from pretrained checkpoint"
427
- return True
428
-
429
-
430
- def remove_prefix(state_dict, prefix):
431
- """ Old style model is stored with all names of parameters sharing common prefix 'module.' """
432
- f = lambda x: x.split(prefix, 1)[-1] if x.startswith(prefix) else x
433
- return {f(key): value for key, value in state_dict.items()}
434
-
435
-
436
- def load_model(model, pretrained_path, load_to_cpu):
437
- if load_to_cpu:
438
- if pretrained_path is None:
439
- url = "https://github.com/yinglinzheng/face_weights/releases/download/v1/mobilenet0.25_Final.pth"
440
- pretrained_dict = torch.utils.model_zoo.load_url(url)
441
- else:
442
- pretrained_dict = torch.load(
443
- pretrained_path, map_location=lambda storage, loc: storage
444
- )
445
- else:
446
- device = torch.cuda.current_device()
447
- pretrained_dict = torch.load(
448
- pretrained_path, map_location=lambda storage, loc: storage.cuda(device)
449
- )
450
- if "state_dict" in pretrained_dict.keys():
451
- pretrained_dict = remove_prefix(pretrained_dict["state_dict"], "module.")
452
- else:
453
- pretrained_dict = remove_prefix(pretrained_dict, "module.")
454
- check_keys(model, pretrained_dict)
455
- model.load_state_dict(pretrained_dict, strict=False)
456
- return model
457
-
458
-
459
- def load_net(model_path, device, network="mobilenet"):
460
- if network == "mobilenet":
461
- cfg = cfg_mnet
462
- elif network == "resnet50":
463
- cfg = cfg_re50
464
- # net and model
465
- net = RetinaFace(cfg=cfg, phase="test")
466
- net = load_model(net, model_path, True)
467
- net.eval()
468
- cudnn.benchmark = True
469
- net = net.to(device)
470
- return net
471
-
472
-
473
- def parse_det(det):
474
- landmarks = det[5:].reshape(5, 2)
475
- box = det[:4]
476
- score = det[4]
477
- return box, landmarks, score
478
-
479
-
480
- def post_process(
481
- loc,
482
- conf,
483
- landms,
484
- prior_data,
485
- cfg,
486
- scale,
487
- scale1,
488
- resize,
489
- confidence_threshold,
490
- top_k,
491
- nms_threshold,
492
- keep_top_k,
493
- ):
494
- boxes = decode(loc, prior_data, cfg["variance"])
495
- boxes = boxes * scale / resize
496
- boxes = boxes.cpu().numpy()
497
- scores = conf.cpu().numpy()[:, 1]
498
- landms_copy = decode_landm(landms, prior_data, cfg["variance"])
499
-
500
- landms_copy = landms_copy * scale1 / resize
501
- landms_copy = landms_copy.cpu().numpy()
502
-
503
- # ignore low scores
504
- inds = np.where(scores > confidence_threshold)[0]
505
- boxes = boxes[inds]
506
- landms_copy = landms_copy[inds]
507
- scores = scores[inds]
508
-
509
- # keep top-K before NMS
510
- order = scores.argsort()[::-1][:top_k]
511
- boxes = boxes[order]
512
- landms_copy = landms_copy[order]
513
- scores = scores[order]
514
-
515
- # do NMS
516
- dets = np.hstack((boxes, scores[:, np.newaxis])).astype(np.float32, copy=False)
517
- keep = py_cpu_nms(dets, nms_threshold)
518
- # keep = nms(dets, args.nms_threshold,force_cpu=args.cpu)
519
- dets = dets[keep, :]
520
- landms_copy = landms_copy[keep]
521
-
522
- # keep top-K faster NMS
523
- dets = dets[:keep_top_k, :]
524
- landms_copy = landms_copy[:keep_top_k, :]
525
-
526
- dets = np.concatenate((dets, landms_copy), axis=1)
527
- # show image
528
- dets = sorted(dets, key=lambda x: x[4], reverse=True)
529
- dets = [parse_det(x) for x in dets]
530
-
531
- return dets
532
-
533
-
534
- def batch_detect(net, images, device, is_tensor=False, normalized=False):
535
- with torch.no_grad():
536
- confidence_threshold = 0.02
537
- cfg = cfg_mnet
538
- top_k = 5000
539
- nms_threshold = 0.4
540
- keep_top_k = 750
541
- resize = 1
542
- if not is_tensor:
543
- try:
544
- img = np.float32(images)
545
- except ValueError:
546
- raise NotImplementedError("Input images must of same size")
547
- img = torch.from_numpy(img)
548
- else:
549
- img = images.float()
550
- img = img.to(device)
551
- mean = (
552
- torch.as_tensor([104, 117, 123], dtype=img.dtype, device=img.device)
553
- .unsqueeze(0)
554
- .unsqueeze(0)
555
- .unsqueeze(0)
556
- )
557
- img -= mean
558
- img = img.permute(0, 3, 1, 2)
559
- (batch_size, _, im_height, im_width,) = img.shape
560
- scale = torch.as_tensor(
561
- [im_width, im_height, im_width, im_height],
562
- dtype=img.dtype,
563
- device=img.device,
564
- )
565
- scale = scale.to(device)
566
-
567
- loc, conf, landms = net(img) # forward pass
568
-
569
- priorbox = PriorBox(cfg, image_size=(im_height, im_width))
570
- priors = priorbox.forward()
571
- prior_data = priors.to(device)
572
- scale1 = torch.as_tensor(
573
- [
574
- img.shape[3],
575
- img.shape[2],
576
- img.shape[3],
577
- img.shape[2],
578
- img.shape[3],
579
- img.shape[2],
580
- img.shape[3],
581
- img.shape[2],
582
- img.shape[3],
583
- img.shape[2],
584
- ],
585
- dtype=img.dtype,
586
- device=img.device,
587
- )
588
- scale1 = scale1.to(device)
589
-
590
- all_dets = [
591
- post_process(
592
- loc_i,
593
- conf_i,
594
- landms_i,
595
- prior_data,
596
- cfg,
597
- scale,
598
- scale1,
599
- resize,
600
- confidence_threshold,
601
- top_k,
602
- nms_threshold,
603
- keep_top_k,
604
- )
605
- for loc_i, conf_i, landms_i in zip(loc, conf, landms)
606
- ]
607
-
608
- return all_dets
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
video/pwtf-dvd/model_code/inference/test_tools/ct/detection/detector.py DELETED
@@ -1,46 +0,0 @@
1
- import os
2
-
3
- import numpy as np
4
- import torch
5
-
6
- from .alignment import load_net, batch_detect
7
-
8
-
9
- def get_project_dir():
10
- current_path = os.path.abspath(os.path.join(__file__, "../"))
11
- return current_path
12
-
13
-
14
- def relative(path):
15
- path = os.path.join(get_project_dir(), path)
16
- return os.path.abspath(path)
17
-
18
-
19
- class RetinaFace:
20
- def __init__(
21
- self, gpu_id=-1, model_path=None, network="mobilenet",
22
- ):
23
- self.gpu_id = gpu_id
24
- self.device = (
25
- torch.device("cpu") if gpu_id == -1 else torch.device("cuda", gpu_id)
26
- )
27
- self.model = load_net(model_path, self.device, network)
28
-
29
- def detect(self, images):
30
- if isinstance(images, np.ndarray):
31
- if len(images.shape) == 3:
32
- return batch_detect(self.model, [images], self.device)[0]
33
- elif len(images.shape) == 4:
34
- return batch_detect(self.model, images, self.device)
35
- elif isinstance(images, list):
36
- return batch_detect(self.model, np.array(images), self.device)
37
- elif isinstance(images, torch.Tensor):
38
- if len(images.shape) == 3:
39
- return batch_detect(self.model, images.unsqueeze(0), self.device)[0]
40
- elif len(images.shape) == 4:
41
- return batch_detect(self.model, images, self.device)
42
- else:
43
- raise NotImplementedError()
44
-
45
- def __call__(self, images):
46
- return self.detect(images)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
video/pwtf-dvd/model_code/inference/test_tools/ct/detection/utils.py DELETED
@@ -1,146 +0,0 @@
1
- import cv2
2
- from test_tools.utils import flatten
3
- import numpy as np
4
-
5
-
6
- def chunks(l, n, step=None):
7
- if step is None:
8
- step = n
9
- return [l[i : i + n] for i in range(0, len(l), step)]
10
-
11
-
12
- def sample_chunks(l, n, step=None):
13
- return [l[i : i + n] for i in range(0, len(l), step) if i + n <= len(l)]
14
-
15
-
16
- def grab_all_frames(path, max_size, cvt=False):
17
- capture = cv2.VideoCapture(path)
18
- ret = True
19
- frames = []
20
- while ret:
21
- ret, frame = capture.read()
22
- if ret:
23
- if cvt:
24
- frame = frame[..., ::-1]
25
- frames.append(frame)
26
- if len(frames) == max_size:
27
- break
28
- capture.release()
29
- return frames
30
-
31
-
32
- def get_clips_uniform(path, count, clip_size):
33
- capture = cv2.VideoCapture(path)
34
- n_frames = int(capture.get(cv2.CAP_PROP_FRAME_COUNT))
35
- max_clip_available = n_frames + 1 - clip_size
36
- if count > max_clip_available:
37
- count = max_clip_available
38
- final_start = max_clip_available - 1
39
- start_indices = np.linspace(0, final_start, count, endpoint=True, dtype=np.int)
40
- all_clip_idx = [list(range(start, start + clip_size)) for start in start_indices]
41
- valid = set(flatten(all_clip_idx))
42
- max_idx = max(valid)
43
-
44
- frames = {}
45
- for idx in range(max_idx + 1):
46
- # Get the next frame, but don't decode if we're not using it.
47
- ret = capture.grab()
48
- if not ret:
49
- continue
50
-
51
- if idx in valid:
52
- ret, frame = capture.retrieve()
53
- if not ret or frame is None:
54
- continue
55
- else:
56
- # frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
57
- frames[idx] = frame
58
-
59
- capture.release()
60
- clips = []
61
- for clip_idx in all_clip_idx:
62
- clip = []
63
- flag = True
64
- for idx in clip_idx:
65
- if idx not in frames:
66
- flag = False
67
- break
68
- clip.append(frames[idx])
69
- if flag:
70
- clips.append(clip)
71
- return clips
72
-
73
-
74
- def get_valid_faces(detect_results, max_count=10, thres=0.5, at_least=False):
75
- new_results = []
76
- for i, faces in enumerate(detect_results):
77
- if len(faces) > max_count:
78
- faces = faces[:max_count]
79
- l = []
80
- for j, face in enumerate(faces):
81
- if face[-1] < thres and not (j == 0 and at_least):
82
- continue
83
- box, lm, score = face
84
- box = box.astype(np.float32)
85
- lm = lm.astype(np.float32)
86
- l.append((box, lm, score))
87
- new_results.append(l)
88
- return new_results
89
-
90
-
91
- def scale_box(box, scale_h, scale_w, h, w):
92
- x1, y1, x2, y2 = box.astype(np.int32)
93
- center_x = (x1 + x2) // 2
94
- center_y = (y1 + y2) // 2
95
- box_h = int((y2 - y1) * scale_h)
96
- box_w = int((x2 - x1) * scale_w)
97
- new_x1 = center_x - box_w // 2
98
- new_x2 = new_x1 + box_w
99
- new_y1 = center_y - box_h // 2
100
- new_y2 = new_y1 + box_h
101
- new_x1 = max(new_x1, 0)
102
- new_y1 = max(new_y1, 0)
103
- new_y2 = min(new_y2, h)
104
- new_x2 = min(new_x2, w)
105
- return new_x1, new_y1, new_x2, new_y2
106
-
107
-
108
- def get_bbox(detect_res):
109
- tmp_detect_res = get_valid_faces(detect_res, max_count=4, thres=0.5)
110
- all_face_bboxs = []
111
- for faces in tmp_detect_res:
112
- all_face_bboxs.extend([face[0] for face in faces])
113
- all_face_bboxs = np.array(all_face_bboxs).astype(np.int)
114
- x1 = all_face_bboxs[:, 0].min()
115
- x2 = all_face_bboxs[:, 2].max()
116
- y1 = all_face_bboxs[:, 1].min()
117
- y2 = all_face_bboxs[:, 3].max()
118
-
119
- return x1, y1, x2, y2
120
-
121
-
122
- def delta_detect_res(detect_res, x1, y1):
123
- diff = np.array([[x1, y1]])
124
- new_detect_res = []
125
- for faces in detect_res:
126
- f = []
127
- for face in faces:
128
- box, lm, score = face
129
- box = box.astype(np.float)
130
- box[[0, 2]] -= x1
131
- box[[1, 3]] -= y1
132
- lm = lm.astype(np.float) - diff
133
- f.append((box, lm, score))
134
- new_detect_res.append(f)
135
- return new_detect_res
136
-
137
-
138
- def pre_crop(clips, detect_res):
139
- box = np.array(get_bbox(detect_res))
140
- w = box[2] - box[0]
141
- h = box[3] - box[1]
142
- x1, y1, x2, y2 = scale_box(
143
- box, 1.5, 1.2 if w > 2 * h else 1.5, clips[0].shape[0], clips[0].shape[1]
144
- )
145
- clips = np.array(clips)
146
- return clips[:, y1:y2, x1:x2], delta_detect_res(detect_res, x1, y1)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
video/pwtf-dvd/model_code/inference/test_tools/ct/face_alignment/__init__.py DELETED
@@ -1 +0,0 @@
1
- from .predictor import LandmarkPredictor
 
 
video/pwtf-dvd/model_code/inference/test_tools/ct/face_alignment/basenet.py DELETED
@@ -1,107 +0,0 @@
1
- # Backbone networks used for face landmark detection
2
- # Cunjian Chen (cunjian@msu.edu)
3
-
4
- import torch.nn as nn
5
- import torchvision.models as models
6
-
7
-
8
- class ConvBlock(nn.Module):
9
- def __init__(self, inp, oup, k, s, p, dw=False, linear=False):
10
- super(ConvBlock, self).__init__()
11
- self.linear = linear
12
- if dw:
13
- self.conv = nn.Conv2d(inp, oup, k, s, p, groups=inp, bias=False)
14
- else:
15
- self.conv = nn.Conv2d(inp, oup, k, s, p, bias=False)
16
- self.bn = nn.BatchNorm2d(oup)
17
- if not linear:
18
- self.prelu = nn.PReLU(oup)
19
-
20
- def forward(self, x):
21
- x = self.conv(x)
22
- x = self.bn(x)
23
- if self.linear:
24
- return x
25
- else:
26
- return self.prelu(x)
27
-
28
-
29
- # SE module
30
- # https://github.com/wujiyang/Face_Pytorch/blob/master/backbone/cbam.py
31
- class SEModule(nn.Module):
32
- """Squeeze and Excitation Module"""
33
-
34
- def __init__(self, channels, reduction):
35
- super(SEModule, self).__init__()
36
- self.avg_pool = nn.AdaptiveAvgPool2d(1)
37
- self.fc1 = nn.Conv2d(
38
- channels, channels // reduction, kernel_size=1, padding=0, bias=False
39
- )
40
- self.relu = nn.ReLU(inplace=True)
41
- self.fc2 = nn.Conv2d(
42
- channels // reduction, channels, kernel_size=1, padding=0, bias=False
43
- )
44
- self.sigmoid = nn.Sigmoid()
45
-
46
- def forward(self, x):
47
- input = x
48
- x = self.avg_pool(x)
49
- x = self.fc1(x)
50
- x = self.relu(x)
51
- x = self.fc2(x)
52
- x = self.sigmoid(x)
53
-
54
- return input * x
55
-
56
-
57
- # USE global depthwise convolution layer. Compatible with MobileNetV2 (224×224), MobileNetV2_ExternalData (224×224)
58
- class MobileNet_GDConv(nn.Module):
59
- def __init__(self, num_classes):
60
- super(MobileNet_GDConv, self).__init__()
61
- self.pretrain_net = models.mobilenet_v2(pretrained=False)
62
- self.base_net = nn.Sequential(*list(self.pretrain_net.children())[:-1])
63
- self.linear7 = ConvBlock(1280, 1280, (7, 7), 1, 0, dw=True, linear=True)
64
- self.linear1 = ConvBlock(1280, num_classes, 1, 1, 0, linear=True)
65
-
66
- def forward(self, x):
67
- x = self.base_net(x)
68
- x = self.linear7(x)
69
- x = self.linear1(x)
70
- x = x.view(x.size(0), -1)
71
- return x
72
-
73
-
74
- # USE global depthwise convolution layer. Compatible with MobileNetV2 (56×56)
75
- class MobileNet_GDConv_56(nn.Module):
76
- def __init__(self, num_classes):
77
- super(MobileNet_GDConv_56, self).__init__()
78
- self.pretrain_net = models.mobilenet_v2(pretrained=False)
79
- self.base_net = nn.Sequential(*list(self.pretrain_net.children())[:-1])
80
- self.linear7 = ConvBlock(1280, 1280, (2, 2), 1, 0, dw=True, linear=True)
81
- self.linear1 = ConvBlock(1280, num_classes, 1, 1, 0, linear=True)
82
-
83
- def forward(self, x):
84
- x = self.base_net(x)
85
- x = self.linear7(x)
86
- x = self.linear1(x)
87
- x = x.view(x.size(0), -1)
88
- return x
89
-
90
-
91
- # MobileNetV2 with SE; Compatible with MobileNetV2_SE (224×224) and MobileNetV2_SE_RE (224×224)
92
- class MobileNet_GDConv_SE(nn.Module):
93
- def __init__(self, num_classes):
94
- super(MobileNet_GDConv_SE, self).__init__()
95
- self.pretrain_net = models.mobilenet_v2(pretrained=True)
96
- self.base_net = nn.Sequential(*list(self.pretrain_net.children())[:-1])
97
- self.linear7 = ConvBlock(1280, 1280, (7, 7), 1, 0, dw=True, linear=True)
98
- self.linear1 = ConvBlock(1280, num_classes, 1, 1, 0, linear=True)
99
- self.attention = SEModule(1280, 8)
100
-
101
- def forward(self, x):
102
- x = self.base_net(x)
103
- x = self.attention(x)
104
- x = self.linear7(x)
105
- x = self.linear1(x)
106
- x = x.view(x.size(0), -1)
107
- return x
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
video/pwtf-dvd/model_code/inference/test_tools/ct/face_alignment/predictor.py DELETED
@@ -1,143 +0,0 @@
1
- # Face alignment demo
2
- # Uses MTCNN as face detector
3
- # Cunjian Chen (ccunjian@gmail.com)
4
- import torch
5
- import cv2
6
- import numpy as np
7
- from torch.utils.data import DataLoader
8
- from .basenet import MobileNet_GDConv
9
-
10
-
11
- def get_device(gpu_id):
12
- if gpu_id > -1:
13
- return torch.device(f"cuda:{str(gpu_id)}")
14
- else:
15
- return torch.device("cpu")
16
-
17
-
18
- def load_model(file):
19
- model = MobileNet_GDConv(136)
20
- if file is not None:
21
- model.load_state_dict(torch.load(file, map_location="cpu"))
22
- else:
23
- url = "https://github.com/yinglinzheng/face_weights/releases/download/v1/mobilenet_224_model_best_gdconv_external.pth"
24
- model.load_state_dict(torch.utils.model_zoo.load_url(url))
25
- return model
26
-
27
-
28
- # landmark of (5L, 2L) from [0,1] to real range
29
- def reproject(bbox, landmark):
30
- landmark_ = landmark.clone()
31
- x1, y1, x2, y2 = bbox
32
- w = x2 - x1
33
- h = y2 - y1
34
- landmark_[:, 0] *= w
35
- landmark_[:, 0] += x1
36
- landmark_[:, 1] *= h
37
- landmark_[:, 1] += y1
38
- return landmark_
39
-
40
-
41
- def prepare_feed(img, face):
42
- height, width, _ = img.shape
43
- mean = np.asarray([0.485, 0.456, 0.406])
44
- std = np.asarray([0.229, 0.224, 0.225])
45
- out_size = 224
46
- x1, y1, x2, y2 = face[:4]
47
-
48
- w = x2 - x1 + 1
49
- h = y2 - y1 + 1
50
- size = int(min([w, h]) * 1.2)
51
- cx = x1 + w // 2
52
- cy = y1 + h // 2
53
- x1 = cx - size // 2
54
- x2 = x1 + size
55
- y1 = cy - size // 2
56
- y2 = y1 + size
57
-
58
- dx = max(0, -x1)
59
- dy = max(0, -y1)
60
- x1 = max(0, x1)
61
- y1 = max(0, y1)
62
-
63
- edx = max(0, x2 - width)
64
- edy = max(0, y2 - height)
65
- x2 = min(width, x2)
66
- y2 = min(height, y2)
67
- new_bbox = torch.Tensor([x1, y1, x2, y2]).int()
68
- x1, y1, x2, y2 = new_bbox
69
- cropped = img[y1:y2, x1:x2]
70
- if dx > 0 or dy > 0 or edx > 0 or edy > 0:
71
- cropped = cv2.copyMakeBorder(
72
- cropped, int(dy), int(edy), int(dx), int(edx), cv2.BORDER_CONSTANT, 0
73
- )
74
- cropped_face = cv2.resize(cropped, (out_size, out_size))
75
-
76
- if cropped_face.shape[0] <= 0 or cropped_face.shape[1] <= 0:
77
- return None
78
- test_face = cropped_face.copy()
79
- test_face = test_face / 255.0
80
- test_face = (test_face - mean) / std
81
- test_face = test_face.transpose((2, 0, 1))
82
- data = torch.from_numpy(test_face).float()
83
- return dict(data=data, bbox=new_bbox)
84
-
85
-
86
- @torch.no_grad()
87
- def single_predict(model, feed, device):
88
- landmark = model(feed["data"].unsqueeze(0).to(device)).cpu()
89
- landmark = landmark.reshape(-1, 2)
90
- landmark = reproject(feed["bbox"], landmark)
91
- return landmark.numpy()
92
-
93
-
94
- @torch.no_grad()
95
- def batch_predict(model, feeds, device):
96
- if not isinstance(feeds, list):
97
- feeds = [feeds]
98
- # loader = DataLoader(FeedDataset(feeds), batch_size=50, shuffle=False)
99
- data = []
100
- for feed in feeds:
101
- data.append(feed["data"].unsqueeze(0))
102
- data = torch.cat(data, 0).to(device)
103
- results = []
104
-
105
- landmarks = model(data).cpu()
106
- for landmark, feed in zip(landmarks, feeds):
107
- landmark = landmark.reshape(-1, 2)
108
- landmark = reproject(feed["bbox"], landmark)
109
- results.append(landmark.numpy())
110
- return results
111
-
112
-
113
- @torch.no_grad()
114
- def batch_predict2(model, feeds, device, batch_size=None):
115
- if not isinstance(feeds, list):
116
- feeds = [feeds]
117
- if batch_size is None:
118
- batch_size = len(feeds)
119
- loader = DataLoader(feeds, batch_size=len(feeds), shuffle=False)
120
- results = []
121
- for feed in loader:
122
- landmarks = model(feed["data"].to(device)).cpu()
123
- for landmark, bbox in zip(landmarks, feed["bbox"]):
124
- landmark = landmark.reshape(-1, 2)
125
- landmark = reproject(bbox, landmark)
126
- results.append(landmark.numpy())
127
- return results
128
-
129
-
130
- class LandmarkPredictor:
131
- def __init__(self, gpu_id=0, file=None):
132
- self.device = get_device(gpu_id)
133
- self.model = load_model(file).to(self.device).eval()
134
-
135
- def __call__(self, feeds):
136
- results = batch_predict2(self.model, feeds, self.device)
137
- if not isinstance(feeds, list):
138
- results = results[0]
139
- return results
140
-
141
- @staticmethod
142
- def prepare_feed(img, face):
143
- return prepare_feed(img, face)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
video/pwtf-dvd/model_code/inference/test_tools/ct/face_alignment/utils.py DELETED
@@ -1,17 +0,0 @@
1
- import cv2
2
-
3
-
4
- def drawLandmark_multiple(img, bbox, landmark):
5
- """
6
- Input:
7
- - img: gray or RGB
8
- - bbox: type of BBox
9
- - landmark: reproject landmark of (5L, 2L)
10
- Output:
11
- - img marked with landmark and bbox
12
- """
13
- x1, y1, x2, y2 = bbox
14
- cv2.rectangle(img, (x1, y1), (x2, y2), (0, 0, 255), 2)
15
- for x, y in landmark:
16
- cv2.circle(img, (int(x), int(y)), 2, (0, 255, 0), -1)
17
- return img
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
video/pwtf-dvd/model_code/inference/test_tools/ct/operations.py DELETED
@@ -1,79 +0,0 @@
1
- import os
2
-
3
- import os
4
- import cv2
5
- import numpy as np
6
- from .tracking.sort import iou
7
-
8
-
9
- def face_iou(f1, f2):
10
- return iou(f1[0], f2[0])
11
-
12
-
13
- def simple_tracking(batch_landmarks, index=0, thres=0.5):
14
- track = []
15
-
16
- for i, faces in enumerate(batch_landmarks):
17
- if i == 0:
18
- if len(faces) <= index or faces[index][-1] < 0.8:
19
- return None
20
- if index != 0:
21
- for idx in range(index):
22
- if face_iou(faces[idx], faces[index]) > thres:
23
- return None
24
- track.append(faces[index])
25
- else:
26
- last = track[i - 1]
27
- if len(faces) == 0:
28
- return None
29
- sorted_faces = sorted(faces, key=lambda x: face_iou(x, last), reverse=True)
30
- if face_iou(sorted_faces[0], last) < thres:
31
- return None
32
- track.append(sorted_faces[0])
33
- return track
34
-
35
-
36
- def multiple_tracking(batch_landmarks):
37
- tracks = []
38
- for i in range(len(batch_landmarks[0])):
39
- track = simple_tracking(batch_landmarks, index=i)
40
- if track is None:
41
- continue
42
- tracks.append(track)
43
- return tracks
44
-
45
- def find_longest(detect_res):
46
- fc = len(detect_res)
47
- tuples = []
48
- start = 0
49
- end = 0
50
- previous_count = -1
51
- all_tracks = []
52
- # start 取得到,end 取不到
53
- while start < (fc - 1):
54
- for end in range(start + 2, fc + 1):
55
- tracks = multiple_tracking(detect_res[start:end])
56
- if (len(tracks) != previous_count and previous_count != -1) or len(
57
- tracks
58
- ) == 0:
59
- break
60
- previous_count = len(tracks)
61
- if end - start > 2:
62
- if end != fc:
63
- un_reach_end = end - 1
64
- else:
65
- un_reach_end = end
66
- sub_tracks = multiple_tracking(detect_res[start:un_reach_end])
67
- if end == fc and len(sub_tracks) == 0:
68
- un_reach_end = end - 1
69
- sub_tracks = multiple_tracking(detect_res[start:un_reach_end])
70
- if len(sub_tracks) > 0:
71
- tpl = (start, un_reach_end)
72
- tuples.append(tpl)
73
- all_tracks.append(sub_tracks[0])
74
- else:
75
- raise NotImplementedError
76
- previous_count = -1
77
- end = un_reach_end
78
- start = end
79
- return tuples, all_tracks
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
video/pwtf-dvd/model_code/inference/test_tools/ct/tracking/__init__.py DELETED
File without changes
video/pwtf-dvd/model_code/inference/test_tools/ct/tracking/sort.py DELETED
@@ -1,285 +0,0 @@
1
- """
2
- SORT: A Simple, Online and Realtime Tracker
3
- Copyright (C) 2016 Alex Bewley alex@dynamicdetection.com
4
-
5
- This program is free software: you can redistribute it and/or modify
6
- it under the terms of the GNU General Public License as published by
7
- the Free Software Foundation, either version 3 of the License, or
8
- (at your option) any later version.
9
-
10
- This program is distributed in the hope that it will be useful,
11
- but WITHOUT ANY WARRANTY; without even the implied warranty of
12
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
- GNU General Public License for more details.
14
-
15
- You should have received a copy of the GNU General Public License
16
- along with this program. If not, see <http://www.gnu.org/licenses/>.
17
- """
18
- from __future__ import print_function
19
- import os.path
20
- import numpy as np
21
- import matplotlib.pyplot as plt
22
- import matplotlib.patches as patches
23
- from scipy.optimize import linear_sum_assignment
24
- import glob
25
- import time
26
- import argparse
27
- from filterpy.kalman import KalmanFilter
28
-
29
-
30
- def iou(bb_test, bb_gt):
31
- """
32
- Computes IUO between two bboxes in the form [x1,y1,x2,y2]
33
- """
34
- xx1 = np.maximum(bb_test[0], bb_gt[0])
35
- yy1 = np.maximum(bb_test[1], bb_gt[1])
36
- xx2 = np.minimum(bb_test[2], bb_gt[2])
37
- yy2 = np.minimum(bb_test[3], bb_gt[3])
38
- w = np.maximum(0.0, xx2 - xx1)
39
- h = np.maximum(0.0, yy2 - yy1)
40
- wh = w * h
41
- o = wh / (
42
- (bb_test[2] - bb_test[0]) * (bb_test[3] - bb_test[1])
43
- + (bb_gt[2] - bb_gt[0]) * (bb_gt[3] - bb_gt[1])
44
- - wh
45
- )
46
- return o
47
-
48
-
49
- def convert_bbox_to_z(bbox):
50
- """
51
- Takes a bounding box in the form [x1,y1,x2,y2] and returns z in the form
52
- [x,y,s,r] where x,y is the centre of the box and s is the scale/area and r is
53
- the aspect ratio
54
- """
55
- w = bbox[2] - bbox[0]
56
- h = bbox[3] - bbox[1]
57
- x = bbox[0] + w / 2.0
58
- y = bbox[1] + h / 2.0
59
- s = w * h # scale is just area
60
- r = w / float(h)
61
- return np.array([x, y, s, r]).reshape((4, 1))
62
-
63
-
64
- def convert_x_to_bbox(x, score=None):
65
- """
66
- Takes a bounding box in the centre form [x,y,s,r] and returns it in the form
67
- [x1,y1,x2,y2] where x1,y1 is the top left and x2,y2 is the bottom right
68
- """
69
- w = np.sqrt(x[2] * x[3])
70
- h = x[2] / w
71
- if score == None:
72
- return np.array(
73
- [x[0] - w / 2.0, x[1] - h / 2.0, x[0] + w / 2.0, x[1] + h / 2.0]
74
- ).reshape((1, 4))
75
- else:
76
- return np.array(
77
- [x[0] - w / 2.0, x[1] - h / 2.0, x[0] + w / 2.0, x[1] + h / 2.0, score]
78
- ).reshape((1, 5))
79
-
80
-
81
- class KalmanBoxTracker(object):
82
- """
83
- This class represents the internel state of individual tracked objects observed as bbox.
84
- """
85
-
86
- count = 0
87
-
88
- def __init__(self, bbox):
89
- """
90
- Initialises a tracker using initial bounding box.
91
- """
92
- # define constant velocity model
93
- self.kf = KalmanFilter(dim_x=7, dim_z=4)
94
- self.kf.F = np.array(
95
- [
96
- [1, 0, 0, 0, 1, 0, 0],
97
- [0, 1, 0, 0, 0, 1, 0],
98
- [0, 0, 1, 0, 0, 0, 1],
99
- [0, 0, 0, 1, 0, 0, 0],
100
- [0, 0, 0, 0, 1, 0, 0],
101
- [0, 0, 0, 0, 0, 1, 0],
102
- [0, 0, 0, 0, 0, 0, 1],
103
- ]
104
- )
105
- self.kf.H = np.array(
106
- [
107
- [1, 0, 0, 0, 0, 0, 0],
108
- [0, 1, 0, 0, 0, 0, 0],
109
- [0, 0, 1, 0, 0, 0, 0],
110
- [0, 0, 0, 1, 0, 0, 0],
111
- ]
112
- )
113
-
114
- self.kf.R[2:, 2:] *= 10.0
115
- self.kf.P[
116
- 4:, 4:
117
- ] *= 1000.0 # give high uncertainty to the unobservable initial velocities
118
- self.kf.P *= 10.0
119
- self.kf.Q[-1, -1] *= 0.01
120
- self.kf.Q[4:, 4:] *= 0.01
121
-
122
- self.kf.x[:4] = convert_bbox_to_z(bbox)
123
- self.time_since_update = 0
124
- self.id = KalmanBoxTracker.count
125
- KalmanBoxTracker.count += 1
126
- self.history = []
127
- self.hits = 0
128
- self.hit_streak = 0
129
- self.age = 0
130
-
131
- def update(self, bbox):
132
- """
133
- Updates the state vector with observed bbox.
134
- """
135
- self.time_since_update = 0
136
- self.history = []
137
- self.hits += 1
138
- self.hit_streak += 1
139
- self.kf.update(convert_bbox_to_z(bbox))
140
-
141
- def predict(self):
142
- """
143
- Advances the state vector and returns the predicted bounding box estimate.
144
- """
145
- if (self.kf.x[6] + self.kf.x[2]) <= 0:
146
- self.kf.x[6] *= 0.0
147
- self.kf.predict()
148
- self.age += 1
149
- if self.time_since_update > 0:
150
- self.hit_streak = 0
151
- self.time_since_update += 1
152
- self.history.append(convert_x_to_bbox(self.kf.x))
153
- return self.history[-1]
154
-
155
- def get_state(self):
156
- """
157
- Returns the current bounding box estimate.
158
- """
159
- return convert_x_to_bbox(self.kf.x)
160
-
161
-
162
- def associate_detections_to_trackers(detections, trackers, iou_threshold=0.3):
163
- """
164
- Assigns detections to tracked object (both represented as bounding boxes)
165
-
166
- Returns 3 lists of matches, unmatched_detections and unmatched_trackers
167
- """
168
- if len(trackers) == 0:
169
- return (
170
- np.empty((0, 2), dtype=int),
171
- np.arange(len(detections)),
172
- np.empty((0, 5), dtype=int),
173
- )
174
- iou_matrix = np.zeros((len(detections), len(trackers)), dtype=np.float32)
175
-
176
- for d, det in enumerate(detections):
177
- for t, trk in enumerate(trackers):
178
- iou_matrix[d, t] = iou(det, trk)
179
-
180
- matched_indices = linear_sum_assignment(-iou_matrix)
181
- matched_indices = np.array(list(zip(*matched_indices)), dtype=np.int)
182
- matched_indices.shape = (-1, 2)
183
- # print(matched_indices)
184
- # print(type(matched_indices))
185
-
186
- unmatched_detections = []
187
- for d, det in enumerate(detections):
188
- if d not in matched_indices[:, 0]:
189
- unmatched_detections.append(d)
190
- unmatched_trackers = []
191
- for t, trk in enumerate(trackers):
192
- if t not in matched_indices[:, 1]:
193
- unmatched_trackers.append(t)
194
-
195
- # filter out matched with low IOU
196
- matches = []
197
- for m in matched_indices:
198
- if iou_matrix[m[0], m[1]] < iou_threshold:
199
- unmatched_detections.append(m[0])
200
- unmatched_trackers.append(m[1])
201
- else:
202
- matches.append(m.reshape(1, 2))
203
- if len(matches) == 0:
204
- matches = np.empty((0, 2), dtype=int)
205
- else:
206
- matches = np.concatenate(matches, axis=0)
207
-
208
- return matches, np.array(unmatched_detections), np.array(unmatched_trackers)
209
-
210
-
211
- class Sort(object):
212
- def __init__(self, max_age=1, min_hits=3):
213
- """
214
- Sets key parameters for SORT
215
- """
216
- self.max_age = max_age
217
- self.min_hits = min_hits
218
- self.trackers = []
219
- self.frame_count = 0
220
-
221
- def update(self, dets):
222
- """
223
- Params:
224
- dets - a numpy array of detections in the format [[x1,y1,x2,y2,score],[x1,y1,x2,y2,score],...]
225
- Requires: this method must be called once for each frame even with empty detections.
226
- Returns the a similar array, where the last column is the object ID.
227
-
228
- NOTE: The number of objects returned may differ from the number of detections provided.
229
- """
230
- self.frame_count += 1
231
- # get predicted locations from existing trackers.
232
- trks = np.zeros((len(self.trackers), 5))
233
- to_del = []
234
- ret = []
235
- for t, trk in enumerate(trks):
236
- pos = self.trackers[t].predict()[0]
237
- trk[:] = [pos[0], pos[1], pos[2], pos[3], 0]
238
- if np.any(np.isnan(pos)):
239
- to_del.append(t)
240
- trks = np.ma.compress_rows(np.ma.masked_invalid(trks))
241
- for t in reversed(to_del):
242
- self.trackers.pop(t)
243
- matched, unmatched_dets, unmatched_trks = associate_detections_to_trackers(
244
- dets, trks
245
- )
246
-
247
- # update matched trackers with assigned detections
248
- for t, trk in enumerate(self.trackers):
249
- if t not in unmatched_trks:
250
- d = matched[np.where(matched[:, 1] == t)[0], 0]
251
- trk.update(dets[d, :][0])
252
-
253
- # create and initialise new trackers for unmatched detections
254
- for i in unmatched_dets:
255
- trk = KalmanBoxTracker(dets[i, :])
256
- self.trackers.append(trk)
257
- i = len(self.trackers)
258
- for trk in reversed(self.trackers):
259
- d = trk.get_state()[0]
260
- if (trk.time_since_update < 1) and (
261
- trk.hit_streak >= self.min_hits or self.frame_count <= self.min_hits
262
- ):
263
- ret.append(
264
- np.concatenate((d, [trk.id + 1])).reshape(1, -1)
265
- ) # +1 as MOT benchmark requires positive
266
- i -= 1
267
- # remove dead tracklet
268
- if trk.time_since_update > self.max_age:
269
- self.trackers.pop(i)
270
- if len(ret) > 0:
271
- return np.concatenate(ret)
272
- return np.empty((0, 5))
273
-
274
-
275
- def parse_args():
276
- """Parse input arguments."""
277
- parser = argparse.ArgumentParser(description="SORT demo")
278
- parser.add_argument(
279
- "--display",
280
- dest="display",
281
- help="Display online tracker output (slow) [False]",
282
- action="store_true",
283
- )
284
- args = parser.parse_args()
285
- return args
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
video/pwtf-dvd/model_code/inference/test_tools/ct/tracking/tracker.py DELETED
@@ -1,27 +0,0 @@
1
- from .sort import Sort
2
- import numpy as np
3
-
4
-
5
- def get_detections(faces):
6
- detections = []
7
- for face in faces:
8
- x1, y1, x2, y2 = face[0]
9
- detections.append((x1, y1, x2, y2, face[-1]))
10
- return np.array(detections)
11
-
12
-
13
- def get_tracks(detect_results):
14
- tracks = {}
15
- mot_tracker = Sort()
16
- for faces in detect_results:
17
- detections = get_detections(faces)
18
- track_bbs_ids = mot_tracker.update(detections)
19
- for track in track_bbs_ids: # 单独框出每一张人脸
20
- id = int(track[-1])
21
- box = track[:4]
22
- if id in tracks:
23
- tracks[id].append(box)
24
- else:
25
- tracks[id] = [box]
26
-
27
- return [track for id, track in tracks.items() if len(track) == len(detect_results)]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
video/pwtf-dvd/model_code/inference/test_tools/ct/utils.py DELETED
@@ -1,5 +0,0 @@
1
- import cv2
2
-
3
-
4
- def write_img(file, img):
5
- cv2.imwrite(file, img, [cv2.IMWRITE_PNG_COMPRESSION, 0])
 
 
 
 
 
 
video/pwtf-dvd/model_code/inference/test_tools/faster_crop_align_xray.py DELETED
@@ -1,73 +0,0 @@
1
- import numpy as np
2
- import cv2
3
- from .warp_for_xray import (
4
- estimiate_batch_transform,
5
- transform_landmarks,
6
- std_points_256,
7
- )
8
- import numpy as np
9
-
10
-
11
- class FasterCropAlignXRay:
12
- """
13
- 修正到统一坐标系,统一图像大小到标准尺寸
14
- """
15
-
16
- def __init__(self, size=256):
17
- self.image_size = size
18
- self.std_points = std_points_256 * size / 256.0
19
-
20
- def __call__(self, landmarks, images=None, jitter=False):
21
- landmarks = [landmark[:4] for landmark in landmarks]
22
- ori_boxes = np.array([ori_box for _, _, _, ori_box in landmarks])
23
- five_landmarks = np.array([ldm5 for _, ldm5, _, _ in landmarks])
24
- landmarks68 = np.array([ldm68 for _, _, ldm68, _ in landmarks])
25
- # assert landmarks68.min() > 0
26
-
27
- left_top = ori_boxes[:, :2].min(0)
28
-
29
- right_bottom = ori_boxes[:, 2:].max(0)
30
-
31
- size = right_bottom - left_top
32
-
33
- w, h = size
34
-
35
- diff = ori_boxes[:, :2] - left_top[None, ...]
36
-
37
- new_five_landmarks = five_landmarks + diff[:, None, :]
38
- new_landmarks68 = landmarks68 + diff[:, None, :]
39
-
40
- landmark_for_estimiate = new_five_landmarks.copy()
41
- if jitter:
42
- landmark_for_estimiate += np.random.uniform(
43
- -4, 4, landmark_for_estimiate.shape
44
- )
45
-
46
- tfm, trans = estimiate_batch_transform(
47
- landmark_for_estimiate, tgt_pts=self.std_points
48
- )
49
-
50
- transformed_landmarks68 = np.array(
51
- [transform_landmarks(ldm68, trans) for ldm68 in new_landmarks68]
52
- )
53
-
54
- if images is not None:
55
- transformed_images = [
56
- self.process_sinlge(tfm, image, d, h, w)
57
- for image, d in zip(images, diff)
58
- ] # 拼接 func 的参数
59
- transformed_images = np.stack(transformed_images)
60
- return transformed_landmarks68, transformed_images
61
- else:
62
- return transformed_landmarks68
63
-
64
- def process_sinlge(self, tfm, image, d, h, w):
65
- assert isinstance(image, np.ndarray)
66
- new_image = np.zeros((h, w, 3), dtype=np.uint8)
67
- x, y = d
68
- ih, iw, _ = image.shape
69
- new_image[y : y + ih, x : x + iw] = image
70
- transformed_image = cv2.warpAffine(
71
- new_image, tfm, (self.image_size, self.image_size)
72
- )
73
- return transformed_image
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
video/pwtf-dvd/model_code/inference/test_tools/supply_writer.py DELETED
@@ -1,49 +0,0 @@
1
- import cv2
2
-
3
- class SupplyWriter:
4
- def __init__(self, intput_video, output_video, opt_thres, rgb_input=True):
5
- reader = cv2.VideoCapture(intput_video)
6
- fourcc = cv2.VideoWriter_fourcc(*"XVID")
7
- fps = reader.get(cv2.CAP_PROP_FPS)
8
- width = int(reader.get(3))
9
- height = int(reader.get(4))
10
- reader.release()
11
- self.padding = 40
12
-
13
- self.writer = cv2.VideoWriter(output_video, fourcc, fps, (height, width)[::-1])
14
- self.rgb_input = rgb_input
15
- self.opt_thres = opt_thres
16
-
17
- def run(self, images, scores, boxes):
18
- # Text variables
19
- font_face = cv2.FONT_HERSHEY_SIMPLEX
20
- thickness = 5
21
- font_scale = 3
22
-
23
- for image, score, box in zip(images, scores, boxes):
24
- if self.rgb_input:
25
- image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
26
- if box is not None:
27
- label = "fake" if score > self.opt_thres else "real"
28
- x1, y1, x2, y2 = box
29
- x = int(x1)
30
- y = int(y1)
31
- w = int(x2 - x1)
32
- h = int(y2 - y1)
33
- color = (
34
- (255, 255, 0) if label == "real" else (0, 255, 255)
35
- ) # BGR 255 0
36
- cv2.putText(
37
- image,
38
- label,
39
- (x, y + h + 68),
40
- font_face,
41
- font_scale,
42
- color,
43
- thickness,
44
- 2,
45
- )
46
- # draw box over face
47
- cv2.rectangle(image, (x, y), (x + w, y + h), color, 10)
48
- self.writer.write(image)
49
- self.writer.release()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
video/pwtf-dvd/model_code/inference/test_tools/utils.py DELETED
@@ -1,115 +0,0 @@
1
- import numpy as np
2
- import cv2
3
- import os
4
- import platform
5
- import json
6
- import errno
7
-
8
-
9
-
10
- def weak_check(detect_res):
11
- return sum([len(faces) for faces in detect_res]) > len(detect_res) * 0.75
12
-
13
-
14
- def get_crop_box(shape, box, scale=0.5):
15
- height, width = shape
16
- box = np.rint(box).astype(np.int32)
17
- new_box = box.reshape(2, 2)
18
- size = new_box[1] - new_box[0]
19
- diff = scale * size
20
- diff = diff[None, :] * np.array([-1, 1])[:, None]
21
- new_box = new_box + diff
22
- new_box[:, 0] = np.clip(new_box[:, 0], 0, width - 1)
23
- new_box[:, 1] = np.clip(new_box[:, 1], 0, height - 1)
24
- new_box = np.rint(new_box).astype(np.int32)
25
- return new_box.reshape(-1)
26
-
27
-
28
- def get_fps(input_file):
29
- reader = cv2.VideoCapture(input_file)
30
- fps = reader.get(cv2.CAP_PROP_FPS)
31
- reader.release()
32
- return fps
33
-
34
-
35
-
36
- def mkdir_p(dirname):
37
- """Like "mkdir -p", make a dir recursively, but do nothing if the dir exists
38
- 这个是线程安全的, from Lingzhi Li
39
- Args:
40
- dirname(str):
41
- """
42
- assert dirname is not None
43
- if dirname == "" or os.path.isdir(dirname):
44
- return
45
- try:
46
- os.makedirs(dirname)
47
- except OSError as e:
48
- if e.errno != errno.EEXIST:
49
- raise e
50
-
51
-
52
- def mkdir(*args):
53
- for folder in args:
54
- if not os.path.isdir(folder):
55
- mkdir_p(folder)
56
-
57
-
58
- def make_join(*args):
59
- folder = os.path.join(*args)
60
- mkdir(folder)
61
- return folder
62
-
63
-
64
- def list_dir(folder, condition=None, key=lambda x: x, reverse=False, co_join=[]):
65
- files = os.listdir(folder)
66
- if condition is not None:
67
- files = filter(condition, files)
68
- co_join = [folder] + co_join
69
- if key is not None:
70
- files = sorted(files, key=key, reverse=reverse)
71
- files = [(file, *[os.path.join(fold, file) for fold in co_join]) for file in files]
72
- return files
73
-
74
- def get_jointer(file):
75
- def jointer(folder):
76
- return os.path.join(folder, file)
77
-
78
- return jointer
79
-
80
- def flatten(l):
81
- return [item for sublist in l for item in sublist]
82
-
83
-
84
- def is_win():
85
- return platform.system() == "Windows"
86
-
87
-
88
- def get_postfix(post_fix):
89
- return lambda x: x.endswith(post_fix)
90
-
91
-
92
- def partition(images, size):
93
- """
94
- Returns a new list with elements
95
- of which is a list of certain size.
96
-
97
- >>> partition([1, 2, 3, 4], 3)
98
- [[1, 2, 3], [4]]
99
- """
100
- return [
101
- images[i : i + size] if i + size <= len(images) else images[i:]
102
- for i in range(0, len(images), size)
103
- ]
104
-
105
-
106
- def load_json(file):
107
- with open(file, "r") as f:
108
- res = json.load(f)
109
- return res
110
-
111
-
112
- def save_json(file, obj):
113
- with open(file, "w", encoding="utf-8") as f:
114
- json.dump(obj, f, indent=4, ensure_ascii=False)
115
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
video/pwtf-dvd/model_code/inference/test_tools/warp_for_xray.py DELETED
@@ -1,574 +0,0 @@
1
- import numpy as np
2
- import cv2
3
-
4
- # -*- coding: utf-8 -*-
5
- """
6
- Created on Tue Jul 11 06:54:28 2017
7
-
8
- @author: zhaoyafei
9
- """
10
-
11
- import numpy as np
12
- from numpy.linalg import inv, norm, lstsq
13
- from numpy.linalg import matrix_rank as rank
14
-
15
- """
16
- Introduction:
17
- ----------
18
- numpy implemetation form matlab function CP2TFORM(...)
19
- with 'transformtype':
20
- 1) 'nonreflective similarity'
21
- 2) 'similarity'
22
-
23
-
24
- MATLAB code:
25
- ----------
26
- %--------------------------------------
27
- % Function findNonreflectiveSimilarity
28
- %
29
- function [trans, output] = findNonreflectiveSimilarity(uv,xy,options)
30
- %
31
- % For a nonreflective similarity:
32
- %
33
- % let sc = s*cos(theta)
34
- % let ss = s*sin(theta)
35
- %
36
- % [ sc -ss
37
- % [u v] = [x y 1] * ss sc
38
- % tx ty]
39
- %
40
- % There are 4 unknowns: sc,ss,tx,ty.
41
- %
42
- % Another way to write this is:
43
- %
44
- % u = [x y 1 0] * [sc
45
- % ss
46
- % tx
47
- % ty]
48
- %
49
- % v = [y -x 0 1] * [sc
50
- % ss
51
- % tx
52
- % ty]
53
- %
54
- % With 2 or more correspondence points we can combine the u equations and
55
- % the v equations for one linear system to solve for sc,ss,tx,ty.
56
- %
57
- % [ u1 ] = [ x1 y1 1 0 ] * [sc]
58
- % [ u2 ] [ x2 y2 1 0 ] [ss]
59
- % [ ... ] [ ... ] [tx]
60
- % [ un ] [ xn yn 1 0 ] [ty]
61
- % [ v1 ] [ y1 -x1 0 1 ]
62
- % [ v2 ] [ y2 -x2 0 1 ]
63
- % [ ... ] [ ... ]
64
- % [ vn ] [ yn -xn 0 1 ]
65
- %
66
- % Or rewriting the above matrix equation:
67
- % U = X * r, where r = [sc ss tx ty]'
68
- % so r = X\ U.
69
- %
70
-
71
- K = options.K;
72
- M = size(xy,1);
73
- x = xy(:,1);
74
- y = xy(:,2);
75
- X = [x y ones(M,1) zeros(M,1);
76
- y -x zeros(M,1) ones(M,1) ];
77
-
78
- u = uv(:,1);
79
- v = uv(:,2);
80
- U = [u; v];
81
-
82
- % We know that X * r = U
83
- if rank(X) >= 2*K
84
- r = X \ U;
85
- else
86
- error(message('images:cp2tform:twoUniquePointsReq'))
87
- end
88
-
89
- sc = r(1);
90
- ss = r(2);
91
- tx = r(3);
92
- ty = r(4);
93
-
94
- Tinv = [sc -ss 0;
95
- ss sc 0;
96
- tx ty 1];
97
-
98
- T = inv(Tinv);
99
- T(:,3) = [0 0 1]';
100
-
101
- trans = maketform('affine', T);
102
- output = [];
103
-
104
- %-------------------------
105
- % Function findSimilarity
106
- %
107
- function [trans, output] = findSimilarity(uv,xy,options)
108
- %
109
- % The similarities are a superset of the nonreflective similarities as they may
110
- % also include reflection.
111
- %
112
- % let sc = s*cos(theta)
113
- % let ss = s*sin(theta)
114
- %
115
- % [ sc -ss
116
- % [u v] = [x y 1] * ss sc
117
- % tx ty]
118
- %
119
- % OR
120
- %
121
- % [ sc ss
122
- % [u v] = [x y 1] * ss -sc
123
- % tx ty]
124
- %
125
- % Algorithm:
126
- % 1) Solve for trans1, a nonreflective similarity.
127
- % 2) Reflect the xy data across the Y-axis,
128
- % and solve for trans2r, also a nonreflective similarity.
129
- % 3) Transform trans2r to trans2, undoing the reflection done in step 2.
130
- % 4) Use TFORMFWD to transform uv using both trans1 and trans2,
131
- % and compare the results, Returnsing the transformation corresponding
132
- % to the smaller L2 norm.
133
-
134
- % Need to reset options.K to prepare for calls to findNonreflectiveSimilarity.
135
- % This is safe because we already checked that there are enough point pairs.
136
- options.K = 2;
137
-
138
- % Solve for trans1
139
- [trans1, output] = findNonreflectiveSimilarity(uv,xy,options);
140
-
141
-
142
- % Solve for trans2
143
-
144
- % manually reflect the xy data across the Y-axis
145
- xyR = xy;
146
- xyR(:,1) = -1*xyR(:,1);
147
-
148
- trans2r = findNonreflectiveSimilarity(uv,xyR,options);
149
-
150
- % manually reflect the tform to undo the reflection done on xyR
151
- TreflectY = [-1 0 0;
152
- 0 1 0;
153
- 0 0 1];
154
- trans2 = maketform('affine', trans2r.tdata.T * TreflectY);
155
-
156
-
157
- % Figure out if trans1 or trans2 is better
158
- xy1 = tformfwd(trans1,uv);
159
- norm1 = norm(xy1-xy);
160
-
161
- xy2 = tformfwd(trans2,uv);
162
- norm2 = norm(xy2-xy);
163
-
164
- if norm1 <= norm2
165
- trans = trans1;
166
- else
167
- trans = trans2;
168
- end
169
- """
170
-
171
-
172
- class MatlabCp2tormException(Exception):
173
- def __str__(self):
174
- return "In File {}:{}".format(__file__, super.__str__(self))
175
-
176
-
177
- def tformfwd(trans, uv):
178
- """
179
- Function:
180
- ----------
181
- apply affine transform 'trans' to uv
182
-
183
- Parameters:
184
- ----------
185
- @trans: 3x3 np.array
186
- transform matrix
187
- @uv: Kx2 np.array
188
- each row is a pair of coordinates (x, y)
189
-
190
- Returns:
191
- ----------
192
- @xy: Kx2 np.array
193
- each row is a pair of transformed coordinates (x, y)
194
- """
195
- uv = np.hstack((uv, np.ones((uv.shape[0], 1))))
196
- xy = np.dot(uv, trans)
197
- xy = xy[:, 0:-1]
198
- return xy
199
-
200
-
201
- def tforminv(trans, uv):
202
- """
203
- Function:
204
- ----------
205
- apply the inverse of affine transform 'trans' to uv
206
-
207
- Parameters:
208
- ----------
209
- @trans: 3x3 np.array
210
- transform matrix
211
- @uv: Kx2 np.array
212
- each row is a pair of coordinates (x, y)
213
-
214
- Returns:
215
- ----------
216
- @xy: Kx2 np.array
217
- each row is a pair of inverse-transformed coordinates (x, y)
218
- """
219
- Tinv = inv(trans)
220
- xy = tformfwd(Tinv, uv)
221
- return xy
222
-
223
-
224
- def findNonreflectiveSimilarity(uv, xy, options=None):
225
- """
226
- Function:
227
- ----------
228
- Find Non-reflective Similarity Transform Matrix 'trans':
229
- u = uv[:, 0]
230
- v = uv[:, 1]
231
- x = xy[:, 0]
232
- y = xy[:, 1]
233
- [x, y, 1] = [u, v, 1] * trans
234
-
235
- Parameters:
236
- ----------
237
- @uv: Kx2 np.array
238
- source points each row is a pair of coordinates (x, y)
239
- @xy: Kx2 np.array
240
- each row is a pair of inverse-transformed
241
- @option: not used, keep it as None
242
-
243
- Returns:
244
- @trans: 3x3 np.array
245
- transform matrix from uv to xy
246
- @trans_inv: 3x3 np.array
247
- inverse of trans, transform matrix from xy to uv
248
-
249
- Matlab:
250
- ----------
251
- % For a nonreflective similarity:
252
- %
253
- % let sc = s*cos(theta)
254
- % let ss = s*sin(theta)
255
- %
256
- % [ sc -ss
257
- % [u v] = [x y 1] * ss sc
258
- % tx ty]
259
- %
260
- % There are 4 unknowns: sc,ss,tx,ty.
261
- %
262
- % Another way to write this is:
263
- %
264
- % u = [x y 1 0] * [sc
265
- % ss
266
- % tx
267
- % ty]
268
- %
269
- % v = [y -x 0 1] * [sc
270
- % ss
271
- % tx
272
- % ty]
273
- %
274
- % With 2 or more correspondence points we can combine the u equations and
275
- % the v equations for one linear system to solve for sc,ss,tx,ty.
276
- %
277
- % [ u1 ] = [ x1 y1 1 0 ] * [sc]
278
- % [ u2 ] [ x2 y2 1 0 ] [ss]
279
- % [ ... ] [ ... ] [tx]
280
- % [ un ] [ xn yn 1 0 ] [ty]
281
- % [ v1 ] [ y1 -x1 0 1 ]
282
- % [ v2 ] [ y2 -x2 0 1 ]
283
- % [ ... ] [ ... ]
284
- % [ vn ] [ yn -xn 0 1 ]
285
- %
286
- % Or rewriting the above matrix equation:
287
- % U = X * r, where r = [sc ss tx ty]'
288
- % so r = X\ U.
289
- %
290
- """
291
- options = {"K": 2}
292
-
293
- K = options["K"]
294
- M = xy.shape[0]
295
- x = xy[:, 0].reshape((-1, 1)) # use reshape to keep a column vector
296
- y = xy[:, 1].reshape((-1, 1)) # use reshape to keep a column vector
297
- # print '--->x, y:\n', x, y
298
-
299
- tmp1 = np.hstack((x, y, np.ones((M, 1)), np.zeros((M, 1))))
300
- tmp2 = np.hstack((y, -x, np.zeros((M, 1)), np.ones((M, 1))))
301
- X = np.vstack((tmp1, tmp2))
302
- # print '--->X.shape: ', X.shape
303
- # print 'X:\n', X
304
-
305
- u = uv[:, 0].reshape((-1, 1)) # use reshape to keep a column vector
306
- v = uv[:, 1].reshape((-1, 1)) # use reshape to keep a column vector
307
- U = np.vstack((u, v))
308
- # print '--->U.shape: ', U.shape
309
- # print 'U:\n', U
310
-
311
- # We know that X * r = U
312
- if rank(X) >= 2 * K:
313
- r, _, _, _ = lstsq(X, U, rcond=-1)
314
- r = np.squeeze(r)
315
- else:
316
- raise Exception("cp2tform:twoUniquePointsReq")
317
-
318
- # print '--->r:\n', r
319
-
320
- sc = r[0]
321
- ss = r[1]
322
- tx = r[2]
323
- ty = r[3]
324
-
325
- Tinv = np.array([[sc, -ss, 0], [ss, sc, 0], [tx, ty, 1]])
326
-
327
- # print '--->Tinv:\n', Tinv
328
-
329
- T = inv(Tinv)
330
- # print '--->T:\n', T
331
-
332
- T[:, 2] = np.array([0, 0, 1])
333
-
334
- return T, Tinv
335
-
336
-
337
- def findSimilarity(uv, xy, options=None):
338
- """
339
- Function:
340
- ----------
341
- Find Reflective Similarity Transform Matrix 'trans':
342
- u = uv[:, 0]
343
- v = uv[:, 1]
344
- x = xy[:, 0]
345
- y = xy[:, 1]
346
- [x, y, 1] = [u, v, 1] * trans
347
-
348
- Parameters:
349
- ----------
350
- @uv: Kx2 np.array
351
- source points each row is a pair of coordinates (x, y)
352
- @xy: Kx2 np.array
353
- each row is a pair of inverse-transformed
354
- @option: not used, keep it as None
355
-
356
- Returns:
357
- ----------
358
- @trans: 3x3 np.array
359
- transform matrix from uv to xy
360
- @trans_inv: 3x3 np.array
361
- inverse of trans, transform matrix from xy to uv
362
-
363
- Matlab:
364
- ----------
365
- % The similarities are a superset of the nonreflective similarities as they may
366
- % also include reflection.
367
- %
368
- % let sc = s*cos(theta)
369
- % let ss = s*sin(theta)
370
- %
371
- % [ sc -ss
372
- % [u v] = [x y 1] * ss sc
373
- % tx ty]
374
- %
375
- % OR
376
- %
377
- % [ sc ss
378
- % [u v] = [x y 1] * ss -sc
379
- % tx ty]
380
- %
381
- % Algorithm:
382
- % 1) Solve for trans1, a nonreflective similarity.
383
- % 2) Reflect the xy data across the Y-axis,
384
- % and solve for trans2r, also a nonreflective similarity.
385
- % 3) Transform trans2r to trans2, undoing the reflection done in step 2.
386
- % 4) Use TFORMFWD to transform uv using both trans1 and trans2,
387
- % and compare the results, Returnsing the transformation corresponding
388
- % to the smaller L2 norm.
389
-
390
- % Need to reset options.K to prepare for calls to findNonreflectiveSimilarity.
391
- % This is safe because we already checked that there are enough point pairs.
392
- """
393
- options = {"K": 2}
394
-
395
- # uv = np.array(uv)
396
- # xy = np.array(xy)
397
-
398
- # Solve for trans1
399
- trans1, trans1_inv = findNonreflectiveSimilarity(uv, xy, options)
400
-
401
- # Solve for trans2
402
-
403
- # manually reflect the xy data across the Y-axis
404
- xyR = xy
405
- xyR[:, 0] = -1 * xyR[:, 0]
406
-
407
- trans2r, trans2r_inv = findNonreflectiveSimilarity(uv, xyR, options)
408
-
409
- # manually reflect the tform to undo the reflection done on xyR
410
- TreflectY = np.array([[-1, 0, 0], [0, 1, 0], [0, 0, 1]])
411
-
412
- trans2 = np.dot(trans2r, TreflectY)
413
-
414
- # Figure out if trans1 or trans2 is better
415
- xy1 = tformfwd(trans1, uv)
416
- norm1 = norm(xy1 - xy)
417
-
418
- xy2 = tformfwd(trans2, uv)
419
- norm2 = norm(xy2 - xy)
420
-
421
- if norm1 <= norm2:
422
- return trans1, trans1_inv
423
- else:
424
- trans2_inv = inv(trans2)
425
- return trans2, trans2_inv
426
-
427
-
428
- def get_similarity_transform(src_pts, dst_pts, reflective=True):
429
- """
430
- Function:
431
- ----------
432
- Find Similarity Transform Matrix 'trans':
433
- u = src_pts[:, 0]
434
- v = src_pts[:, 1]
435
- x = dst_pts[:, 0]
436
- y = dst_pts[:, 1]
437
- [x, y, 1] = [u, v, 1] * trans
438
-
439
- Parameters:
440
- ----------
441
- @src_pts: Kx2 np.array
442
- source points, each row is a pair of coordinates (x, y)
443
- @dst_pts: Kx2 np.array
444
- destination points, each row is a pair of transformed
445
- coordinates (x, y)
446
- @reflective: True or False
447
- if True:
448
- use reflective similarity transform
449
- else:
450
- use non-reflective similarity transform
451
-
452
- Returns:
453
- ----------
454
- @trans: 3x3 np.array
455
- transform matrix from uv to xy
456
- trans_inv: 3x3 np.array
457
- inverse of trans, transform matrix from xy to uv
458
- """
459
-
460
- if reflective:
461
- trans, trans_inv = findSimilarity(src_pts, dst_pts)
462
- else:
463
- trans, trans_inv = findNonreflectiveSimilarity(src_pts, dst_pts)
464
-
465
- return trans, trans_inv
466
-
467
-
468
- def cvt_tform_mat_for_cv2(trans):
469
- """
470
- Function:
471
- ----------
472
- Convert Transform Matrix 'trans' into 'cv2_trans' which could be
473
- directly used by cv2.warpAffine():
474
- u = src_pts[:, 0]
475
- v = src_pts[:, 1]
476
- x = dst_pts[:, 0]
477
- y = dst_pts[:, 1]
478
- [x, y].T = cv_trans * [u, v, 1].T
479
-
480
- Parameters:
481
- ----------
482
- @trans: 3x3 np.array
483
- transform matrix from uv to xy
484
-
485
- Returns:
486
- ----------
487
- @cv2_trans: 2x3 np.array
488
- transform matrix from src_pts to dst_pts, could be directly used
489
- for cv2.warpAffine()
490
- """
491
- cv2_trans = trans[:, 0:2].T
492
-
493
- return cv2_trans
494
-
495
-
496
- def get_similarity_transform_for_cv2(src_pts, dst_pts, reflective=True):
497
- """
498
- Function:
499
- ----------
500
- Find Similarity Transform Matrix 'cv2_trans' which could be
501
- directly used by cv2.warpAffine():
502
- u = src_pts[:, 0]
503
- v = src_pts[:, 1]
504
- x = dst_pts[:, 0]
505
- y = dst_pts[:, 1]
506
- [x, y].T = cv_trans * [u, v, 1].T
507
-
508
- Parameters:
509
- ----------
510
- @src_pts: Kx2 np.array
511
- source points, each row is a pair of coordinates (x, y)
512
- @dst_pts: Kx2 np.array
513
- destination points, each row is a pair of transformed
514
- coordinates (x, y)
515
- reflective: True or False
516
- if True:
517
- use reflective similarity transform
518
- else:
519
- use non-reflective similarity transform
520
-
521
- Returns:
522
- ----------
523
- @cv2_trans: 2x3 np.array
524
- transform matrix from src_pts to dst_pts, could be directly used
525
- for cv2.warpAffine()
526
- """
527
- trans, trans_inv = get_similarity_transform(src_pts, dst_pts, reflective)
528
- cv2_trans = cvt_tform_mat_for_cv2(trans)
529
- return cv2_trans, trans
530
-
531
-
532
- std_points_317 = np.array(
533
- [
534
- [85.82991, 115.7792],
535
- [169.0532, 114.3381],
536
- [127.574, 167.0006],
537
- [90.6964, 204.7014],
538
- [167.3069, 203.3733],
539
- ]
540
- )
541
-
542
-
543
- padding = 30
544
-
545
- std_points_317 = std_points_317 + padding
546
-
547
- std_points_256=std_points_317.copy()
548
- std_points_256[..., 0] -= 30
549
- std_points_256[..., 1] -= 60
550
-
551
- def warp_as_face_x_ray(img, src_pts, tgt_pts=std_points_317):
552
- tfm, trans = get_similarity_transform_for_cv2(src_pts.copy(), tgt_pts.copy())
553
- return cv2.warpAffine(img, tfm, (317, 317)), trans
554
-
555
-
556
- def estimiate_batch_transform(all_src_pts, tgt_pts=std_points_317):
557
- tgt_pts = np.repeat(tgt_pts[None, ...], len(all_src_pts), 0).reshape(-1, 2)
558
- src_pts = np.array(all_src_pts).reshape(-1, 2)
559
- tfm, trans = get_similarity_transform_for_cv2(src_pts, tgt_pts)
560
- return tfm, trans
561
-
562
-
563
- def batch_warp_as_face_x_ray(images, all_src_pts, tgt_pts=std_points_317):
564
- tfm, trans = estimiate_batch_transform(all_src_pts, tgt_pts)
565
- return [cv2.warpAffine(img, tfm, (317, 317)) for img in images], trans
566
-
567
-
568
- def transform_landmarks(landmarks, trans):
569
- transformed = np.hstack((landmarks, np.ones((landmarks.shape[0], 1))))
570
- transformed = np.dot(transformed, trans)
571
- return transformed[:, :2]
572
-
573
- def compute_reverse_trans(trans):
574
- return np.linalg.inv(trans)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
video/pwtf-dvd/model_code/inference/utils/__init__.py DELETED
@@ -1,7 +0,0 @@
1
-
2
- __all__ = [] # do not use ' from utils import *'
3
-
4
- from .common import *
5
- from .plugin_loader import PluginLoader
6
- #from .plugin_loaderv2 import PluginLoader as PluginLoaderV2
7
- from .model_loader import add_loader
 
 
 
 
 
 
 
 
video/pwtf-dvd/model_code/inference/utils/common.py DELETED
@@ -1,80 +0,0 @@
1
- #!/usr/bin/python
2
- # -*- coding: UTF-8 -*-
3
-
4
-
5
- import os
6
- import torch
7
- from torch.autograd import Variable
8
- import errno
9
- import torch.distributed as dist
10
- import math
11
- from functools import reduce
12
- def make_folder(path, version):
13
- if not os.path.exists(os.path.join(path, version)):
14
- print(os.path.join(path, version))
15
- os.makedirs(os.path.join(path, version))
16
-
17
-
18
- def tensor2var(x, grad=False):
19
- if torch.cuda.is_available():
20
- x = x.cuda()
21
- return Variable(x, requires_grad=grad)
22
-
23
- def var2tensor(x):
24
- return x.data.cpu()
25
-
26
- def var2numpy(x):
27
- return x.data.cpu().numpy()
28
-
29
- def denorm(x):
30
- out = (x + 1) / 2
31
- return out.clamp_(0, 1)
32
-
33
- def mkdir_p(dirname):
34
- """ Like "mkdir -p", make a dir recursively, but do nothing if the dir exists
35
- Args:
36
- dirname(str):
37
- """
38
- assert dirname is not None
39
- if dirname == '' or os.path.isdir(dirname):
40
- return
41
- try:
42
- os.makedirs(dirname)
43
- except OSError as e:
44
- if e.errno != errno.EEXIST:
45
- raise e
46
-
47
-
48
- def skipShardSplit(aList, drop_last=False, num_replicas=None, rank=None):
49
- if not isinstance(aList, list) and not isinstance(aList, tuple):
50
- aList = List
51
-
52
- if num_replicas is None:
53
- num_replicas = dist.get_world_size() if dist.is_initialized() else 1
54
- if rank is None:
55
- rank = dist.get_rank() if dist.is_initialized() else 0
56
-
57
- num_replicas = num_replicas
58
- rank = rank
59
- drop_last = drop_last
60
-
61
- if drop_last:
62
- aList = aList[0: (len(aList) // num_replicas) * num_replicas]
63
-
64
- # subsample
65
- aList = aList[rank::num_replicas]
66
-
67
- return aList
68
-
69
- def mixb2a(a,b):
70
- if len(b) > len(a):
71
- a,b = b,a
72
- if len(b) == 0:
73
- return a
74
- chunk_num = (len(b))
75
- a_chunk = splitIntoChunk(a, chunk_num)
76
- b_chunk = list(map(lambda x:[x],b))
77
- return reduce(lambda x, y: x+y, [_a+_b for _a,_b in zip(a_chunk, b_chunk)])
78
-
79
- def splitIntoChunk(aList, chunk_num):
80
- return [aList[math.ceil(k * (len(aList) / chunk_num)):math.ceil((k + 1) * (len(aList) / chunk_num)):] for k in range(chunk_num)]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
video/pwtf-dvd/model_code/inference/utils/logger.py DELETED
@@ -1,182 +0,0 @@
1
- #!/usr/bin/python
2
- # -*- coding: UTF-8 -*-
3
- # Modified by: algohunt
4
- # Microsoft Research & Peking University
5
- # lilingzhi@pku.edu.cn
6
- # Copyright (c) 2019
7
-
8
-
9
- # -*- coding: utf-8 -*-
10
-
11
- """
12
- Borrow from tensorpack credit goes to yuxin wu
13
- The logger module itself has the common logging functions of Python's
14
- :class:`logging.Logger`. For example:
15
-
16
- .. code-block:: python
17
-
18
- from utils import logger
19
- logger.set_logger_dir('train_log/test')
20
- logger.info("Test")
21
- logger.error("Error happened!")
22
- """
23
-
24
-
25
- import logging
26
- import os
27
- import os.path
28
- import shutil
29
- import sys
30
- from datetime import datetime, timedelta
31
- from six.moves import input
32
- from termcolor import colored
33
- import time
34
-
35
- __all__ = ['set_logger_dir', 'auto_set_dir', 'get_logger_dir']
36
-
37
-
38
- class _MyFormatter(logging.Formatter):
39
- def format(self, record):
40
- date = colored('[%(asctime)s @%(filename)s:%(lineno)d]', 'green')
41
- msg = '%(message)s'
42
- if record.levelno == logging.WARNING:
43
- fmt = date + ' ' + colored('WRN', 'red', attrs=['blink']) + ' ' + msg
44
- elif record.levelno == logging.ERROR or record.levelno == logging.CRITICAL:
45
- fmt = date + ' ' + colored('ERR', 'red', attrs=['blink', 'underline']) + ' ' + msg
46
- elif record.levelno == logging.DEBUG:
47
- fmt = date + ' ' + colored('DBG', 'yellow', attrs=['blink']) + ' ' + msg
48
- else:
49
- fmt = date + ' ' + msg
50
- if hasattr(self, '_style'):
51
- # Python3 compatibility
52
- self._style._fmt = fmt
53
- self._fmt = fmt
54
- return super(_MyFormatter, self).format(record)
55
-
56
-
57
- def _getlogger():
58
- logger = logging.getLogger('tensorpack')
59
- logger.propagate = False
60
- logger.setLevel(logging.INFO)
61
- handler = logging.StreamHandler(sys.stdout)
62
- handler.setFormatter(_MyFormatter(datefmt='%m%d %H:%M:%S'))
63
- logger.addHandler(handler)
64
- return logger
65
-
66
-
67
- _logger = _getlogger()
68
- _LOGGING_METHOD = ['info', 'warning', 'error', 'critical', 'exception', 'debug', 'setLevel']
69
- # export logger functions
70
- for func in _LOGGING_METHOD:
71
- locals()[func] = getattr(_logger, func)
72
- __all__.append(func)
73
- # 'warn' is deprecated in logging module
74
- warn = _logger.warning
75
- __all__.append('warn')
76
-
77
-
78
- def _get_time_str():
79
- utc_time = datetime.utcfromtimestamp(time.time())
80
- beijing_time = utc_time- timedelta(hours=8)
81
- return beijing_time.strftime('%m%d-%H%M%S')
82
-
83
-
84
- # globals: logger file and directory:
85
- LOG_DIR = None
86
- _FILE_HANDLER = None
87
-
88
-
89
- def _set_file(path):
90
- global _FILE_HANDLER
91
- if os.path.isfile(path):
92
- backup_name = path + '.' + _get_time_str()
93
- shutil.move(path, backup_name)
94
- _logger.info("Existing log file '{}' backuped to '{}'".format(path, backup_name)) # noqa: F821
95
- hdl = logging.FileHandler(
96
- filename=path, encoding='utf-8', mode='w')
97
- hdl.setFormatter(_MyFormatter(datefmt='%m%d %H:%M:%S'))
98
-
99
- _FILE_HANDLER = hdl
100
- _logger.addHandler(hdl)
101
- _logger.info("Argv: " + ' '.join(sys.argv))
102
-
103
-
104
- def set_logger_dir(dirname, action=None):
105
- """
106
- Set the directory for global logging.
107
-
108
- Args:
109
- dirname(str): log directory
110
- action(str): an action of ["k","d","q"] to be performed
111
- when the directory exists. Will ask user by default.
112
-
113
- "d": delete the directory. Note that the deletion may fail when
114
- the directory is used by tensorboard.
115
-
116
- "k": keep the directory. This is useful when you resume from a
117
- previous training and want the directory to look as if the
118
- training was not interrupted.
119
- Note that this option does not load old models or any other
120
- old states for you. It simply does nothing.
121
-
122
- """
123
- global LOG_DIR, _FILE_HANDLER
124
- if _FILE_HANDLER:
125
- # unload and close the old file handler, so that we may safely delete the logger directory
126
- _logger.removeHandler(_FILE_HANDLER)
127
- del _FILE_HANDLER
128
-
129
- def dir_nonempty(dirname):
130
- # If directory exists and nonempty (ignore hidden files), prompt for action
131
- return os.path.isdir(dirname) and len([x for x in os.listdir(dirname) if x[0] != '.'])
132
-
133
- if dir_nonempty(dirname):
134
- if not action:
135
- _logger.warn("""\
136
- Log directory {} exists! Use 'd' to delete it. """.format(dirname))
137
- _logger.warn("""\
138
- If you're resuming from a previous run, you can choose to keep it.
139
- Press any other key to exit. """)
140
- while not action:
141
- action = input("Select Action: k (keep) / d (delete) / q (quit):").lower().strip()
142
- act = action
143
- if act == 'b':
144
- backup_name = dirname + _get_time_str()
145
- shutil.move(dirname, backup_name)
146
- info("Directory '{}' backuped to '{}'".format(dirname, backup_name)) # noqa: F821
147
- elif act == 'd':
148
- shutil.rmtree(dirname, ignore_errors=True)
149
- if dir_nonempty(dirname):
150
- shutil.rmtree(dirname, ignore_errors=False)
151
- elif act == 'n':
152
- dirname = dirname + _get_time_str()
153
- info("Use a new log directory {}".format(dirname)) # noqa: F821
154
- elif act == 'k':
155
- pass
156
- else:
157
- raise OSError("Directory {} exits!".format(dirname))
158
- LOG_DIR = dirname
159
- from . import mkdir_p
160
- mkdir_p(dirname)
161
- _set_file(os.path.join(dirname, 'log.log'))
162
-
163
-
164
- def auto_set_dir(action=None, name=None):
165
- """
166
- Use :func:`logger.set_logger_dir` to set log directory to
167
- "./train_log/{scriptname}:{name}". "scriptname" is the name of the main python file currently running"""
168
- mod = sys.modules['__main__']
169
- basename = os.path.basename(mod.__file__)
170
- auto_dirname = os.path.join('train_log', basename[:basename.rfind('.')])
171
- if name:
172
- auto_dirname += '_%s' % name if os.name == 'nt' else ':%s' % name
173
- set_logger_dir(auto_dirname, action=action)
174
-
175
-
176
- def get_logger_dir():
177
- """
178
- Returns:
179
- The logger directory, or None if not set.
180
- The directory is used for general logging, tensorboard events, checkpoints, etc.
181
- """
182
- return LOG_DIR
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
video/pwtf-dvd/model_code/inference/utils/model_loader.py DELETED
@@ -1,117 +0,0 @@
1
- #!/usr/bin/python
2
- # -*- coding: UTF-8 -*-
3
-
4
-
5
- import types
6
- from utils import logger
7
- from config import config as cfg
8
- import os
9
- import sys
10
- import glob
11
- import torch
12
- import traceback
13
- import types
14
- import torch.distributed as dist
15
- import copy
16
- from .torch_save import torch_save
17
-
18
- def add_loader(target, name,max_to_keep=2):
19
-
20
- def get_rank(self):
21
- return dist.get_rank() if dist.is_initialized() else 0
22
-
23
- def save_models(self, epoch):
24
- """ Backup and save the models """
25
- if self.get_rank() == 0:
26
- logger.debug("Backing up and saving models")
27
- if not os.path.exists(self.model_dir):
28
- os.mkdir(self.model_dir)
29
-
30
- torch_save(self.state_dict(), self.get_checkpoint_path(epoch))
31
- if os.path.exists(self.get_checkpoint_path(epoch - self.max_to_keep)):
32
- os.remove(self.get_checkpoint_path(epoch - self.max_to_keep))
33
- logger.info("{} models saved".format(self.name))
34
-
35
- def load(self, fullpath=None, epoch=-1):
36
- """ Force Loading a model, or load the latest model"""
37
- if fullpath is None:
38
- fullpath, loaded_epoch = self.find_last(epoch)
39
- else:
40
- loaded_epoch = epoch
41
-
42
- if fullpath is None:
43
- logger.info("No existing {} model found".format(self.name))
44
- return False, -1
45
- logger.debug("Loading model: '%s'", fullpath)
46
- try:
47
- saved_state_dict = torch.load(fullpath, map_location='cpu')
48
- self.load_state_dict(saved_state_dict)
49
- logger.info(" consume training from {}".format(fullpath))
50
- except ValueError as err:
51
- logger.warning("Failed loading existing training data for {}. Generating new models".format(self.name))
52
- logger.debug("Exception: %s", str(err))
53
- return False, -1
54
- except OSError as err:
55
- logger.warning("Failed loading existing training data for {}. Generating new models".format(self.name))
56
- logger.debug("Exception: %s", str(err))
57
- return False, -1
58
- except RuntimeError as err:
59
- logger.warning("{} model has corrupted, try to load earlier one".format(self.name))
60
- logger.debug("Exception: %s", str(err))
61
- return False, -1
62
- except:
63
- logger.error(traceback.format_exc())
64
- raise
65
-
66
- return True, loaded_epoch
67
-
68
- def get_checkpoint_path(self, epoch):
69
- """" returning the checkpoint path w.r.t epoch which should be {name}_{epoch}.pth"""
70
- return os.path.join(self.model_dir, self.name + '_' +str(epoch) + '.pth')
71
-
72
-
73
- def find_last(self, epoch=-1, model_dir=None):
74
- """Finds the last checkpoint file of the last trained model in the
75
- model directory.
76
- Returns:
77
- checkpoint :The path of the last checkpoint file
78
-
79
- """
80
- if model_dir is None:
81
- model_dir = self.model_dir
82
- if not os.path.exists(model_dir):
83
- logger.info("model dir not exists {} ".format(model_dir))
84
- return None, -1
85
- #assert os.path.exists(self.model_dir), "model dir not exists {}".format(self.model_dir)
86
- checkpoints = glob.glob(os.path.join(model_dir, '*.pth'))
87
-
88
-
89
- checkpoints = list(filter(lambda x: os.path.basename(x).startswith(self.name), checkpoints))
90
- if len(checkpoints) == 0:
91
- return None, -1
92
- checkpoints = {int(os.path.basename(x).split('.')[0].split('_')[-1]):x for x in checkpoints}
93
-
94
- start = min(checkpoints.keys())
95
- end = max(checkpoints.keys())
96
-
97
- if epoch == -1:
98
- return checkpoints[end], end
99
- elif epoch < start :
100
- raise RuntimeError(
101
- "model for epoch {} has been deleted as we only keep {} models".format(epoch,self.max_to_keep))
102
- elif epoch > end:
103
- raise RuntimeError(
104
- "epoch {} is bigger than all exist checkpoints".format(epoch))
105
- else:
106
- return checkpoints[epoch], epoch
107
-
108
- target.find_last = types.MethodType(find_last, target)
109
- target.get_checkpoint_path = types.MethodType(get_checkpoint_path, target)
110
- target.load = types.MethodType(load, target)
111
- target.save_models = types.MethodType(save_models, target)
112
- target.get_rank = types.MethodType(get_rank, target)
113
-
114
- target.max_to_keep = max_to_keep
115
- target.name = name
116
- target.model_dir = os.path.join(cfg.path.model_dir, cfg.setting_name)
117
- return target
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
video/pwtf-dvd/model_code/inference/utils/plugin_loader.py DELETED
@@ -1,69 +0,0 @@
1
- #!/usr/bin/python
2
- # -*- coding: UTF-8 -*-
3
-
4
-
5
-
6
- """ Plugin loader for extract, training and model tasks """
7
-
8
- from utils import logger
9
- import os
10
- from importlib import import_module
11
- from typing import Type
12
- from trainer._base import TrainerBase
13
- from torch.utils.data import Dataset
14
- from model._base import ModelBase
15
-
16
- class PluginLoader():
17
- """
18
- Plugin loader for extract, training and model tasks
19
- function: get_{model_type}
20
- args: {model_name}
21
- will return the a class named model_type under model_type.model_name.py
22
-
23
- as it return a class you should also annotate the returning classtype to make
24
- code linting avaliable in some IDE
25
- """
26
- @staticmethod
27
- def get_classifier(name) -> Type[ModelBase]:
28
- """ Return requested attribute encoder plugin """
29
- return PluginLoader._import("model.classifier", name)
30
-
31
- @staticmethod
32
- def get_trainer(name) -> Type[TrainerBase]:
33
- """ Return requested trainer plugin """
34
- return PluginLoader._import("trainer", name)
35
-
36
- @staticmethod
37
- def get_dataset(name) -> Type[Dataset]:
38
- """ Return requested trainer plugin """
39
- return PluginLoader._import("dataset", name)
40
-
41
- @staticmethod
42
- def _import(attr, name):
43
- """ Import the plugin's module """
44
- name = name.replace("-", "_")
45
- ttl = attr.split(".")[-1].title()
46
- logger.info("Loading %s from %s plugin...", ttl, name.title())
47
- attr = "model" if attr == "Trainer" else attr.lower()
48
- mod = ".".join((attr, name))
49
- module = import_module(mod)
50
- logger.info(str(module) + str(ttl))
51
- return getattr(module, ttl)
52
-
53
- @staticmethod
54
- def get_available_trainer():
55
- """ Return a list of available models """
56
- modelpath = os.path.join(os.path.dirname(__file__), "trainer")
57
- models = sorted(item.name.replace(".py", "").replace("_", "-")
58
- for item in os.scandir(modelpath)
59
- if not item.name.startswith("_")
60
- and item.name.endswith(".py"))
61
- return models
62
-
63
- @staticmethod
64
- def get_default_model():
65
- """ Return the default model """
66
- models = PluginLoader.get_available_models()
67
- return 'original' if 'original' in models else models[0]
68
-
69
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
video/pwtf-dvd/model_code/inference/utils/torch_save.py DELETED
@@ -1,9 +0,0 @@
1
- import torch
2
-
3
- def torch_save(arr,file):
4
- if torch.__version__>="1.6.0":
5
- torch.save(arr, file, _use_new_zipfile_serialization=False)
6
- else:
7
- torch.save(arr, file)
8
-
9
-
 
 
 
 
 
 
 
 
 
 
video/pwtf-dvd/model_code/preprocessing/preprocess.py DELETED
@@ -1,258 +0,0 @@
1
- import os
2
- from os.path import join
3
- import argparse
4
- import glob
5
- import subprocess
6
- import cv2
7
- from tqdm import tqdm
8
- import numpy as np
9
- import logging
10
- import torch
11
- from test_tools.common import detect_all, grab_all_frames
12
- from test_tools.faster_crop_align_xray import FasterCropAlignXRay
13
- from test_tools.warp_for_xray import (
14
- estimiate_batch_transform,
15
- transform_landmarks,
16
- std_points_256,
17
- )
18
- from test_tools.ct.operations import find_longest, multiple_tracking
19
- from test_tools.utils import get_crop_box
20
- import datetime
21
- # from FaceForensics.face_detection_save import get_boundingbox
22
-
23
- os.environ['CUDA_LAUNCH_BLOCKING'] = "1"
24
- os.environ["CUDA_VISIBLE_DEVICES"] = "0"
25
-
26
- device=torch.device('cuda')
27
- #Date
28
- now = datetime.datetime.now()
29
- logger = logging.getLogger("main") #Logger 선언
30
- stream_handler = logging.StreamHandler() # Logger output 방법 선언
31
- formatter = logging.Formatter('[%(asctime)s][%(levelname)s|%(filename)s:%(lineno)s] >> %(message)s')
32
- stream_handler.setFormatter(formatter)
33
- logger.addHandler(stream_handler)
34
- logger.setLevel(logging.DEBUG)
35
-
36
- crop_align_func = FasterCropAlignXRay(256)
37
- max_frame= 10000
38
-
39
- ### video path를 받으면 crop된 face를 저장하는 함수 ###
40
- def crop_face_from_video(video_path,cache_path,crop_path,clip_size):
41
- # mp4 파일이 아니면 return
42
- if 'mp4' not in video_path : return
43
- # video name
44
- video_name = video_path.split('/')[-1].replace('.mp4','')
45
- # 만약 crop image path에 crop된 이미지가 110개 이상이면 return
46
-
47
- if os.path.exists(crop_path):
48
- if len(os.listdir(crop_path))>clip_limit:
49
- logger.info(f'{video_name} already exists')
50
- return
51
-
52
- ##########################################
53
- # detect_res : list, 전체 frame, whole frame
54
- # detect_res [] : list, len = 사람 수로 예상 the number of detected face in a frame
55
- # detect_res [] [] : tuple, length = 3
56
- # detect_res [] [] 의 각 요소는 각각 box, lm5 : landmark (5,2) , score
57
- ##########################################
58
- # all_lm68 : list, 전체 frame, whole frame
59
- # all_lm68 : list, len = 사람 수로 예상, the number of detected face in a frame
60
- # all_lm68 : np.array : landmark 68개 (68,2)
61
- ##########################################
62
- # frames : each frame's np.array
63
-
64
-
65
- # cache_file : cache file path
66
- # landmark와 box를 저장하는 cache file
67
- cache_file = f"{cache_path}.pth"
68
-
69
- if os.path.exists(cache_file):
70
- # cache file이 존재하면 load하고 frame만 불러옴
71
- detect_res, all_lm68 = torch.load(cache_file)
72
- frames = grab_all_frames(video_path, max_size=max_frame, cvt=True)
73
- logger.info("detection result loaded from cache")
74
- else:
75
- # cache file이 존재하지 않으면 detect_all 함수를 통해 detect_res, all_lm68, frames를 불러옴
76
- # detection_all 함수는 retina_face를 이용해서 box와 landmark를 찾는 함수
77
- detect_res, all_lm68, frames = detect_all(
78
- video_path, return_frames=True, max_size=10000
79
- )
80
- torch.save((detect_res, all_lm68), cache_file)
81
- try:
82
- shape = frames[0].shape[:2]
83
- except IndexError: # if there is no frame in the video, error list에 저장
84
- f = open("./indexerror.txt", 'a')
85
- f.write("{}\n".format(video_path))
86
- f.close()
87
- return
88
-
89
- # 모든 detect_res
90
- all_detect_res = []
91
-
92
- assert len(all_lm68) == len(detect_res)
93
- # in each frame, save the detected face's bounding box, landmark(5, 68), score as a tuple and save it in a list
94
- for faces, faces_lm68 in zip(detect_res, all_lm68):
95
- new_faces = []
96
- for (box, lm5, score), face_lm68 in zip(faces, faces_lm68):
97
- new_face = (box, lm5, face_lm68, score)
98
- new_faces.append(new_face)
99
- all_detect_res.append(new_faces)
100
- detect_res = all_detect_res
101
- # SORT tracking
102
- # tracks : list, len = 사람 수로 예상, the number of detected face in a frame
103
- # tracks [] : list, len = 프레임 수, the number of frames
104
- # tracks [] [] : tuple, length = 4, 각각 box, lm5 : landmark (5,2) , lm68 : landmark (68,2), score
105
- tracks = multiple_tracking(detect_res)
106
- # tuples : list, len = 사람 수로 예상, the number of detected face in a frame
107
- # tuples [] : tuple, length = 2, 각각 0, 프레임 수 the number of frames
108
- tuples = [(0, len(detect_res))] * len(tracks)
109
- # if there is no face detected, find the longest face in the video
110
- if len(tracks) == 0:
111
- tuples, tracks = find_longest(detect_res)
112
- data_storage = {}
113
- frame_boxes = {}
114
- super_clips = []
115
- frame_res = {}
116
- super_clips_start_end = []
117
- # super_clips : tracking된 face들을 의미하는 것으로 보임
118
- for track_i, ((start, end), track) in enumerate(zip(tuples, tracks)): # each track(=face)
119
-
120
- # if detect_res's length is not equal to track's length, raise error
121
- assert len(detect_res[start:end]) == len(track)
122
-
123
- super_clips.append(len(track))
124
- super_clips_start_end.append((start, end))
125
- for face, frame_idx, j in zip(track, range(start, end), range(len(track))): # frame에서 각각의 face
126
- box,lm5,lm68 = face[:3] # box, lm5, lm68
127
- big_box = get_crop_box(shape, box, scale=0.5) # get crop box
128
-
129
- top_left = big_box[:2][None, :] # top left point
130
-
131
- new_lm5 = lm5 - top_left
132
- new_lm68 = lm68 - top_left
133
-
134
- new_box = (box.reshape(2, 2) - top_left).reshape(-1)
135
-
136
- info = (new_box, new_lm5, new_lm68, big_box) # face info
137
-
138
-
139
- x1, y1, x2, y2 = big_box
140
- cropped = frames[frame_idx][y1:y2, x1:x2]
141
- # cropped = cv2.resize(cropped, (512, 512))
142
- # face들을 tracking한 박스들로 crop함
143
- # landmark들도 box에 맞게 변환
144
- # data_storage에 저장 i는 face id, j는 frame을 의미
145
- base_key = f"{track_i}_{j}_" # i : face, j : frame
146
- data_storage[base_key + "img"] = cropped
147
- data_storage[base_key + "ldm"] = info
148
- data_storage[base_key + "idx"] = frame_idx
149
- frame_boxes[frame_idx] = np.rint(box).astype(np.int64)
150
- # 총 crop된 face들과 그 face들의 frame 수를 알려줌
151
- logger.info(f"{crop_path} : sampling clips from super clips {super_clips}")
152
- clips_for_video = []
153
- clip_size = clip_size
154
- pad_length = clip_size - 1
155
-
156
- # 각 face id 별로 clip을 만듦
157
- # 아래의 영어 표기로는 8clip을 의미하지만 정확하겐 clip size 만큼 함
158
- for super_clip_idx, super_clip_size in enumerate(super_clips): # cut the super clip into clips, overlap 7frames, 8frames per clip
159
- inner_index = list(range(super_clip_size))
160
-
161
- if super_clip_size < clip_size: # if there is not enough frames to make a clip, pad the frames
162
- # to do : how to operate the padding
163
- # 정확하게 이 코드가 어떻게 동작하는지 모르겠지만
164
- # 대략적으로 frame들을 clipsize로 나눌때 부족하면
165
- # clip size만큼의 frame이 되도록 padding을 함
166
- if super_clip_size < clip_size//2 : continue
167
- post_module = inner_index[1:-1][::-1] + inner_index
168
-
169
- l_post = len(post_module)
170
- post_module = post_module * (pad_length // l_post + 1)
171
- post_module = post_module[:pad_length]
172
- assert len(post_module) == pad_length
173
-
174
- pre_module = inner_index + inner_index[1:-1][::-1]
175
- l_pre = len(post_module)
176
- pre_module = pre_module * (pad_length // l_pre + 1)
177
- pre_module = pre_module[-pad_length:]
178
- assert len(pre_module) == pad_length
179
-
180
- inner_index = pre_module + inner_index + post_module
181
-
182
- super_clip_size = len(inner_index)
183
-
184
- frame_range = [
185
- inner_index[i : i + clip_size] for i in range(super_clip_size) if i + clip_size <= super_clip_size
186
- ]
187
- for indices in frame_range:
188
- clip = [(super_clip_idx, t) for t in indices]
189
- clips_for_video.append(clip)
190
-
191
- # landmarks, images = crop_align_func(landmarks, images) # i : face, j : frame
192
- processed_clips = 0 # Track number of processed clips
193
- for clip in clips_for_video:
194
- # Check if we've reached the clip limit
195
- if processed_clips >= clip_limit:
196
- logger.info(f"Reached clip limit of {clip_limit}, stopping processing")
197
- break
198
-
199
- # 각 자른 clip에 대해서 진행
200
- images = [data_storage[f"{i}_{j}_img"] for i, j in clip] # call cropped face images from data_storage, i : face, j : frame
201
- landmarks = [data_storage[f"{i}_{j}_ldm"] for i, j in clip] # call landmarks from data_storage, i : face, j : frame
202
- # landmark를 기준으로 crop align func을 진행
203
- # 해당 함수가 clip에 있는 얼굴들의 landmark 평균을 기준으로 박스를 설정하고
204
- # 박스를 기준으로 crop align을 진행
205
- # 다르게 말하면, landmark 평균을 기준으로 박스의 geometry를 설정하고
206
- # 박스의 geometry는 고정한체로 얼굴이 움직이는 걸 찍었다 생각하면 됨
207
- # 다시 또 말하면, 카메라를 고정하고 사람이 움직이는 것을 찍은것처럼
208
- # PPT 참조
209
- landmarks, images = crop_align_func(landmarks, images) # align the face images by landmarks in the clip
210
- i, j = clip[-1]
211
- k = super_clips[i]%clip_size
212
-
213
- ##########################################################################
214
- # 코드 변경시 이 함수에서는 이부분만 변경할 것을 권고 !!!!!!!!!!!!!!!!!!!!!!!!
215
- # 특히, cv2.imwrite함수만 변경할 것을 추천
216
- ##########################################################################
217
- if (j+1)%clip_size==0: # if last frame number of the clip is multiple of clip_size, save all images in the clip
218
- # it means save face alignments in 8 frames in the video so that they don't overlap
219
- for f, (i,j) in enumerate(clip) :
220
- cv2.imwrite(join(crop_path, f'{i:02}_{j:04}.png'), cv2.cvtColor(images[f], cv2.COLOR_BGR2RGB))
221
- if j == super_clips[i]-1: # if the clip have last frame image, save all images in the clip
222
- if k!=0 : # if the clip is not multiple of clip_size, save the last k images in the clip
223
- # k is the number of frames that are not overlapped
224
- for l in range(clip_size-k,clip_size):
225
- ci,cj = clip[l]
226
- cv2.imwrite(join(crop_path, f'{ci:02}_{cj:04}.png'), cv2.cvtColor(images[l], cv2.COLOR_BGR2RGB)) # clip means face alignment images in 8 frames, non-overlap
227
-
228
- processed_clips += 1 # Increment processed clip counter
229
- ##########################################################################
230
-
231
-
232
- if __name__ == '__main__':
233
- p = argparse.ArgumentParser(
234
- formatter_class=argparse.ArgumentDefaultsHelpFormatter
235
- )
236
- p.add_argument('--video_path','-i', type=str, default='/videos.mp4', help='path to input video')
237
- p.add_argument('--save_path','-s', type=str, default='/data/crop_face', help='path to save cropped faces')
238
- p.add_argument('--cachepath', '-c', type=str, default='/data/cache', help='path to cache detection results')
239
- p.add_argument('--clipsize','-l',type=int,default=32, help='number of frames in a clip')
240
- args = p.parse_args()
241
- video_path = args.video_path
242
- save_path = args.save_path
243
- cache_path = args.cachepath
244
- clip_size = args.clipsize
245
-
246
- crop_face_from_video(video_path, cache_path, crop_path, clip_size)
247
-
248
-
249
-
250
-
251
- ###################### reference ######################
252
-
253
- # this code reference from FTCN Official Code in git hub
254
- # link is https://github.com/yinglinzheng/FTCN
255
-
256
- # - Zheng, Y., Bao, J., Chen, D., Zeng, M., & Wen, F. (2021). Exploring Temporal Coherence for More General Video Face Forgery Detection. In Proceedings of the IEEE/CVF International Conference on Computer Vision (pp. 15044–15054).
257
-
258
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
video/pwtf-dvd/model_code/preprocessing/test_tools/__init__.py DELETED
File without changes
video/pwtf-dvd/model_code/preprocessing/test_tools/common.py DELETED
@@ -1,122 +0,0 @@
1
- import os
2
-
3
- os.environ["KMP_DUPLICATE_LIB_OK"] = "TRUE"
4
-
5
- from .ct.detection.utils import grab_all_frames, get_valid_faces, sample_chunks
6
- from .ct.operations import multiple_tracking
7
- import numpy as np
8
- from .ct.face_alignment import LandmarkPredictor
9
- from .ct.detection import FaceDetector
10
- import cv2
11
- from .utils import flatten,partition
12
-
13
-
14
- detector = FaceDetector(0)
15
- predictor = LandmarkPredictor(0)
16
-
17
-
18
- def get_five(ldm68):
19
- groups = [range(36, 42), range(42, 48), [30], [48], [54]]
20
- points = []
21
- for group in groups:
22
- points.append(ldm68[group].mean(0))
23
- return np.array(points)
24
-
25
-
26
- def get_bbox(mask):
27
- try:
28
- y, x = np.nonzero(mask[..., 0])
29
- return x.min() - 1, y.min() - 1, x.max() + 1, y.max() + 1
30
- except:
31
- return None
32
-
33
-
34
- def get_bigger_box(image, box, scale=0.5):
35
- height, width = image.shape[:2]
36
- box = np.rint(box).astype(np.int)
37
- new_box = box.reshape(2, 2)
38
- size = new_box[1] - new_box[0]
39
- diff = scale * size
40
- diff = diff[None, :] * np.array([-1, 1])[:, None]
41
- new_box = new_box + diff
42
- new_box[:, 0] = np.clip(new_box[:, 0], 0, width - 1)
43
- new_box[:, 1] = np.clip(new_box[:, 1], 0, height - 1)
44
- new_box = np.rint(new_box).astype(np.int)
45
- return new_box.reshape(-1)
46
-
47
-
48
- def process_bigger_clips(clips, dete_res, clip_size, step, scale=0.5):
49
- assert len(clips) % clip_size == 0
50
- detect_results = sample_chunks(dete_res, clip_size, step)
51
- clips = sample_chunks(clips, clip_size, step)
52
- new_clips = []
53
- for i, (frame_clip, record_clip) in enumerate(zip(clips, detect_results)):
54
- tracks = multiple_tracking(record_clip)
55
- for j, track in enumerate(tracks):
56
- new_images = []
57
- for (box, ldm, _), frame in zip(track, frame_clip):
58
- big_box = get_bigger_box(frame, box, scale)
59
- x1, y1, x2, y2 = big_box
60
- top_left = big_box[:2][None, :]
61
- new_ldm5 = ldm - top_left
62
- box = np.rint(box).astype(np.int)
63
- new_box = (box.reshape(2, 2) - top_left).reshape(-1)
64
- feed = LandmarkPredictor.prepare_feed(frame, box)
65
- ldm68 = predictor(feed) - top_left
66
- new_images.append(
67
- (frame[y1:y2, x1:x2], big_box, new_box, new_ldm5, ldm68)
68
- )
69
- new_clips.append(new_images)
70
- return new_clips
71
-
72
-
73
- def post(detected_faces):
74
- return [[face[:4], None, face[-1]] for face in detected_faces]
75
-
76
-
77
- def check(detect_res):
78
- return min([len(faces) for faces in detect_res]) != 0
79
-
80
-
81
- def detect_all(file, sfd_only=False, return_frames=False, max_size=None):
82
- frames = grab_all_frames(file, max_size=max_size, cvt=True)
83
- if not sfd_only:
84
- detect_res = flatten(
85
- [detector.detect(item) for item in partition(frames, 50)]
86
- )
87
- detect_res = get_valid_faces(detect_res, thres=0.5)
88
- else:
89
- raise NotImplementedError
90
-
91
- all_68 = get_lm68(frames, detect_res)
92
- if not return_frames:
93
- return detect_res, all_68
94
- else:
95
- return detect_res, all_68, frames
96
-
97
-
98
- def get_lm68(frames, detect_res):
99
- assert len(frames) == len(detect_res)
100
- frame_count = len(frames)
101
- all_68 = []
102
- for i in range(frame_count):
103
- frame = frames[i]
104
- faces = detect_res[i]
105
- if len(faces) == 0:
106
- res_68 = []
107
- else:
108
- feeds = []
109
- for face in faces:
110
- assert len(face) == 3
111
- box = face[0]
112
- feed = LandmarkPredictor.prepare_feed(frame, box)
113
- feeds.append(feed)
114
- res_68 = predictor(feeds)
115
- assert len(res_68) == len(faces)
116
- for face, l_68 in zip(faces, res_68):
117
- if face[1] is None:
118
- face[1] = get_five(l_68)
119
- all_68.append(res_68)
120
-
121
- assert len(all_68) == len(detect_res)
122
- return all_68
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
video/pwtf-dvd/model_code/preprocessing/test_tools/ct/detection/__init__.py DELETED
@@ -1,56 +0,0 @@
1
- import cv2
2
- from .detector import RetinaFace
3
- from .utils import *
4
-
5
-
6
- def assert_bounded(val, low, up):
7
- return val >= low and val < up
8
-
9
-
10
- def check_valid(face, w, h):
11
- box = face[0]
12
- if box[0] > box[2]:
13
- return False
14
- if box[1] > box[3]:
15
- return False
16
- for idx, bound in zip([0, 1, 2, 3], [w, h, w, h]):
17
- if not assert_bounded(box[idx], 0, bound):
18
- return False
19
- pts = face[1]
20
- for p in pts:
21
- for idx, bound in zip([0, 1], [w, h]):
22
- if not assert_bounded(p[idx], 0, bound):
23
- return False
24
- return True
25
-
26
-
27
- def post_detect(detect_results, scale, w, h):
28
- new_results = []
29
- for frame_faces in detect_results:
30
- new_frame_faces = []
31
- for box, ldm, score in frame_faces:
32
- box = box * scale
33
- ldm = ldm * scale
34
- face = (box, ldm, score)
35
- if check_valid(face, w=w, h=h):
36
- new_frame_faces.append(face)
37
- new_results.append(new_frame_faces)
38
- return new_results
39
-
40
-
41
- class FaceDetector(RetinaFace):
42
- def scale_detect(self, images):
43
- max_res = 1920
44
- h, w = images[0].shape[:2]
45
- if max(h, w) > max_res:
46
- init_scale = max(h, w) / max_res
47
- else:
48
- init_scale = 1
49
- resize_scale = 2 * init_scale
50
- resize_w = int(w / resize_scale)
51
- resize_h = int(h / resize_scale)
52
- detect_input = [cv2.resize(frame, (resize_w, resize_h)) for frame in images]
53
- detect_results = post_detect(
54
- self.detect(detect_input), scale=resize_scale, w=w, h=h,
55
- )
56
- return detect_results
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
video/pwtf-dvd/model_code/preprocessing/test_tools/ct/detection/alignment.py DELETED
@@ -1,608 +0,0 @@
1
- from itertools import product as product
2
- from math import ceil
3
-
4
- import numpy as np
5
- import torch
6
- import torch.backends.cudnn as cudnn
7
- import torch.nn as nn
8
- import torch.nn.functional as F
9
- import torchvision.models._utils as _utils
10
-
11
-
12
- def conv_bn(inp, oup, stride=1, leaky=0):
13
- return nn.Sequential(
14
- nn.Conv2d(inp, oup, 3, stride, 1, bias=False),
15
- nn.BatchNorm2d(oup),
16
- nn.LeakyReLU(negative_slope=leaky, inplace=True),
17
- )
18
-
19
-
20
- def conv_bn_no_relu(inp, oup, stride):
21
- return nn.Sequential(
22
- nn.Conv2d(inp, oup, 3, stride, 1, bias=False), nn.BatchNorm2d(oup),
23
- )
24
-
25
-
26
- def conv_bn1X1(inp, oup, stride, leaky=0):
27
- return nn.Sequential(
28
- nn.Conv2d(inp, oup, 1, stride, padding=0, bias=False),
29
- nn.BatchNorm2d(oup),
30
- nn.LeakyReLU(negative_slope=leaky, inplace=True),
31
- )
32
-
33
-
34
- def conv_dw(inp, oup, stride, leaky=0.1):
35
- return nn.Sequential(
36
- nn.Conv2d(inp, inp, 3, stride, 1, groups=inp, bias=False),
37
- nn.BatchNorm2d(inp),
38
- nn.LeakyReLU(negative_slope=leaky, inplace=True),
39
- nn.Conv2d(inp, oup, 1, 1, 0, bias=False),
40
- nn.BatchNorm2d(oup),
41
- nn.LeakyReLU(negative_slope=leaky, inplace=True),
42
- )
43
-
44
-
45
- class SSH(nn.Module):
46
- def __init__(self, in_channel, out_channel):
47
- super(SSH, self).__init__()
48
- assert out_channel % 4 == 0
49
- leaky = 0
50
- if out_channel <= 64:
51
- leaky = 0.1
52
- self.conv3X3 = conv_bn_no_relu(in_channel, out_channel // 2, stride=1)
53
-
54
- self.conv5X5_1 = conv_bn(in_channel, out_channel // 4, stride=1, leaky=leaky)
55
- self.conv5X5_2 = conv_bn_no_relu(out_channel // 4, out_channel // 4, stride=1)
56
-
57
- self.conv7X7_2 = conv_bn(
58
- out_channel // 4, out_channel // 4, stride=1, leaky=leaky
59
- )
60
- self.conv7x7_3 = conv_bn_no_relu(out_channel // 4, out_channel // 4, stride=1)
61
-
62
- def forward(self, input):
63
- conv3X3 = self.conv3X3(input)
64
-
65
- conv5X5_1 = self.conv5X5_1(input)
66
- conv5X5 = self.conv5X5_2(conv5X5_1)
67
-
68
- conv7X7_2 = self.conv7X7_2(conv5X5_1)
69
- conv7X7 = self.conv7x7_3(conv7X7_2)
70
-
71
- out = torch.cat([conv3X3, conv5X5, conv7X7], dim=1)
72
- out = F.relu(out)
73
- return out
74
-
75
-
76
- class FPN(nn.Module):
77
- def __init__(self, in_channels_list, out_channels):
78
- super(FPN, self).__init__()
79
- leaky = 0
80
- if out_channels <= 64:
81
- leaky = 0.1
82
- self.output1 = conv_bn1X1(
83
- in_channels_list[0], out_channels, stride=1, leaky=leaky
84
- )
85
- self.output2 = conv_bn1X1(
86
- in_channels_list[1], out_channels, stride=1, leaky=leaky
87
- )
88
- self.output3 = conv_bn1X1(
89
- in_channels_list[2], out_channels, stride=1, leaky=leaky
90
- )
91
-
92
- self.merge1 = conv_bn(out_channels, out_channels, leaky=leaky)
93
- self.merge2 = conv_bn(out_channels, out_channels, leaky=leaky)
94
-
95
- def forward(self, input):
96
- # names = list(input.keys())
97
- input = list(input.values())
98
-
99
- output1 = self.output1(input[0])
100
- output2 = self.output2(input[1])
101
- output3 = self.output3(input[2])
102
-
103
- up3 = F.interpolate(
104
- output3, size=[output2.size(2), output2.size(3)], mode="nearest"
105
- )
106
- output2 = output2 + up3
107
- output2 = self.merge2(output2)
108
-
109
- up2 = F.interpolate(
110
- output2, size=[output1.size(2), output1.size(3)], mode="nearest"
111
- )
112
- output1 = output1 + up2
113
- output1 = self.merge1(output1)
114
-
115
- out = [output1, output2, output3]
116
- return out
117
-
118
-
119
- class MobileNetV1(nn.Module):
120
- def __init__(self):
121
- super(MobileNetV1, self).__init__()
122
- self.stage1 = nn.Sequential(
123
- conv_bn(3, 8, 2, leaky=0.1), # 3
124
- conv_dw(8, 16, 1), # 7
125
- conv_dw(16, 32, 2), # 11
126
- conv_dw(32, 32, 1), # 19
127
- conv_dw(32, 64, 2), # 27
128
- conv_dw(64, 64, 1), # 43
129
- )
130
- self.stage2 = nn.Sequential(
131
- conv_dw(64, 128, 2), # 43 + 16 = 59
132
- conv_dw(128, 128, 1), # 59 + 32 = 91
133
- conv_dw(128, 128, 1), # 91 + 32 = 123
134
- conv_dw(128, 128, 1), # 123 + 32 = 155
135
- conv_dw(128, 128, 1), # 155 + 32 = 187
136
- conv_dw(128, 128, 1), # 187 + 32 = 219
137
- )
138
- self.stage3 = nn.Sequential(
139
- conv_dw(128, 256, 2), # 219 +3 2 = 241
140
- conv_dw(256, 256, 1), # 241 + 64 = 301
141
- )
142
- self.avg = nn.AdaptiveAvgPool2d((1, 1))
143
- self.fc = nn.Linear(256, 1000)
144
-
145
- def forward(self, x):
146
- x = self.stage1(x)
147
- x = self.stage2(x)
148
- x = self.stage3(x)
149
- x = self.avg(x)
150
- # x = self.model(x)
151
- x = x.view(-1, 256)
152
- x = self.fc(x)
153
- return x
154
-
155
-
156
- class ClassHead(nn.Module):
157
- def __init__(self, inchannels=512, num_anchors=3):
158
- super(ClassHead, self).__init__()
159
- self.num_anchors = num_anchors
160
- self.conv1x1 = nn.Conv2d(
161
- inchannels, self.num_anchors * 2, kernel_size=(1, 1), stride=1, padding=0
162
- )
163
-
164
- def forward(self, x):
165
- out = self.conv1x1(x)
166
- out = out.permute(0, 2, 3, 1).contiguous()
167
-
168
- return out.view(out.shape[0], -1, 2)
169
-
170
-
171
- class BboxHead(nn.Module):
172
- def __init__(self, inchannels=512, num_anchors=3):
173
- super(BboxHead, self).__init__()
174
- self.conv1x1 = nn.Conv2d(
175
- inchannels, num_anchors * 4, kernel_size=(1, 1), stride=1, padding=0
176
- )
177
-
178
- def forward(self, x):
179
- out = self.conv1x1(x)
180
- out = out.permute(0, 2, 3, 1).contiguous()
181
-
182
- return out.view(out.shape[0], -1, 4)
183
-
184
-
185
- class LandmarkHead(nn.Module):
186
- def __init__(self, inchannels=512, num_anchors=3):
187
- super(LandmarkHead, self).__init__()
188
- self.conv1x1 = nn.Conv2d(
189
- inchannels, num_anchors * 10, kernel_size=(1, 1), stride=1, padding=0
190
- )
191
-
192
- def forward(self, x):
193
- out = self.conv1x1(x)
194
- out = out.permute(0, 2, 3, 1).contiguous()
195
-
196
- return out.view(out.shape[0], -1, 10)
197
-
198
-
199
- class RetinaFace(nn.Module):
200
- def __init__(self, cfg=None, phase="train"):
201
- """
202
- :param cfg: Network related settings.
203
- :param phase: train or test.
204
- """
205
- super(RetinaFace, self).__init__()
206
- self.phase = phase
207
- backbone = None
208
- if cfg["name"] == "mobilenet0.25":
209
- backbone = MobileNetV1()
210
- elif cfg["name"] == "Resnet50":
211
- import torchvision.models as models
212
-
213
- backbone = models.resnet50(pretrained=cfg["pretrain"])
214
-
215
- self.body = _utils.IntermediateLayerGetter(backbone, cfg["return_layers"])
216
- in_channels_stage2 = cfg["in_channel"]
217
- in_channels_list = [
218
- in_channels_stage2 * 2,
219
- in_channels_stage2 * 4,
220
- in_channels_stage2 * 8,
221
- ]
222
- out_channels = cfg["out_channel"]
223
- self.fpn = FPN(in_channels_list, out_channels)
224
- self.ssh1 = SSH(out_channels, out_channels)
225
- self.ssh2 = SSH(out_channels, out_channels)
226
- self.ssh3 = SSH(out_channels, out_channels)
227
-
228
- self.ClassHead = self._make_class_head(fpn_num=3, inchannels=cfg["out_channel"])
229
- self.BboxHead = self._make_bbox_head(fpn_num=3, inchannels=cfg["out_channel"])
230
- self.LandmarkHead = self._make_landmark_head(
231
- fpn_num=3, inchannels=cfg["out_channel"]
232
- )
233
-
234
- def _make_class_head(self, fpn_num=3, inchannels=64, anchor_num=2):
235
- classhead = nn.ModuleList()
236
- for i in range(fpn_num):
237
- classhead.append(ClassHead(inchannels, anchor_num))
238
- return classhead
239
-
240
- def _make_bbox_head(self, fpn_num=3, inchannels=64, anchor_num=2):
241
- bboxhead = nn.ModuleList()
242
- for i in range(fpn_num):
243
- bboxhead.append(BboxHead(inchannels, anchor_num))
244
- return bboxhead
245
-
246
- def _make_landmark_head(self, fpn_num=3, inchannels=64, anchor_num=2):
247
- landmarkhead = nn.ModuleList()
248
- for i in range(fpn_num):
249
- landmarkhead.append(LandmarkHead(inchannels, anchor_num))
250
- return landmarkhead
251
-
252
- def forward(self, inputs):
253
- out = self.body(inputs)
254
-
255
- # FPN
256
- fpn = self.fpn(out)
257
-
258
- # SSH
259
- feature1 = self.ssh1(fpn[0])
260
- feature2 = self.ssh2(fpn[1])
261
- feature3 = self.ssh3(fpn[2])
262
- features = [feature1, feature2, feature3]
263
-
264
- bbox_regressions = torch.cat(
265
- [self.BboxHead[i](feature) for i, feature in enumerate(features)], dim=1
266
- )
267
- classifications = torch.cat(
268
- [self.ClassHead[i](feature) for i, feature in enumerate(features)], dim=1
269
- )
270
- ldm_regressions = torch.cat(
271
- [self.LandmarkHead[i](feature) for i, feature in enumerate(features)], dim=1
272
- )
273
-
274
- if self.phase == "train":
275
- output = (bbox_regressions, classifications, ldm_regressions)
276
- else:
277
- output = (
278
- bbox_regressions,
279
- F.softmax(classifications, dim=-1),
280
- ldm_regressions,
281
- )
282
- return output
283
-
284
-
285
- # Adapted from https://github.com/Hakuyume/chainer-ssd
286
- def decode(loc, priors, variances):
287
- boxes = torch.cat(
288
- (
289
- priors[:, :2] + loc[:, :2] * variances[0] * priors[:, 2:],
290
- priors[:, 2:] * torch.exp(loc[:, 2:] * variances[1]),
291
- ),
292
- 1,
293
- )
294
- boxes[:, :2] -= boxes[:, 2:] / 2
295
- boxes[:, 2:] += boxes[:, :2]
296
- return boxes
297
-
298
-
299
- def decode_landm(pre, priors, variances):
300
- landms = torch.cat(
301
- (
302
- priors[:, :2] + pre[:, :2] * variances[0] * priors[:, 2:],
303
- priors[:, :2] + pre[:, 2:4] * variances[0] * priors[:, 2:],
304
- priors[:, :2] + pre[:, 4:6] * variances[0] * priors[:, 2:],
305
- priors[:, :2] + pre[:, 6:8] * variances[0] * priors[:, 2:],
306
- priors[:, :2] + pre[:, 8:10] * variances[0] * priors[:, 2:],
307
- ),
308
- dim=1,
309
- )
310
- return landms
311
-
312
-
313
- def py_cpu_nms(dets, thresh):
314
- """Pure Python NMS baseline."""
315
- x1 = dets[:, 0]
316
- y1 = dets[:, 1]
317
- x2 = dets[:, 2]
318
- y2 = dets[:, 3]
319
- scores = dets[:, 4]
320
-
321
- areas = (x2 - x1 + 1) * (y2 - y1 + 1)
322
- order = scores.argsort()[::-1]
323
-
324
- keep = []
325
- while order.size > 0:
326
- i = order[0]
327
- keep.append(i)
328
- xx1 = np.maximum(x1[i], x1[order[1:]])
329
- yy1 = np.maximum(y1[i], y1[order[1:]])
330
- xx2 = np.minimum(x2[i], x2[order[1:]])
331
- yy2 = np.minimum(y2[i], y2[order[1:]])
332
-
333
- w = np.maximum(0.0, xx2 - xx1 + 1)
334
- h = np.maximum(0.0, yy2 - yy1 + 1)
335
- inter = w * h
336
- ovr = inter / (areas[i] + areas[order[1:]] - inter)
337
-
338
- inds = np.where(ovr <= thresh)[0]
339
- order = order[inds + 1]
340
-
341
- return keep
342
-
343
-
344
- class PriorBox(object):
345
- def __init__(self, cfg, image_size=None, phase="train"):
346
- super(PriorBox, self).__init__()
347
- self.min_sizes = cfg["min_sizes"]
348
- self.steps = cfg["steps"]
349
- self.clip = cfg["clip"]
350
- self.image_size = image_size
351
- self.feature_maps = [
352
- [ceil(self.image_size[0] / step), ceil(self.image_size[1] / step)]
353
- for step in self.steps
354
- ]
355
- self.name = "s"
356
-
357
- def forward(self):
358
- anchors = []
359
- for k, f in enumerate(self.feature_maps):
360
- min_sizes = self.min_sizes[k]
361
- for i, j in product(range(f[0]), range(f[1])):
362
- for min_size in min_sizes:
363
- s_kx = min_size / self.image_size[1]
364
- s_ky = min_size / self.image_size[0]
365
- dense_cx = [
366
- x * self.steps[k] / self.image_size[1] for x in [j + 0.5]
367
- ]
368
- dense_cy = [
369
- y * self.steps[k] / self.image_size[0] for y in [i + 0.5]
370
- ]
371
- for cy, cx in product(dense_cy, dense_cx):
372
- anchors += [cx, cy, s_kx, s_ky]
373
-
374
- # back to torch land
375
- output = torch.Tensor(anchors).view(-1, 4)
376
- if self.clip:
377
- output.clamp_(max=1, min=0)
378
- return output
379
-
380
-
381
- cfg_mnet = {
382
- "name": "mobilenet0.25",
383
- "min_sizes": [[16, 32], [64, 128], [256, 512]],
384
- "steps": [8, 16, 32],
385
- "variance": [0.1, 0.2],
386
- "clip": False,
387
- "loc_weight": 2.0,
388
- "gpu_train": True,
389
- "batch_size": 32,
390
- "ngpu": 1,
391
- "epoch": 250,
392
- "decay1": 190,
393
- "decay2": 220,
394
- "image_size": 640,
395
- "pretrain": True,
396
- "return_layers": {"stage1": 1, "stage2": 2, "stage3": 3},
397
- "in_channel": 32,
398
- "out_channel": 64,
399
- }
400
-
401
- cfg_re50 = {
402
- "name": "Resnet50",
403
- "min_sizes": [[16, 32], [64, 128], [256, 512]],
404
- "steps": [8, 16, 32],
405
- "variance": [0.1, 0.2],
406
- "clip": False,
407
- "loc_weight": 2.0,
408
- "gpu_train": True,
409
- "batch_size": 24,
410
- "ngpu": 4,
411
- "epoch": 100,
412
- "decay1": 70,
413
- "decay2": 90,
414
- "image_size": 840,
415
- "pretrain": False,
416
- "return_layers": {"layer2": 1, "layer3": 2, "layer4": 3},
417
- "in_channel": 256,
418
- "out_channel": 256,
419
- }
420
-
421
-
422
- def check_keys(model, pretrained_state_dict):
423
- ckpt_keys = set(pretrained_state_dict.keys())
424
- model_keys = set(model.state_dict().keys())
425
- used_pretrained_keys = model_keys & ckpt_keys
426
- assert len(used_pretrained_keys) > 0, "load NONE from pretrained checkpoint"
427
- return True
428
-
429
-
430
- def remove_prefix(state_dict, prefix):
431
- """ Old style model is stored with all names of parameters sharing common prefix 'module.' """
432
- f = lambda x: x.split(prefix, 1)[-1] if x.startswith(prefix) else x
433
- return {f(key): value for key, value in state_dict.items()}
434
-
435
-
436
- def load_model(model, pretrained_path, load_to_cpu):
437
- if load_to_cpu:
438
- if pretrained_path is None:
439
- url = "https://github.com/yinglinzheng/face_weights/releases/download/v1/mobilenet0.25_Final.pth"
440
- pretrained_dict = torch.utils.model_zoo.load_url(url)
441
- else:
442
- pretrained_dict = torch.load(
443
- pretrained_path, map_location=lambda storage, loc: storage
444
- )
445
- else:
446
- device = torch.cuda.current_device()
447
- pretrained_dict = torch.load(
448
- pretrained_path, map_location=lambda storage, loc: storage.cuda(device)
449
- )
450
- if "state_dict" in pretrained_dict.keys():
451
- pretrained_dict = remove_prefix(pretrained_dict["state_dict"], "module.")
452
- else:
453
- pretrained_dict = remove_prefix(pretrained_dict, "module.")
454
- check_keys(model, pretrained_dict)
455
- model.load_state_dict(pretrained_dict, strict=False)
456
- return model
457
-
458
-
459
- def load_net(model_path, device, network="mobilenet"):
460
- if network == "mobilenet":
461
- cfg = cfg_mnet
462
- elif network == "resnet50":
463
- cfg = cfg_re50
464
- # net and model
465
- net = RetinaFace(cfg=cfg, phase="test")
466
- net = load_model(net, model_path, True)
467
- net.eval()
468
- cudnn.benchmark = True
469
- net = net.to(device)
470
- return net
471
-
472
-
473
- def parse_det(det):
474
- landmarks = det[5:].reshape(5, 2)
475
- box = det[:4]
476
- score = det[4]
477
- return box, landmarks, score
478
-
479
-
480
- def post_process(
481
- loc,
482
- conf,
483
- landms,
484
- prior_data,
485
- cfg,
486
- scale,
487
- scale1,
488
- resize,
489
- confidence_threshold,
490
- top_k,
491
- nms_threshold,
492
- keep_top_k,
493
- ):
494
- boxes = decode(loc, prior_data, cfg["variance"])
495
- boxes = boxes * scale / resize
496
- boxes = boxes.cpu().numpy()
497
- scores = conf.cpu().numpy()[:, 1]
498
- landms_copy = decode_landm(landms, prior_data, cfg["variance"])
499
-
500
- landms_copy = landms_copy * scale1 / resize
501
- landms_copy = landms_copy.cpu().numpy()
502
-
503
- # ignore low scores
504
- inds = np.where(scores > confidence_threshold)[0]
505
- boxes = boxes[inds]
506
- landms_copy = landms_copy[inds]
507
- scores = scores[inds]
508
-
509
- # keep top-K before NMS
510
- order = scores.argsort()[::-1][:top_k]
511
- boxes = boxes[order]
512
- landms_copy = landms_copy[order]
513
- scores = scores[order]
514
-
515
- # do NMS
516
- dets = np.hstack((boxes, scores[:, np.newaxis])).astype(np.float32, copy=False)
517
- keep = py_cpu_nms(dets, nms_threshold)
518
- # keep = nms(dets, args.nms_threshold,force_cpu=args.cpu)
519
- dets = dets[keep, :]
520
- landms_copy = landms_copy[keep]
521
-
522
- # keep top-K faster NMS
523
- dets = dets[:keep_top_k, :]
524
- landms_copy = landms_copy[:keep_top_k, :]
525
-
526
- dets = np.concatenate((dets, landms_copy), axis=1)
527
- # show image
528
- dets = sorted(dets, key=lambda x: x[4], reverse=True)
529
- dets = [parse_det(x) for x in dets]
530
-
531
- return dets
532
-
533
-
534
- def batch_detect(net, images, device, is_tensor=False, normalized=False):
535
- with torch.no_grad():
536
- confidence_threshold = 0.02
537
- cfg = cfg_mnet
538
- top_k = 5000
539
- nms_threshold = 0.4
540
- keep_top_k = 750
541
- resize = 1
542
- if not is_tensor:
543
- try:
544
- img = np.float32(images)
545
- except ValueError:
546
- raise NotImplementedError("Input images must of same size")
547
- img = torch.from_numpy(img)
548
- else:
549
- img = images.float()
550
- img = img.to(device)
551
- mean = (
552
- torch.as_tensor([104, 117, 123], dtype=img.dtype, device=img.device)
553
- .unsqueeze(0)
554
- .unsqueeze(0)
555
- .unsqueeze(0)
556
- )
557
- img -= mean
558
- img = img.permute(0, 3, 1, 2)
559
- (batch_size, _, im_height, im_width,) = img.shape
560
- scale = torch.as_tensor(
561
- [im_width, im_height, im_width, im_height],
562
- dtype=img.dtype,
563
- device=img.device,
564
- )
565
- scale = scale.to(device)
566
-
567
- loc, conf, landms = net(img) # forward pass
568
-
569
- priorbox = PriorBox(cfg, image_size=(im_height, im_width))
570
- priors = priorbox.forward()
571
- prior_data = priors.to(device)
572
- scale1 = torch.as_tensor(
573
- [
574
- img.shape[3],
575
- img.shape[2],
576
- img.shape[3],
577
- img.shape[2],
578
- img.shape[3],
579
- img.shape[2],
580
- img.shape[3],
581
- img.shape[2],
582
- img.shape[3],
583
- img.shape[2],
584
- ],
585
- dtype=img.dtype,
586
- device=img.device,
587
- )
588
- scale1 = scale1.to(device)
589
-
590
- all_dets = [
591
- post_process(
592
- loc_i,
593
- conf_i,
594
- landms_i,
595
- prior_data,
596
- cfg,
597
- scale,
598
- scale1,
599
- resize,
600
- confidence_threshold,
601
- top_k,
602
- nms_threshold,
603
- keep_top_k,
604
- )
605
- for loc_i, conf_i, landms_i in zip(loc, conf, landms)
606
- ]
607
-
608
- return all_dets
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
video/pwtf-dvd/model_code/preprocessing/test_tools/ct/detection/detector.py DELETED
@@ -1,46 +0,0 @@
1
- import os
2
-
3
- import numpy as np
4
- import torch
5
-
6
- from .alignment import load_net, batch_detect
7
-
8
-
9
- def get_project_dir():
10
- current_path = os.path.abspath(os.path.join(__file__, "../"))
11
- return current_path
12
-
13
-
14
- def relative(path):
15
- path = os.path.join(get_project_dir(), path)
16
- return os.path.abspath(path)
17
-
18
-
19
- class RetinaFace:
20
- def __init__(
21
- self, gpu_id=-1, model_path=None, network="mobilenet",
22
- ):
23
- self.gpu_id = gpu_id
24
- self.device = (
25
- torch.device("cpu") if gpu_id == -1 else torch.device("cuda", gpu_id)
26
- )
27
- self.model = load_net(model_path, self.device, network)
28
-
29
- def detect(self, images):
30
- if isinstance(images, np.ndarray):
31
- if len(images.shape) == 3:
32
- return batch_detect(self.model, [images], self.device)[0]
33
- elif len(images.shape) == 4:
34
- return batch_detect(self.model, images, self.device)
35
- elif isinstance(images, list):
36
- return batch_detect(self.model, np.array(images), self.device)
37
- elif isinstance(images, torch.Tensor):
38
- if len(images.shape) == 3:
39
- return batch_detect(self.model, images.unsqueeze(0), self.device)[0]
40
- elif len(images.shape) == 4:
41
- return batch_detect(self.model, images, self.device)
42
- else:
43
- raise NotImplementedError()
44
-
45
- def __call__(self, images):
46
- return self.detect(images)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
video/pwtf-dvd/model_code/preprocessing/test_tools/ct/detection/utils.py DELETED
@@ -1,147 +0,0 @@
1
- import cv2
2
- # from test_tools.utils import flatten
3
- import numpy as np
4
- def flatten(l):
5
- return [item for sublist in l for item in sublist]
6
-
7
- def chunks(l, n, step=None):
8
- if step is None:
9
- step = n
10
- return [l[i : i + n] for i in range(0, len(l), step)]
11
-
12
-
13
- def sample_chunks(l, n, step=None):
14
- return [l[i : i + n] for i in range(0, len(l), step) if i + n <= len(l)]
15
-
16
-
17
- def grab_all_frames(path, max_size, cvt=False):
18
- capture = cv2.VideoCapture(path)
19
- ret = True
20
- frames = []
21
- while ret:
22
- ret, frame = capture.read()
23
- if ret:
24
- if cvt:
25
- frame = frame[..., ::-1]
26
- frames.append(frame)
27
- if len(frames) == max_size:
28
- break
29
- capture.release()
30
- return frames
31
-
32
-
33
- def get_clips_uniform(path, count, clip_size):
34
- capture = cv2.VideoCapture(path)
35
- n_frames = int(capture.get(cv2.CAP_PROP_FRAME_COUNT))
36
- max_clip_available = n_frames + 1 - clip_size
37
- if count > max_clip_available:
38
- count = max_clip_available
39
- final_start = max_clip_available - 1
40
- start_indices = np.linspace(0, final_start, count, endpoint=True, dtype=np.int)
41
- all_clip_idx = [list(range(start, start + clip_size)) for start in start_indices]
42
- valid = set(flatten(all_clip_idx))
43
- max_idx = max(valid)
44
-
45
- frames = {}
46
- for idx in range(max_idx + 1):
47
- # Get the next frame, but don't decode if we're not using it.
48
- ret = capture.grab()
49
- if not ret:
50
- continue
51
-
52
- if idx in valid:
53
- ret, frame = capture.retrieve()
54
- if not ret or frame is None:
55
- continue
56
- else:
57
- # frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
58
- frames[idx] = frame
59
-
60
- capture.release()
61
- clips = []
62
- for clip_idx in all_clip_idx:
63
- clip = []
64
- flag = True
65
- for idx in clip_idx:
66
- if idx not in frames:
67
- flag = False
68
- break
69
- clip.append(frames[idx])
70
- if flag:
71
- clips.append(clip)
72
- return clips
73
-
74
-
75
- def get_valid_faces(detect_results, max_count=10, thres=0.5, at_least=False):
76
- new_results = []
77
- for i, faces in enumerate(detect_results):
78
- if len(faces) > max_count:
79
- faces = faces[:max_count]
80
- l = []
81
- for j, face in enumerate(faces):
82
- if face[-1] < thres and not (j == 0 and at_least):
83
- continue
84
- box, lm, score = face
85
- box = box.astype(np.float64)
86
- lm = lm.astype(np.float64)
87
- l.append((box, lm, score))
88
- new_results.append(l)
89
- return new_results
90
-
91
-
92
- def scale_box(box, scale_h, scale_w, h, w):
93
- x1, y1, x2, y2 = box.astype(np.int32)
94
- center_x = (x1 + x2) // 2
95
- center_y = (y1 + y2) // 2
96
- box_h = int((y2 - y1) * scale_h)
97
- box_w = int((x2 - x1) * scale_w)
98
- new_x1 = center_x - box_w // 2
99
- new_x2 = new_x1 + box_w
100
- new_y1 = center_y - box_h // 2
101
- new_y2 = new_y1 + box_h
102
- new_x1 = max(new_x1, 0)
103
- new_y1 = max(new_y1, 0)
104
- new_y2 = min(new_y2, h)
105
- new_x2 = min(new_x2, w)
106
- return new_x1, new_y1, new_x2, new_y2
107
-
108
-
109
- def get_bbox(detect_res):
110
- tmp_detect_res = get_valid_faces(detect_res, max_count=4, thres=0.5)
111
- all_face_bboxs = []
112
- for faces in tmp_detect_res:
113
- all_face_bboxs.extend([face[0] for face in faces])
114
- all_face_bboxs = np.array(all_face_bboxs).astype(np.int)
115
- x1 = all_face_bboxs[:, 0].min()
116
- x2 = all_face_bboxs[:, 2].max()
117
- y1 = all_face_bboxs[:, 1].min()
118
- y2 = all_face_bboxs[:, 3].max()
119
-
120
- return x1, y1, x2, y2
121
-
122
-
123
- def delta_detect_res(detect_res, x1, y1):
124
- diff = np.array([[x1, y1]])
125
- new_detect_res = []
126
- for faces in detect_res:
127
- f = []
128
- for face in faces:
129
- box, lm, score = face
130
- box = box.astype(np.float64)
131
- box[[0, 2]] -= x1
132
- box[[1, 3]] -= y1
133
- lm = lm.astype(np.float64) - diff
134
- f.append((box, lm, score))
135
- new_detect_res.append(f)
136
- return new_detect_res
137
-
138
-
139
- def pre_crop(clips, detect_res):
140
- box = np.array(get_bbox(detect_res))
141
- w = box[2] - box[0]
142
- h = box[3] - box[1]
143
- x1, y1, x2, y2 = scale_box(
144
- box, 1.5, 1.2 if w > 2 * h else 1.5, clips[0].shape[0], clips[0].shape[1]
145
- )
146
- clips = np.array(clips)
147
- return clips[:, y1:y2, x1:x2], delta_detect_res(detect_res, x1, y1)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
video/pwtf-dvd/model_code/preprocessing/test_tools/ct/face_alignment/__init__.py DELETED
@@ -1 +0,0 @@
1
- from .predictor import LandmarkPredictor
 
 
video/pwtf-dvd/model_code/preprocessing/test_tools/ct/face_alignment/basenet.py DELETED
@@ -1,107 +0,0 @@
1
- # Backbone networks used for face landmark detection
2
- # Cunjian Chen (cunjian@msu.edu)
3
-
4
- import torch.nn as nn
5
- import torchvision.models as models
6
-
7
-
8
- class ConvBlock(nn.Module):
9
- def __init__(self, inp, oup, k, s, p, dw=False, linear=False):
10
- super(ConvBlock, self).__init__()
11
- self.linear = linear
12
- if dw:
13
- self.conv = nn.Conv2d(inp, oup, k, s, p, groups=inp, bias=False)
14
- else:
15
- self.conv = nn.Conv2d(inp, oup, k, s, p, bias=False)
16
- self.bn = nn.BatchNorm2d(oup)
17
- if not linear:
18
- self.prelu = nn.PReLU(oup)
19
-
20
- def forward(self, x):
21
- x = self.conv(x)
22
- x = self.bn(x)
23
- if self.linear:
24
- return x
25
- else:
26
- return self.prelu(x)
27
-
28
-
29
- # SE module
30
- # https://github.com/wujiyang/Face_Pytorch/blob/master/backbone/cbam.py
31
- class SEModule(nn.Module):
32
- """Squeeze and Excitation Module"""
33
-
34
- def __init__(self, channels, reduction):
35
- super(SEModule, self).__init__()
36
- self.avg_pool = nn.AdaptiveAvgPool2d(1)
37
- self.fc1 = nn.Conv2d(
38
- channels, channels // reduction, kernel_size=1, padding=0, bias=False
39
- )
40
- self.relu = nn.ReLU(inplace=True)
41
- self.fc2 = nn.Conv2d(
42
- channels // reduction, channels, kernel_size=1, padding=0, bias=False
43
- )
44
- self.sigmoid = nn.Sigmoid()
45
-
46
- def forward(self, x):
47
- input = x
48
- x = self.avg_pool(x)
49
- x = self.fc1(x)
50
- x = self.relu(x)
51
- x = self.fc2(x)
52
- x = self.sigmoid(x)
53
-
54
- return input * x
55
-
56
-
57
- # USE global depthwise convolution layer. Compatible with MobileNetV2 (224×224), MobileNetV2_ExternalData (224×224)
58
- class MobileNet_GDConv(nn.Module):
59
- def __init__(self, num_classes):
60
- super(MobileNet_GDConv, self).__init__()
61
- self.pretrain_net = models.mobilenet_v2(pretrained=False)
62
- self.base_net = nn.Sequential(*list(self.pretrain_net.children())[:-1])
63
- self.linear7 = ConvBlock(1280, 1280, (7, 7), 1, 0, dw=True, linear=True)
64
- self.linear1 = ConvBlock(1280, num_classes, 1, 1, 0, linear=True)
65
-
66
- def forward(self, x):
67
- x = self.base_net(x)
68
- x = self.linear7(x)
69
- x = self.linear1(x)
70
- x = x.view(x.size(0), -1)
71
- return x
72
-
73
-
74
- # USE global depthwise convolution layer. Compatible with MobileNetV2 (56×56)
75
- class MobileNet_GDConv_56(nn.Module):
76
- def __init__(self, num_classes):
77
- super(MobileNet_GDConv_56, self).__init__()
78
- self.pretrain_net = models.mobilenet_v2(pretrained=False)
79
- self.base_net = nn.Sequential(*list(self.pretrain_net.children())[:-1])
80
- self.linear7 = ConvBlock(1280, 1280, (2, 2), 1, 0, dw=True, linear=True)
81
- self.linear1 = ConvBlock(1280, num_classes, 1, 1, 0, linear=True)
82
-
83
- def forward(self, x):
84
- x = self.base_net(x)
85
- x = self.linear7(x)
86
- x = self.linear1(x)
87
- x = x.view(x.size(0), -1)
88
- return x
89
-
90
-
91
- # MobileNetV2 with SE; Compatible with MobileNetV2_SE (224×224) and MobileNetV2_SE_RE (224×224)
92
- class MobileNet_GDConv_SE(nn.Module):
93
- def __init__(self, num_classes):
94
- super(MobileNet_GDConv_SE, self).__init__()
95
- self.pretrain_net = models.mobilenet_v2(pretrained=True)
96
- self.base_net = nn.Sequential(*list(self.pretrain_net.children())[:-1])
97
- self.linear7 = ConvBlock(1280, 1280, (7, 7), 1, 0, dw=True, linear=True)
98
- self.linear1 = ConvBlock(1280, num_classes, 1, 1, 0, linear=True)
99
- self.attention = SEModule(1280, 8)
100
-
101
- def forward(self, x):
102
- x = self.base_net(x)
103
- x = self.attention(x)
104
- x = self.linear7(x)
105
- x = self.linear1(x)
106
- x = x.view(x.size(0), -1)
107
- return x
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
video/pwtf-dvd/model_code/preprocessing/test_tools/ct/face_alignment/predictor.py DELETED
@@ -1,143 +0,0 @@
1
- # Face alignment demo
2
- # Uses MTCNN as face detector
3
- # Cunjian Chen (ccunjian@gmail.com)
4
- import torch
5
- import cv2
6
- import numpy as np
7
- from torch.utils.data import DataLoader
8
- from .basenet import MobileNet_GDConv
9
-
10
-
11
- def get_device(gpu_id):
12
- if gpu_id > -1:
13
- return torch.device(f"cuda:{str(gpu_id)}")
14
- else:
15
- return torch.device("cpu")
16
-
17
-
18
- def load_model(file):
19
- model = MobileNet_GDConv(136)
20
- if file is not None:
21
- model.load_state_dict(torch.load(file, map_location="cpu"))
22
- else:
23
- url = "https://github.com/yinglinzheng/face_weights/releases/download/v1/mobilenet_224_model_best_gdconv_external.pth"
24
- model.load_state_dict(torch.utils.model_zoo.load_url(url))
25
- return model
26
-
27
-
28
- # landmark of (5L, 2L) from [0,1] to real range
29
- def reproject(bbox, landmark):
30
- landmark_ = landmark.clone()
31
- x1, y1, x2, y2 = bbox
32
- w = x2 - x1
33
- h = y2 - y1
34
- landmark_[:, 0] *= w
35
- landmark_[:, 0] += x1
36
- landmark_[:, 1] *= h
37
- landmark_[:, 1] += y1
38
- return landmark_
39
-
40
-
41
- def prepare_feed(img, face):
42
- height, width, _ = img.shape
43
- mean = np.asarray([0.485, 0.456, 0.406])
44
- std = np.asarray([0.229, 0.224, 0.225])
45
- out_size = 224
46
- x1, y1, x2, y2 = face[:4]
47
-
48
- w = x2 - x1 + 1
49
- h = y2 - y1 + 1
50
- size = int(min([w, h]) * 1.2)
51
- cx = x1 + w // 2
52
- cy = y1 + h // 2
53
- x1 = cx - size // 2
54
- x2 = x1 + size
55
- y1 = cy - size // 2
56
- y2 = y1 + size
57
-
58
- dx = max(0, -x1)
59
- dy = max(0, -y1)
60
- x1 = max(0, x1)
61
- y1 = max(0, y1)
62
-
63
- edx = max(0, x2 - width)
64
- edy = max(0, y2 - height)
65
- x2 = min(width, x2)
66
- y2 = min(height, y2)
67
- new_bbox = torch.Tensor([x1, y1, x2, y2]).int()
68
- x1, y1, x2, y2 = new_bbox
69
- cropped = img[y1:y2, x1:x2]
70
- if dx > 0 or dy > 0 or edx > 0 or edy > 0:
71
- cropped = cv2.copyMakeBorder(
72
- cropped, int(dy), int(edy), int(dx), int(edx), cv2.BORDER_CONSTANT, 0
73
- )
74
- cropped_face = cv2.resize(cropped, (out_size, out_size))
75
-
76
- if cropped_face.shape[0] <= 0 or cropped_face.shape[1] <= 0:
77
- return None
78
- test_face = cropped_face.copy()
79
- test_face = test_face / 255.0
80
- test_face = (test_face - mean) / std
81
- test_face = test_face.transpose((2, 0, 1))
82
- data = torch.from_numpy(test_face).float()
83
- return dict(data=data, bbox=new_bbox)
84
-
85
-
86
- @torch.no_grad()
87
- def single_predict(model, feed, device):
88
- landmark = model(feed["data"].unsqueeze(0).to(device)).cpu()
89
- landmark = landmark.reshape(-1, 2)
90
- landmark = reproject(feed["bbox"], landmark)
91
- return landmark.numpy()
92
-
93
-
94
- @torch.no_grad()
95
- def batch_predict(model, feeds, device):
96
- if not isinstance(feeds, list):
97
- feeds = [feeds]
98
- # loader = DataLoader(FeedDataset(feeds), batch_size=50, shuffle=False)
99
- data = []
100
- for feed in feeds:
101
- data.append(feed["data"].unsqueeze(0))
102
- data = torch.cat(data, 0).to(device)
103
- results = []
104
-
105
- landmarks = model(data).cpu()
106
- for landmark, feed in zip(landmarks, feeds):
107
- landmark = landmark.reshape(-1, 2)
108
- landmark = reproject(feed["bbox"], landmark)
109
- results.append(landmark.numpy())
110
- return results
111
-
112
-
113
- @torch.no_grad()
114
- def batch_predict2(model, feeds, device, batch_size=None):
115
- if not isinstance(feeds, list):
116
- feeds = [feeds]
117
- if batch_size is None:
118
- batch_size = len(feeds)
119
- loader = DataLoader(feeds, batch_size=len(feeds), shuffle=False)
120
- results = []
121
- for feed in loader:
122
- landmarks = model(feed["data"].to(device)).cpu()
123
- for landmark, bbox in zip(landmarks, feed["bbox"]):
124
- landmark = landmark.reshape(-1, 2)
125
- landmark = reproject(bbox, landmark)
126
- results.append(landmark.numpy())
127
- return results
128
-
129
-
130
- class LandmarkPredictor:
131
- def __init__(self, gpu_id=0, file=None):
132
- self.device = get_device(gpu_id)
133
- self.model = load_model(file).to(self.device).eval()
134
-
135
- def __call__(self, feeds):
136
- results = batch_predict2(self.model, feeds, self.device)
137
- if not isinstance(feeds, list):
138
- results = results[0]
139
- return results
140
-
141
- @staticmethod
142
- def prepare_feed(img, face):
143
- return prepare_feed(img, face)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
video/pwtf-dvd/model_code/preprocessing/test_tools/ct/face_alignment/utils.py DELETED
@@ -1,17 +0,0 @@
1
- import cv2
2
-
3
-
4
- def drawLandmark_multiple(img, bbox, landmark):
5
- """
6
- Input:
7
- - img: gray or RGB
8
- - bbox: type of BBox
9
- - landmark: reproject landmark of (5L, 2L)
10
- Output:
11
- - img marked with landmark and bbox
12
- """
13
- x1, y1, x2, y2 = bbox
14
- cv2.rectangle(img, (x1, y1), (x2, y2), (0, 0, 255), 2)
15
- for x, y in landmark:
16
- cv2.circle(img, (int(x), int(y)), 2, (0, 255, 0), -1)
17
- return img
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
video/pwtf-dvd/model_code/preprocessing/test_tools/ct/operations.py DELETED
@@ -1,79 +0,0 @@
1
- import os
2
-
3
- import os
4
- import cv2
5
- import numpy as np
6
- from .tracking.sort import iou
7
-
8
-
9
- def face_iou(f1, f2):
10
- return iou(f1[0], f2[0])
11
-
12
-
13
- def simple_tracking(batch_landmarks, index=0, thres=0.5):
14
- track = []
15
-
16
- for i, faces in enumerate(batch_landmarks):
17
- if i == 0:
18
- if len(faces) <= index or faces[index][-1] < 0.8:
19
- return None
20
- if index != 0:
21
- for idx in range(index):
22
- if face_iou(faces[idx], faces[index]) > thres:
23
- return None
24
- track.append(faces[index])
25
- else:
26
- last = track[i - 1]
27
- if len(faces) == 0:
28
- return None
29
- sorted_faces = sorted(faces, key=lambda x: face_iou(x, last), reverse=True)
30
- if face_iou(sorted_faces[0], last) < thres:
31
- return None
32
- track.append(sorted_faces[0])
33
- return track
34
-
35
-
36
- def multiple_tracking(batch_landmarks):
37
- tracks = []
38
- for i in range(len(batch_landmarks[0])):
39
- track = simple_tracking(batch_landmarks, index=i)
40
- if track is None:
41
- continue
42
- tracks.append(track)
43
- return tracks
44
-
45
- def find_longest(detect_res):
46
- fc = len(detect_res)
47
- tuples = []
48
- start = 0
49
- end = 0
50
- previous_count = -1
51
- all_tracks = []
52
- # start 取得到,end 取不到
53
- while start < (fc - 1):
54
- for end in range(start + 2, fc + 1):
55
- tracks = multiple_tracking(detect_res[start:end])
56
- if (len(tracks) != previous_count and previous_count != -1) or len(
57
- tracks
58
- ) == 0:
59
- break
60
- previous_count = len(tracks)
61
- if end - start > 2:
62
- if end != fc:
63
- un_reach_end = end - 1
64
- else:
65
- un_reach_end = end
66
- sub_tracks = multiple_tracking(detect_res[start:un_reach_end])
67
- if end == fc and len(sub_tracks) == 0:
68
- un_reach_end = end - 1
69
- sub_tracks = multiple_tracking(detect_res[start:un_reach_end])
70
- if len(sub_tracks) > 0:
71
- tpl = (start, un_reach_end)
72
- tuples.append(tpl)
73
- all_tracks.append(sub_tracks[0])
74
- else:
75
- raise NotImplementedError
76
- previous_count = -1
77
- end = un_reach_end
78
- start = end
79
- return tuples, all_tracks
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
video/pwtf-dvd/model_code/preprocessing/test_tools/ct/tracking/__init__.py DELETED
File without changes
video/pwtf-dvd/model_code/preprocessing/test_tools/ct/tracking/sort.py DELETED
@@ -1,285 +0,0 @@
1
- """
2
- SORT: A Simple, Online and Realtime Tracker
3
- Copyright (C) 2016 Alex Bewley alex@dynamicdetection.com
4
-
5
- This program is free software: you can redistribute it and/or modify
6
- it under the terms of the GNU General Public License as published by
7
- the Free Software Foundation, either version 3 of the License, or
8
- (at your option) any later version.
9
-
10
- This program is distributed in the hope that it will be useful,
11
- but WITHOUT ANY WARRANTY; without even the implied warranty of
12
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
- GNU General Public License for more details.
14
-
15
- You should have received a copy of the GNU General Public License
16
- along with this program. If not, see <http://www.gnu.org/licenses/>.
17
- """
18
- from __future__ import print_function
19
- import os.path
20
- import numpy as np
21
- import matplotlib.pyplot as plt
22
- import matplotlib.patches as patches
23
- from scipy.optimize import linear_sum_assignment
24
- import glob
25
- import time
26
- import argparse
27
- from filterpy.kalman import KalmanFilter
28
-
29
-
30
- def iou(bb_test, bb_gt):
31
- """
32
- Computes IUO between two bboxes in the form [x1,y1,x2,y2]
33
- """
34
- xx1 = np.maximum(bb_test[0], bb_gt[0])
35
- yy1 = np.maximum(bb_test[1], bb_gt[1])
36
- xx2 = np.minimum(bb_test[2], bb_gt[2])
37
- yy2 = np.minimum(bb_test[3], bb_gt[3])
38
- w = np.maximum(0.0, xx2 - xx1)
39
- h = np.maximum(0.0, yy2 - yy1)
40
- wh = w * h
41
- o = wh / (
42
- (bb_test[2] - bb_test[0]) * (bb_test[3] - bb_test[1])
43
- + (bb_gt[2] - bb_gt[0]) * (bb_gt[3] - bb_gt[1])
44
- - wh
45
- )
46
- return o
47
-
48
-
49
- def convert_bbox_to_z(bbox):
50
- """
51
- Takes a bounding box in the form [x1,y1,x2,y2] and returns z in the form
52
- [x,y,s,r] where x,y is the centre of the box and s is the scale/area and r is
53
- the aspect ratio
54
- """
55
- w = bbox[2] - bbox[0]
56
- h = bbox[3] - bbox[1]
57
- x = bbox[0] + w / 2.0
58
- y = bbox[1] + h / 2.0
59
- s = w * h # scale is just area
60
- r = w / float(h)
61
- return np.array([x, y, s, r]).reshape((4, 1))
62
-
63
-
64
- def convert_x_to_bbox(x, score=None):
65
- """
66
- Takes a bounding box in the centre form [x,y,s,r] and returns it in the form
67
- [x1,y1,x2,y2] where x1,y1 is the top left and x2,y2 is the bottom right
68
- """
69
- w = np.sqrt(x[2] * x[3])
70
- h = x[2] / w
71
- if score == None:
72
- return np.array(
73
- [x[0] - w / 2.0, x[1] - h / 2.0, x[0] + w / 2.0, x[1] + h / 2.0]
74
- ).reshape((1, 4))
75
- else:
76
- return np.array(
77
- [x[0] - w / 2.0, x[1] - h / 2.0, x[0] + w / 2.0, x[1] + h / 2.0, score]
78
- ).reshape((1, 5))
79
-
80
-
81
- class KalmanBoxTracker(object):
82
- """
83
- This class represents the internel state of individual tracked objects observed as bbox.
84
- """
85
-
86
- count = 0
87
-
88
- def __init__(self, bbox):
89
- """
90
- Initialises a tracker using initial bounding box.
91
- """
92
- # define constant velocity model
93
- self.kf = KalmanFilter(dim_x=7, dim_z=4)
94
- self.kf.F = np.array(
95
- [
96
- [1, 0, 0, 0, 1, 0, 0],
97
- [0, 1, 0, 0, 0, 1, 0],
98
- [0, 0, 1, 0, 0, 0, 1],
99
- [0, 0, 0, 1, 0, 0, 0],
100
- [0, 0, 0, 0, 1, 0, 0],
101
- [0, 0, 0, 0, 0, 1, 0],
102
- [0, 0, 0, 0, 0, 0, 1],
103
- ]
104
- )
105
- self.kf.H = np.array(
106
- [
107
- [1, 0, 0, 0, 0, 0, 0],
108
- [0, 1, 0, 0, 0, 0, 0],
109
- [0, 0, 1, 0, 0, 0, 0],
110
- [0, 0, 0, 1, 0, 0, 0],
111
- ]
112
- )
113
-
114
- self.kf.R[2:, 2:] *= 10.0
115
- self.kf.P[
116
- 4:, 4:
117
- ] *= 1000.0 # give high uncertainty to the unobservable initial velocities
118
- self.kf.P *= 10.0
119
- self.kf.Q[-1, -1] *= 0.01
120
- self.kf.Q[4:, 4:] *= 0.01
121
-
122
- self.kf.x[:4] = convert_bbox_to_z(bbox)
123
- self.time_since_update = 0
124
- self.id = KalmanBoxTracker.count
125
- KalmanBoxTracker.count += 1
126
- self.history = []
127
- self.hits = 0
128
- self.hit_streak = 0
129
- self.age = 0
130
-
131
- def update(self, bbox):
132
- """
133
- Updates the state vector with observed bbox.
134
- """
135
- self.time_since_update = 0
136
- self.history = []
137
- self.hits += 1
138
- self.hit_streak += 1
139
- self.kf.update(convert_bbox_to_z(bbox))
140
-
141
- def predict(self):
142
- """
143
- Advances the state vector and returns the predicted bounding box estimate.
144
- """
145
- if (self.kf.x[6] + self.kf.x[2]) <= 0:
146
- self.kf.x[6] *= 0.0
147
- self.kf.predict()
148
- self.age += 1
149
- if self.time_since_update > 0:
150
- self.hit_streak = 0
151
- self.time_since_update += 1
152
- self.history.append(convert_x_to_bbox(self.kf.x))
153
- return self.history[-1]
154
-
155
- def get_state(self):
156
- """
157
- Returns the current bounding box estimate.
158
- """
159
- return convert_x_to_bbox(self.kf.x)
160
-
161
-
162
- def associate_detections_to_trackers(detections, trackers, iou_threshold=0.3):
163
- """
164
- Assigns detections to tracked object (both represented as bounding boxes)
165
-
166
- Returns 3 lists of matches, unmatched_detections and unmatched_trackers
167
- """
168
- if len(trackers) == 0:
169
- return (
170
- np.empty((0, 2), dtype=int),
171
- np.arange(len(detections)),
172
- np.empty((0, 5), dtype=int),
173
- )
174
- iou_matrix = np.zeros((len(detections), len(trackers)), dtype=np.float32)
175
-
176
- for d, det in enumerate(detections):
177
- for t, trk in enumerate(trackers):
178
- iou_matrix[d, t] = iou(det, trk)
179
-
180
- matched_indices = linear_sum_assignment(-iou_matrix)
181
- matched_indices = np.array(list(zip(*matched_indices)), dtype=np.int)
182
- matched_indices.shape = (-1, 2)
183
- # print(matched_indices)
184
- # print(type(matched_indices))
185
-
186
- unmatched_detections = []
187
- for d, det in enumerate(detections):
188
- if d not in matched_indices[:, 0]:
189
- unmatched_detections.append(d)
190
- unmatched_trackers = []
191
- for t, trk in enumerate(trackers):
192
- if t not in matched_indices[:, 1]:
193
- unmatched_trackers.append(t)
194
-
195
- # filter out matched with low IOU
196
- matches = []
197
- for m in matched_indices:
198
- if iou_matrix[m[0], m[1]] < iou_threshold:
199
- unmatched_detections.append(m[0])
200
- unmatched_trackers.append(m[1])
201
- else:
202
- matches.append(m.reshape(1, 2))
203
- if len(matches) == 0:
204
- matches = np.empty((0, 2), dtype=int)
205
- else:
206
- matches = np.concatenate(matches, axis=0)
207
-
208
- return matches, np.array(unmatched_detections), np.array(unmatched_trackers)
209
-
210
-
211
- class Sort(object):
212
- def __init__(self, max_age=1, min_hits=3):
213
- """
214
- Sets key parameters for SORT
215
- """
216
- self.max_age = max_age
217
- self.min_hits = min_hits
218
- self.trackers = []
219
- self.frame_count = 0
220
-
221
- def update(self, dets):
222
- """
223
- Params:
224
- dets - a numpy array of detections in the format [[x1,y1,x2,y2,score],[x1,y1,x2,y2,score],...]
225
- Requires: this method must be called once for each frame even with empty detections.
226
- Returns the a similar array, where the last column is the object ID.
227
-
228
- NOTE: The number of objects returned may differ from the number of detections provided.
229
- """
230
- self.frame_count += 1
231
- # get predicted locations from existing trackers.
232
- trks = np.zeros((len(self.trackers), 5))
233
- to_del = []
234
- ret = []
235
- for t, trk in enumerate(trks):
236
- pos = self.trackers[t].predict()[0]
237
- trk[:] = [pos[0], pos[1], pos[2], pos[3], 0]
238
- if np.any(np.isnan(pos)):
239
- to_del.append(t)
240
- trks = np.ma.compress_rows(np.ma.masked_invalid(trks))
241
- for t in reversed(to_del):
242
- self.trackers.pop(t)
243
- matched, unmatched_dets, unmatched_trks = associate_detections_to_trackers(
244
- dets, trks
245
- )
246
-
247
- # update matched trackers with assigned detections
248
- for t, trk in enumerate(self.trackers):
249
- if t not in unmatched_trks:
250
- d = matched[np.where(matched[:, 1] == t)[0], 0]
251
- trk.update(dets[d, :][0])
252
-
253
- # create and initialise new trackers for unmatched detections
254
- for i in unmatched_dets:
255
- trk = KalmanBoxTracker(dets[i, :])
256
- self.trackers.append(trk)
257
- i = len(self.trackers)
258
- for trk in reversed(self.trackers):
259
- d = trk.get_state()[0]
260
- if (trk.time_since_update < 1) and (
261
- trk.hit_streak >= self.min_hits or self.frame_count <= self.min_hits
262
- ):
263
- ret.append(
264
- np.concatenate((d, [trk.id + 1])).reshape(1, -1)
265
- ) # +1 as MOT benchmark requires positive
266
- i -= 1
267
- # remove dead tracklet
268
- if trk.time_since_update > self.max_age:
269
- self.trackers.pop(i)
270
- if len(ret) > 0:
271
- return np.concatenate(ret)
272
- return np.empty((0, 5))
273
-
274
-
275
- def parse_args():
276
- """Parse input arguments."""
277
- parser = argparse.ArgumentParser(description="SORT demo")
278
- parser.add_argument(
279
- "--display",
280
- dest="display",
281
- help="Display online tracker output (slow) [False]",
282
- action="store_true",
283
- )
284
- args = parser.parse_args()
285
- return args
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
video/pwtf-dvd/model_code/preprocessing/test_tools/ct/tracking/tracker.py DELETED
@@ -1,27 +0,0 @@
1
- from .sort import Sort
2
- import numpy as np
3
-
4
-
5
- def get_detections(faces):
6
- detections = []
7
- for face in faces:
8
- x1, y1, x2, y2 = face[0]
9
- detections.append((x1, y1, x2, y2, face[-1]))
10
- return np.array(detections)
11
-
12
-
13
- def get_tracks(detect_results):
14
- tracks = {}
15
- mot_tracker = Sort()
16
- for faces in detect_results:
17
- detections = get_detections(faces)
18
- track_bbs_ids = mot_tracker.update(detections)
19
- for track in track_bbs_ids: # 单独框出每一张人脸
20
- id = int(track[-1])
21
- box = track[:4]
22
- if id in tracks:
23
- tracks[id].append(box)
24
- else:
25
- tracks[id] = [box]
26
-
27
- return [track for id, track in tracks.items() if len(track) == len(detect_results)]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
video/pwtf-dvd/model_code/preprocessing/test_tools/ct/utils.py DELETED
@@ -1,5 +0,0 @@
1
- import cv2
2
-
3
-
4
- def write_img(file, img):
5
- cv2.imwrite(file, img, [cv2.IMWRITE_PNG_COMPRESSION, 0])
 
 
 
 
 
 
video/pwtf-dvd/model_code/preprocessing/test_tools/faster_crop_align_xray.py DELETED
@@ -1,73 +0,0 @@
1
- import numpy as np
2
- import cv2
3
- from .warp_for_xray import (
4
- estimiate_batch_transform,
5
- transform_landmarks,
6
- std_points_256,
7
- )
8
- import numpy as np
9
-
10
-
11
- class FasterCropAlignXRay:
12
- """
13
- 修正到统一坐标系,统一图像大小到标准尺寸
14
- """
15
-
16
- def __init__(self, size=256):
17
- self.image_size = size
18
- self.std_points = std_points_256 * size / 256.0
19
-
20
- def __call__(self, landmarks, images=None, jitter=False):
21
- landmarks = [landmark[:4] for landmark in landmarks]
22
- ori_boxes = np.array([ori_box for _, _, _, ori_box in landmarks])
23
- five_landmarks = np.array([ldm5 for _, ldm5, _, _ in landmarks])
24
- landmarks68 = np.array([ldm68 for _, _, ldm68, _ in landmarks])
25
- # assert landmarks68.min() > 0
26
-
27
- left_top = ori_boxes[:, :2].min(0)
28
-
29
- right_bottom = ori_boxes[:, 2:].max(0)
30
-
31
- size = right_bottom - left_top
32
-
33
- w, h = size
34
-
35
- diff = ori_boxes[:, :2] - left_top[None, ...]
36
-
37
- new_five_landmarks = five_landmarks + diff[:, None, :]
38
- new_landmarks68 = landmarks68 + diff[:, None, :]
39
-
40
- landmark_for_estimiate = new_five_landmarks.copy()
41
- if jitter:
42
- landmark_for_estimiate += np.random.uniform(
43
- -4, 4, landmark_for_estimiate.shape
44
- )
45
-
46
- tfm, trans = estimiate_batch_transform(
47
- landmark_for_estimiate, tgt_pts=self.std_points
48
- )
49
-
50
- transformed_landmarks68 = np.array(
51
- [transform_landmarks(ldm68, trans) for ldm68 in new_landmarks68]
52
- )
53
-
54
- if images is not None:
55
- transformed_images = [
56
- self.process_sinlge(tfm, image, d, h, w)
57
- for image, d in zip(images, diff)
58
- ] # 拼接 func 的参数
59
- transformed_images = np.stack(transformed_images)
60
- return transformed_landmarks68, transformed_images
61
- else:
62
- return transformed_landmarks68
63
-
64
- def process_sinlge(self, tfm, image, d, h, w):
65
- assert isinstance(image, np.ndarray)
66
- new_image = np.zeros((h, w, 3), dtype=np.uint8)
67
- x, y = d
68
- ih, iw, _ = image.shape
69
- new_image[y : y + ih, x : x + iw] = image
70
- transformed_image = cv2.warpAffine(
71
- new_image, tfm, (self.image_size, self.image_size)
72
- )
73
- return transformed_image