pipe_utils.py 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. # Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License");
  4. # you may not use this file except in compliance with the License.
  5. # You may obtain a copy of the License at
  6. #
  7. # http://www.apache.org/licenses/LICENSE-2.0
  8. #
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS,
  11. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. # See the License for the specific language governing permissions and
  13. # limitations under the License.
  14. import time
  15. import os
  16. import ast
  17. import glob
  18. import yaml
  19. import copy
  20. import numpy as np
  21. import subprocess as sp
  22. from python.keypoint_preprocess import EvalAffine, TopDownEvalAffine, expand_crop
  23. class Times(object):
  24. def __init__(self):
  25. self.time = 0.
  26. # start time
  27. self.st = 0.
  28. # end time
  29. self.et = 0.
  30. def start(self):
  31. self.st = time.time()
  32. def end(self, repeats=1, accumulative=True):
  33. self.et = time.time()
  34. if accumulative:
  35. self.time += (self.et - self.st) / repeats
  36. else:
  37. self.time = (self.et - self.st) / repeats
  38. def reset(self):
  39. self.time = 0.
  40. self.st = 0.
  41. self.et = 0.
  42. def value(self):
  43. return round(self.time, 4)
  44. class PipeTimer(Times):
  45. def __init__(self):
  46. super(PipeTimer, self).__init__()
  47. self.total_time = Times()
  48. self.module_time = {
  49. 'det': Times(),
  50. 'mot': Times(),
  51. 'attr': Times(),
  52. 'kpt': Times(),
  53. 'video_action': Times(),
  54. 'skeleton_action': Times(),
  55. 'reid': Times(),
  56. 'det_action': Times(),
  57. 'cls_action': Times(),
  58. 'vehicle_attr': Times(),
  59. 'vehicleplate': Times(),
  60. 'lanes': Times(),
  61. 'vehicle_press': Times(),
  62. 'vehicle_retrograde': Times()
  63. }
  64. self.img_num = 0
  65. self.track_num = 0
  66. def get_total_time(self):
  67. total_time = self.total_time.value()
  68. total_time = round(total_time, 4)
  69. average_latency = total_time / max(1, self.img_num)
  70. qps = 0
  71. if total_time > 0:
  72. qps = 1 / average_latency
  73. return total_time, average_latency, qps
  74. def info(self):
  75. total_time, average_latency, qps = self.get_total_time()
  76. print("------------------ Inference Time Info ----------------------")
  77. print("total_time(ms): {}, img_num: {}".format(total_time * 1000,
  78. self.img_num))
  79. for k, v in self.module_time.items():
  80. v_time = round(v.value(), 4)
  81. if v_time > 0 and k in ['det', 'mot', 'video_action']:
  82. print("{} time(ms): {}; per frame average time(ms): {}".format(
  83. k, v_time * 1000, v_time * 1000 / self.img_num))
  84. elif v_time > 0:
  85. print("{} time(ms): {}; per trackid average time(ms): {}".
  86. format(k, v_time * 1000, v_time * 1000 / self.track_num))
  87. print("average latency time(ms): {:.2f}, QPS: {:2f}".format(
  88. average_latency * 1000, qps))
  89. return qps
  90. def report(self, average=False):
  91. dic = {}
  92. dic['total'] = round(self.total_time.value() / max(1, self.img_num),
  93. 4) if average else self.total_time.value()
  94. dic['det'] = round(self.module_time['det'].value() /
  95. max(1, self.img_num),
  96. 4) if average else self.module_time['det'].value()
  97. dic['mot'] = round(self.module_time['mot'].value() /
  98. max(1, self.img_num),
  99. 4) if average else self.module_time['mot'].value()
  100. dic['attr'] = round(self.module_time['attr'].value() /
  101. max(1, self.img_num),
  102. 4) if average else self.module_time['attr'].value()
  103. dic['kpt'] = round(self.module_time['kpt'].value() /
  104. max(1, self.img_num),
  105. 4) if average else self.module_time['kpt'].value()
  106. dic['video_action'] = self.module_time['video_action'].value()
  107. dic['skeleton_action'] = round(
  108. self.module_time['skeleton_action'].value() / max(1, self.img_num),
  109. 4) if average else self.module_time['skeleton_action'].value()
  110. dic['img_num'] = self.img_num
  111. return dic
  112. class PushStream(object):
  113. def __init__(self, pushurl="rtsp://127.0.0.1:8554/"):
  114. self.command = ""
  115. # 自行设置
  116. self.pushurl = pushurl
  117. def initcmd(self, fps, width, height):
  118. self.command = [
  119. 'ffmpeg', '-y', '-f', 'rawvideo', '-vcodec', 'rawvideo', '-pix_fmt',
  120. 'bgr24', '-s', "{}x{}".format(width, height), '-r', str(fps), '-i',
  121. '-', '-pix_fmt', 'yuv420p', '-f', 'rtsp', self.pushurl
  122. ]
  123. self.pipe = sp.Popen(self.command, stdin=sp.PIPE)
  124. def get_test_images(infer_dir, infer_img):
  125. """
  126. Get image path list in TEST mode
  127. """
  128. assert infer_img is not None or infer_dir is not None, \
  129. "--infer_img or --infer_dir should be set"
  130. assert infer_img is None or os.path.isfile(infer_img), \
  131. "{} is not a file".format(infer_img)
  132. assert infer_dir is None or os.path.isdir(infer_dir), \
  133. "{} is not a directory".format(infer_dir)
  134. # infer_img has a higher priority
  135. if infer_img and os.path.isfile(infer_img):
  136. return [infer_img]
  137. images = set()
  138. infer_dir = os.path.abspath(infer_dir)
  139. assert os.path.isdir(infer_dir), \
  140. "infer_dir {} is not a directory".format(infer_dir)
  141. exts = ['jpg', 'jpeg', 'png', 'bmp']
  142. exts += [ext.upper() for ext in exts]
  143. for ext in exts:
  144. images.update(glob.glob('{}/*.{}'.format(infer_dir, ext)))
  145. images = list(images)
  146. assert len(images) > 0, "no image found in {}".format(infer_dir)
  147. print("Found {} inference images in total.".format(len(images)))
  148. return images
  149. def crop_image_with_det(batch_input, det_res, thresh=0.3):
  150. boxes = det_res['boxes']
  151. score = det_res['boxes'][:, 1]
  152. boxes_num = det_res['boxes_num']
  153. start_idx = 0
  154. crop_res = []
  155. for b_id, input in enumerate(batch_input):
  156. boxes_num_i = boxes_num[b_id]
  157. if boxes_num_i == 0:
  158. continue
  159. boxes_i = boxes[start_idx:start_idx + boxes_num_i, :]
  160. score_i = score[start_idx:start_idx + boxes_num_i]
  161. res = []
  162. for box, s in zip(boxes_i, score_i):
  163. if s > thresh:
  164. crop_image, new_box, ori_box = expand_crop(input, box)
  165. if crop_image is not None:
  166. res.append(crop_image)
  167. crop_res.append(res)
  168. return crop_res
  169. def normal_crop(image, rect):
  170. imgh, imgw, c = image.shape
  171. label, conf, xmin, ymin, xmax, ymax = [int(x) for x in rect.tolist()]
  172. org_rect = [xmin, ymin, xmax, ymax]
  173. if label != 0:
  174. return None, None, None
  175. xmin = max(0, xmin)
  176. ymin = max(0, ymin)
  177. xmax = min(imgw, xmax)
  178. ymax = min(imgh, ymax)
  179. return image[ymin:ymax, xmin:xmax, :], [xmin, ymin, xmax, ymax], org_rect
  180. def crop_image_with_mot(input, mot_res, expand=True):
  181. res = mot_res['boxes']
  182. crop_res = []
  183. new_bboxes = []
  184. ori_bboxes = []
  185. for box in res:
  186. if expand:
  187. crop_image, new_bbox, ori_bbox = expand_crop(input, box[1:])
  188. else:
  189. crop_image, new_bbox, ori_bbox = normal_crop(input, box[1:])
  190. if crop_image is not None:
  191. crop_res.append(crop_image)
  192. new_bboxes.append(new_bbox)
  193. ori_bboxes.append(ori_bbox)
  194. return crop_res, new_bboxes, ori_bboxes
  195. def parse_mot_res(input):
  196. mot_res = []
  197. boxes, scores, ids = input[0]
  198. for box, score, i in zip(boxes[0], scores[0], ids[0]):
  199. xmin, ymin, w, h = box
  200. res = [i, 0, score, xmin, ymin, xmin + w, ymin + h]
  201. mot_res.append(res)
  202. return {'boxes': np.array(mot_res)}
  203. def refine_keypoint_coordinary(kpts, bbox, coord_size):
  204. """
  205. This function is used to adjust coordinate values to a fixed scale.
  206. """
  207. tl = bbox[:, 0:2]
  208. wh = bbox[:, 2:] - tl
  209. tl = np.expand_dims(np.transpose(tl, (1, 0)), (2, 3))
  210. wh = np.expand_dims(np.transpose(wh, (1, 0)), (2, 3))
  211. target_w, target_h = coord_size
  212. res = (kpts - tl) / wh * np.expand_dims(
  213. np.array([[target_w], [target_h]]), (2, 3))
  214. return res
  215. def parse_mot_keypoint(input, coord_size):
  216. parsed_skeleton_with_mot = {}
  217. ids = []
  218. skeleton = []
  219. for tracker_id, kpt_seq in input:
  220. ids.append(tracker_id)
  221. kpts = np.array(kpt_seq.kpts, dtype=np.float32)[:, :, :2]
  222. kpts = np.expand_dims(np.transpose(kpts, [2, 0, 1]),
  223. -1) #T, K, C -> C, T, K, 1
  224. bbox = np.array(kpt_seq.bboxes, dtype=np.float32)
  225. skeleton.append(refine_keypoint_coordinary(kpts, bbox, coord_size))
  226. parsed_skeleton_with_mot["mot_id"] = ids
  227. parsed_skeleton_with_mot["skeleton"] = skeleton
  228. return parsed_skeleton_with_mot