1
+ import cv2
2
+ import numpy as np
3
+ import os
4
+ import sys
5
+ from vis_utils import *
6
+ import time
7
+
8
+ __version__ = "1.1.3"
9
+
10
+ joints_pair = [[0 , 1 ], [1 , 2 ], [2 , 0 ], [1 , 3 ], [2 , 4 ], [3 , 5 ], [4 , 6 ], [5 , 6 ], [5 , 11 ],
11
+ [6 , 12 ], [11 , 12 ], [5 , 7 ], [7 , 9 ], [6 , 8 ], [8 , 10 ], [11 , 13 ], [13 , 15 ], [12 , 14 ], [14 , 16 ]]
12
+ colors_tableau = [(255 , 255 , 255 ), (31 , 119 , 180 ), (174 , 199 , 232 ), (255 , 127 , 14 ), (255 , 187 , 120 ),
13
+ (44 , 160 , 44 ), (152 , 223 , 138 ), (214 , 39 , 40 ), (255 , 152 , 150 ),
14
+ (148 , 103 , 189 ), (197 , 176 , 213 ), (140 , 86 , 75 ), (196 , 156 , 148 ),
15
+ (227 , 119 , 194 ), (247 , 182 , 210 ), (127 , 127 , 127 ), (199 , 199 , 199 ),
16
+ (188 , 189 , 34 ), (219 , 219 , 141 ), (23 , 190 , 207 ), (158 , 218 , 229 )]
17
+
18
+ def add_jointsv2 (image , joints , color , r = 3 ,threshold = 0.1 ):
19
+
20
+ def link (a , b , color ):
21
+ jointa = joints [a ]
22
+ jointb = joints [b ]
23
+ if jointa [2 ] > threshold and jointb [2 ] > threshold :
24
+ cv2 .line (
25
+ image ,
26
+ (int (jointa [0 ]), int (jointa [1 ])),
27
+ (int (jointb [0 ]), int (jointb [1 ])),
28
+ color , 2 )
29
+
30
+ # add link
31
+ for pair in joints_pair :
32
+ link (pair [0 ], pair [1 ], color )
33
+
34
+ # add joints
35
+ for i , joint in enumerate (joints ):
36
+ if joint [2 ] > threshold and joint [0 ] > 1 and joint [1 ] > 1 :
37
+ cv2 .circle (image , (int (joint [0 ]), int (joint [1 ])), r , colors_tableau [i ], - 1 )
38
+
39
+ return image
40
+
41
+ def show_keypoints (image , joints , color = [0 ,255 ,0 ],threshold = 0.1 ):
42
+ image = np .ascontiguousarray (image )
43
+ if color is None :
44
+ use_random_color = True
45
+ else :
46
+ use_random_color = False
47
+ for person in joints :
48
+ if use_random_color :
49
+ color = np .random .randint (0 , 255 , size = 3 )
50
+ color = [int (i ) for i in color ]
51
+ add_jointsv2 (image , person , color = color ,threshold = threshold )
52
+
53
+ return image
54
+
55
+ class BufferTextPainter :
56
+ def __init__ (self ,buffer_len = 30 ):
57
+ self .buffer_nr = buffer_len
58
+ self .cur_text = ""
59
+ self .cur_idx = 0
60
+ self .font = os .path .join (os .path .dirname (__file__ ),"simhei.ttf" )
61
+
62
+ def putText (self ,img ,text ,font_scale = 20 ,text_color = (255 ,255 ,255 )):
63
+ img = np .ascontiguousarray (img )
64
+ if text == "" :
65
+ if self .cur_idx == 0 :
66
+ return img
67
+ else :
68
+ self .cur_idx = self .buffer_nr
69
+ self .cur_text = text
70
+
71
+ self .cur_idx = self .cur_idx - 1
72
+ img = draw_text (img ,(12 ,12 ),self .cur_text ,
73
+ text_color = text_color ,
74
+ font_size = font_scale ,
75
+ font = self .font )
76
+ return img
77
+
78
+ def resize_height (img ,h ,interpolation = cv2 .INTER_LINEAR ):
79
+ shape = img .shape
80
+ new_h = h
81
+ new_w = int (shape [1 ]* new_h / shape [0 ])
82
+ return cv2 .resize (img ,dsize = (new_w ,new_h ),interpolation = interpolation )
83
+
84
+ def resize_width (img ,w ,interpolation = cv2 .INTER_LINEAR ):
85
+ shape = img .shape
86
+ new_w = w
87
+ new_h = int (shape [0 ]* new_w / shape [1 ])
88
+ return cv2 .resize (img ,dsize = (new_w ,new_h ),interpolation = interpolation )
89
+
90
+ def resize_short_size (img ,size ,interpolation = cv2 .INTER_LINEAR ):
91
+ shape = img .shape
92
+ if shape [0 ]< shape [1 ]:
93
+ return resize_height (img ,size ,interpolation )
94
+ else :
95
+ return resize_width (img ,size ,interpolation )
96
+
97
+ class VideoDemo :
98
+ def __init__ (self ,model ,fps = 30 ,save_path = None ,buffer_size = 0 ,show_video = True ,max_frame_cn = None ,interval = None ) -> None :
99
+ self .model = model
100
+ self .fps = fps
101
+ self .save_path = save_path
102
+ self .buffer_size = buffer_size
103
+ self .buffer = []
104
+ self .write_size = None
105
+ self .video_reader = None
106
+ self .video_writer = None
107
+ self .show_video = show_video
108
+ self .preprocess = None
109
+ self .max_frame_cn = max_frame_cn
110
+ self .interval = interval
111
+ self .model .runner = self
112
+ self .window_name = "video"
113
+ print (f"Demo toolkit version { __version__ } ." )
114
+
115
+ def __del__ (self ):
116
+ self .close ()
117
+
118
+ def close (self ):
119
+ if self .video_writer is not None :
120
+ self .video_writer .release ()
121
+
122
+
123
+ def init_writer (self ):
124
+ save_path = self .save_path
125
+ if save_path is not None :
126
+ fourcc = cv2 .VideoWriter_fourcc (* 'XVID' )
127
+ self .video_writer = cv2 .VideoWriter (save_path ,fourcc ,self .fps ,self .write_size )
128
+
129
+ def init_reader (self ):
130
+ if self .video_path is not None and os .path .exists (self .video_path ):
131
+ print (f"Use video file { self .video_path } " )
132
+ self .video_reader = cv2 .VideoCapture (self .video_path )
133
+ self .frame_cnt = int (self .video_reader .get (cv2 .CAP_PROP_FRAME_COUNT ))
134
+ if self .max_frame_cn is not None and self .max_frame_cn > 1 :
135
+ self .frame_cnt = min (self .frame_cnt ,self .max_frame_cn )
136
+ else :
137
+ if self .video_path is not None :
138
+ vc = int (self .video_path )
139
+ else :
140
+ vc = - 1
141
+ print (f"Use camera { vc } " )
142
+ self .video_reader = cv2 .VideoCapture (vc )
143
+ self .frame_cnt = - 1
144
+
145
+ self .video_reader .set (cv2 .CAP_PROP_BUFFERSIZE ,1 )
146
+ self .video_reader .set (cv2 .CAP_PROP_POS_FRAMES ,1 )
147
+
148
+ if self .show_video :
149
+ cv2 .namedWindow (self .window_name , cv2 .WND_PROP_FULLSCREEN )
150
+ cv2 .setWindowProperty (self .window_name ,cv2 .WND_PROP_FULLSCREEN ,cv2 .WINDOW_FULLSCREEN )
151
+
152
+ width = int (self .video_reader .get (cv2 .CAP_PROP_FRAME_WIDTH ))
153
+ height = int (self .video_reader .get (cv2 .CAP_PROP_FRAME_HEIGHT ))
154
+ if self .preprocess is None :
155
+ self .write_size = (width ,height )
156
+ else :
157
+ tmp_img = np .zeros ([height ,width ,3 ],dtype = np .uint8 )
158
+ tmp_img = self .preprocess (tmp_img )
159
+ if isinstance (tmp_img ,dict ):
160
+ tmp_img = self .get_last_img ([tmp_img ])
161
+ self .write_size = (tmp_img .shape [1 ],tmp_img .shape [0 ])
162
+ self .fps = self .video_reader .get (cv2 .CAP_PROP_FPS )
163
+
164
+ def inference_loop (self ,video_path = None ):
165
+ self .video_path = video_path
166
+ self .init_reader ()
167
+ self .init_writer ()
168
+ idx = 0
169
+
170
+ print (f"Press Esc to escape." )
171
+
172
+ while True :
173
+ idx += 1
174
+ if self .interval is not None and self .interval > 1 :
175
+ if idx % self .interval != 0 :
176
+ continue
177
+ ret ,frame = self .video_reader .read ()
178
+ if not ret :
179
+ break
180
+ frame = frame [...,::- 1 ] #torgb
181
+ if self .preprocess is not None :
182
+ frame = self .preprocess (frame )
183
+ img = self .inference (frame )
184
+ if img is None :
185
+ continue
186
+ if self .show_video :
187
+ cv2 .imshow (self .window_name ,img [...,::- 1 ])
188
+ if cv2 .waitKey (30 )& 0xFF == 27 :
189
+ break
190
+ if self .frame_cnt > 1 :
191
+ sys .stdout .write (f"{ idx } /{ self .frame_cnt } { idx * 100 / self .frame_cnt :.3f} %.\r " )
192
+ if idx > self .frame_cnt :
193
+ break
194
+
195
+ def inference (self ,img ):
196
+ if self .buffer_size <= 1 :
197
+ r_img = self .inference_single_img (img )
198
+ else :
199
+ r_img = self .inference_buffer_img (img )
200
+ if self .video_writer is not None :
201
+ self .video_writer .write (r_img [...,::- 1 ])
202
+ return r_img
203
+
204
+ def inference_single_img (self ,img ):
205
+ return self .model (img )
206
+
207
+ def inference_buffer_img (self ,img ):
208
+ self .buffer .append (img )
209
+ if len (self .buffer )> self .buffer_size :
210
+ self .buffer = self .buffer [- self .buffer_size :]
211
+ return self .model (self .buffer )
212
+
213
+ @staticmethod
214
+ def get_last_img (imgs ):
215
+ img = imgs [- 1 ]
216
+ if isinstance (img ,dict ):
217
+ if 'raw_image' in img :
218
+ return img ['raw_image' ]
219
+ return img ['image' ]
220
+ else :
221
+ return img
222
+
223
+ @staticmethod
224
+ def resize_h_and_save_raw_image_preprocess (img ,h = 224 ):
225
+ r_img = resize_height (img ,h ).astype (np .uint8 )
226
+ return {'image' :r_img ,"raw_image" :img }
227
+
228
+ class IntervalMode :
229
+ def __init__ (self ,interval = 30 ):
230
+ self .interval = interval
231
+ self .idx = 0
232
+
233
+ def add (self ):
234
+ self .idx += 1
235
+
236
+ def need_pred (self ):
237
+ self .add ()
238
+ return (self .idx % self .interval )== 0
239
+
240
+
241
+ def get_video_indexs (size ,nr ):
242
+ delta = (size - 1 )/ nr
243
+ idxs = (np .arange (nr ).astype (np .float32 )* delta + delta / 2 ).astype (np .int32 )
244
+ return idxs
245
+
246
+ def crop_imgs (imgs , crop_bbox ):
247
+ x1 , y1 , x2 , y2 = crop_bbox
248
+ return [img [y1 :y2 , x1 :x2 ] for img in imgs ]
249
+
250
+ def center_crop (imgs ,crop_size ):
251
+ img_h , img_w = imgs [0 ].shape [:2 ]
252
+ crop_w , crop_h = crop_size
253
+
254
+ left = (img_w - crop_w ) // 2
255
+ top = (img_h - crop_h ) // 2
256
+ right = left + crop_w
257
+ bottom = top + crop_h
258
+
259
+ crop_bbox = np .array ([left , top , right , bottom ])
260
+
261
+ return crop_imgs (imgs , crop_bbox )
262
+
263
+ class TimeThis ():
264
+ def __init__ (self ,name = "TimeThis" ,auto_show = True ):
265
+ self .begin_time = 0.
266
+ self .end_time = 0
267
+ self .name = name
268
+ self .auto_show = auto_show
269
+
270
+ def __enter__ (self ):
271
+ self .begin_time = time .time ()
272
+
273
+ def __exit__ (self , exc_type , exc_val , exc_tb ):
274
+ self .end_time = time .time ()
275
+ if self .auto_show :
276
+ te = (self .end_time - self .begin_time )* 1000
277
+ fps = 1000 / (te + 1e-8 )
278
+ print (f"{ self .name } : total time { te :.3f} , FPS={ fps :.3f} ." )
279
+
280
+ def time (self ):
281
+ return self .end_time - self .begin_time
0 commit comments