engine.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. # note: https://github.com/SthPhoenix/InsightFace-REST
  2. """
  3. 测试结果:
  4. 使用python版本的onnxruntime,推理onnx模型,推理一次时间为4751.71ms
  5. 本测试用例适用于onnxruntime-gpu 1.10.0版本
  6. 100帧fp16处理时间
  7. TensorrtExecutionProvider: 1464ms
  8. 24帧fp16处理时间
  9. TensorrtExecutionProvider: 358.92ms
  10. 1帧fp16处理时间
  11. TensorrtExecutionProvider: 49ms
  12. 100帧处理时间
  13. TensorrtExecutionProvider: 3727ms
  14. CUDAExecutionProvider: 5169ms
  15. CPUExecutionProvider: 68953ms
  16. 24帧处理时间
  17. TensorrtExecutionProvider: 796ms
  18. CUDAExecutionProvider: 1206ms
  19. CPUExecutionProvider: 16591ms
  20. 1帧测试
  21. TensorrtExecutionProvider: 85ms
  22. CUDAExecutionProvider: 88ms
  23. CPUExecutionProvider: 738ms
  24. """
  25. from numpy.linalg import norm
  26. import onnxruntime
  27. import numpy as np
  28. import cv2
  29. import logging
  30. import binascii
  31. import sys
  32. import importlib
  33. sys.path.append('/home/server/projects/taiwuict/cscec-8bur-vms/supplement-python')
  34. methods = importlib.import_module(f"libraries.base_original")
  35. numpy_method = importlib.import_module(f"libraries.base_external.data_by_numpy")
  36. class FaceRecognitionEngine:
  37. def __init__(self):
  38. model_path = '/home/server/resources/DockerDependencies/2022/target/AlgorithmModels/FaceRecognition-arcface/'
  39. model_path += 'arcface_r100_v1.onnx'
  40. # model_path += 'MFR_glintr100.onnx'
  41. # --- debug mode ---
  42. # self.onnx_session = onnxruntime.InferenceSession(model_path, providers=['TensorrtExecutionProvider'])
  43. self.onnx_session = onnxruntime.InferenceSession(model_path, providers=['CUDAExecutionProvider']) # for test
  44. # self.onnx_session = onnxruntime.InferenceSession(model_path, providers=['CPUExecutionProvider'])
  45. # self.onnx_session.set_providers(['CUDAExecutionProvider'], [{'device_id': 1}]) # 指定GPU
  46. # --- release mode ---
  47. # providers = [
  48. # ('TensorrtExecutionProvider', {
  49. # # 'device_id': 1,
  50. # # 'trt_max_workspace_size': 2147483648,
  51. # 'trt_fp16_enable': True,
  52. # # 'trt_int8_enable': True,
  53. # # 'trt_engine_cache_enable': True,
  54. # # 'trt_engine_cache_path': '',
  55. # }),
  56. # ]
  57. # self.onnx_session = onnxruntime.InferenceSession(model_path, providers=providers)
  58. self.outputs = [e.name for e in self.onnx_session.get_outputs()]
  59. def prepare(self, **kwargs):
  60. """模型初始化"""
  61. logging.info("Warming up ArcFace ONNX Runtime engine...")
  62. self.onnx_session.run(output_names=self.outputs,
  63. input_feed={
  64. self.onnx_session.get_inputs()[0].name: [np.zeros((3, 112, 112), np.float32)]})
  65. @staticmethod
  66. def normalize(embedding):
  67. """特征数据格式化"""
  68. embedding_norm = norm(embedding)
  69. normed_embedding = embedding / embedding_norm
  70. return normed_embedding
  71. def get_face_features_normalization_by_image_array(self, image_array):
  72. """获取特征"""
  73. # --- debug ---
  74. # methods.debug_log('FaceRecognitionEngine', f"m-92: size: {image_array.shape}")
  75. # --- check todo 连乘得到像素值,旨在过滤低于112的尺寸图片 ---
  76. # if np.prod(image_array.shape) < np.prod((112, 112, 3)):
  77. # return None
  78. # --- check ---
  79. if image_array is None:
  80. return None
  81. # --- check ---
  82. if image_array.shape != (112, 112, 3):
  83. # methods.debug_log('FaceRecognitionEngine', f"m-96: image resize before is {image_array.shape}")
  84. image_array = cv2.resize(image_array, (112, 112))
  85. if not isinstance(image_array, list):
  86. image_array = [image_array]
  87. for i, img in enumerate(image_array):
  88. img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
  89. img = np.transpose(img, (2, 0, 1))
  90. image_array[i] = img.astype(np.float32)
  91. image_array = np.stack(image_array)
  92. net_out = self.onnx_session.run(self.outputs, {self.onnx_session.get_inputs()[0].name: image_array})
  93. return self.normalize(net_out[0][0])
  94. @staticmethod
  95. def image_bytes_to_image_array(image_bytes, mode='RGB'):
  96. """
  97. 数据格式转换
  98. """
  99. _image = numpy_method.bytes_to_array_v2(image_bytes)
  100. _image = cv2.imdecode(_image, cv2.IMREAD_COLOR)
  101. return _image
  102. def get_face_features_normalization_by_image_bytes(self, image_bytes):
  103. """获取特征"""
  104. # --- bytes to array ---
  105. image_array = self.image_bytes_to_image_array(image_bytes)
  106. # --- check todo 低于112的尺寸,则过滤掉 ---
  107. # if np.prod(image_array.shape) < np.prod((112, 112, 3)):
  108. # return None
  109. # --- check size --- todo 如果是4通道,考虑通过cvtColor转3通道
  110. if image_array.shape != (112, 112, 3):
  111. image_array = cv2.resize(image_array, (112, 112))
  112. if not isinstance(image_array, list):
  113. image_array = [image_array]
  114. for i, img in enumerate(image_array):
  115. img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
  116. img = np.transpose(img, (2, 0, 1))
  117. image_array[i] = img.astype(np.float32)
  118. image_array = np.stack(image_array)
  119. net_out = self.onnx_session.run(self.outputs, {self.onnx_session.get_inputs()[0].name: image_array})
  120. return self.normalize(net_out[0][0])
  121. @staticmethod
  122. def compare_faces_by_normalization(input_normalization, specimen_normalization):
  123. """
  124. 计算相似度(使用格式化数据)
  125. """
  126. _sim = (1.0 + np.dot(input_normalization, specimen_normalization)) / 2.0
  127. return _sim
  128. def search_face(self, face_features_normalization, face_dict):
  129. """
  130. 寻找近似人脸(face_dict为一对一)
  131. """
  132. # --- get face ---
  133. best_face_uuid, best_face_dist = None, None
  134. for face_uuid, face_features in face_dict.items():
  135. dist = self.compare_faces_by_normalization(face_features_normalization, face_features)
  136. # --- check --- 高相似度,直接返回 (85%以上基本就判定为同一个人了)
  137. # if dist > 0.85:
  138. # methods.debug_log('FaceRecognitionEngine', f"m-162: best dist {dist} | {type(dist)}")
  139. # return face_uuid, dist
  140. # --- check --- 低相似度,直接过滤 (一般低于71%就不是一个人了)
  141. if dist > 0.71 and not best_face_dist:
  142. best_face_dist = dist
  143. best_face_uuid = face_uuid
  144. if best_face_dist and dist > best_face_dist:
  145. best_face_dist = dist
  146. best_face_uuid = face_uuid
  147. # methods.debug_log('FaceRecognitionEngine', f"m-178: best dist {best_face_dist}, face uuid is{best_face_uuid}")
  148. return best_face_uuid, best_face_dist
  149. # def search_face_v2(self, face_features_normalization, face_dict, filter_dist=0.745):
  150. # def search_face_v2(self, face_features_normalization, face_dict, filter_dist=0.7):
  151. def search_face_v2(self, face_features_normalization, face_dict, filter_dist=0.72):
  152. """
  153. 寻找近似人脸(face_dict为一对多)
  154. filter_dist: 相似度判定值
  155. """
  156. # --- get face ---
  157. best_face_uuid, best_face_dist, best_face_image_path = None, 0.0, None
  158. for face_uuid, info_list in face_dict.items():
  159. for info in info_list:
  160. face_features, image_path = info
  161. dist = self.compare_faces_by_normalization(face_features_normalization, face_features)
  162. # --- check --- 高相似度,直接返回 (85%以上基本就判定为同一个人了)
  163. # if dist > 0.85:
  164. # methods.debug_log('FaceRecognitionEngine', f"m-162: best dist {dist} | {type(dist)}")
  165. # return face_uuid, dist
  166. # --- check --- 低相似度,直接过滤 (一般低于72%就不是一个人了)
  167. if dist > filter_dist and not best_face_dist:
  168. best_face_dist = dist
  169. best_face_uuid = face_uuid
  170. best_face_image_path = image_path
  171. # --- update ---
  172. if best_face_dist and dist > best_face_dist:
  173. best_face_dist = dist
  174. best_face_uuid = face_uuid
  175. best_face_image_path = image_path
  176. # methods.debug_log('FaceRecognitionEngine', f"m-206: best dist {best_face_dist}, face uuid is{best_face_uuid}")
  177. return best_face_uuid, best_face_dist, best_face_image_path
  178. def search_face_top3(self, face_features_normalization, face_dict):
  179. """
  180. 寻找近似人脸TOP3
  181. """
  182. # --- define ---
  183. d1 = list() # [{rate: <rate>, uuid: <uuid>}]
  184. # --- get face ---
  185. for face_uuid, face_features in face_dict.items():
  186. rate = self.compare_faces_by_normalization(face_features_normalization, face_features)
  187. d1.append({'rate': rate, 'uuid': face_uuid})
  188. d1[rate] = face_uuid
  189. # --- check ---
  190. d2 = sorted(d1, key=lambda d: d['rate'], reverse=True)[:3]
  191. for _ in range(3 - len(d2)):
  192. d2.append({'rate': None, 'uuid': None})
  193. return d2[0], d2[1], d2[2]
  194. @staticmethod
  195. def clip_image(image_array, left, top, width, height):
  196. """剪裁图像"""
  197. # --- debug ---
  198. # methods.debug_log('FaceRecognitionEngine', f"m-185: size: {image_array.shape}")
  199. # methods.debug_log('FaceRecognitionEngine',
  200. # f"m-185: left: {left}, top: {top}, width: {width}, height: {height}")
  201. # --- 根据deepstream的左上点坐标,进行剪裁图像 ---
  202. return image_array[int(top):int(top + height), int(left):int(left + width)]
  203. # --- 根据deepstream的左上点坐标,计算出中心点,然后剪裁112尺寸的图像 --- todo 存在误识别问题
  204. # half = 112/2
  205. # return image_array[int(top + height/2 - half): int(top + height/2 + half),
  206. # int(left + width/2 - half): int(left + width/2 + half)]
  207. @staticmethod
  208. def image_hex_to_image_array(hex_str_image, mode='RGB'):
  209. """
  210. 数据格式转换
  211. """
  212. try:
  213. bytes_image = binascii.unhexlify(hex_str_image)
  214. _image = numpy_method.bytes_to_array_v2(bytes_image)
  215. _image = cv2.imdecode(_image, cv2.IMREAD_COLOR)
  216. return _image
  217. except Exception as exception:
  218. methods.debug_log('FaceDetectionEngine', f"m-138: exception | {exception}")
  219. methods.debug_log('FaceDetectionEngine', f"m-138: traceback | {methods.trace_log()}")
  220. return None
  221. if __name__ == '__main__':
  222. # --- init ---
  223. agent = FaceRecognitionEngine()
  224. agent.prepare()
  225. # --- test ---
  226. # p0 = cv2.imread('./face.jpg')
  227. # f0 = agent.get_face_features_by_image_array(p0)
  228. # p3 = cv2.imread('./worker.jpg')
  229. # p3 = cv2.resize(p3, (112, 112))
  230. # f3 = agent.get_face_features_by_image_array(p3)
  231. # sim = agent.compare_faces(f0, f3)
  232. # print(f"Similarity: {sim}")
  233. # --- test ---
  234. import requests
  235. url = 'https://lwres.yzw.cn/worker-avatar/Original/2020/1013/96c419ca-dbf2-4bf7-a072-92fde861a2bc.jpg'
  236. response = requests.get(url, headers={'content-type': 'application/json'})
  237. _image_bytes = response.content
  238. f0 = agent.get_face_features_normalization_by_image_bytes(_image_bytes)
  239. print(f"f0: {type(f0)}")
  240. # p1 = cv2.imread('./face.jpg')
  241. # f1 = agent.get_face_features_normalization_by_image_array(p1)
  242. # sim = agent.compare_faces_by_normalization(f0, f1)
  243. # print(f"Similarity: {sim}")