module.py 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. # Copyright (c) 2020 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 os
  15. import time
  16. from functools import reduce
  17. import cv2
  18. import numpy as np
  19. from paddlehub.module.module import moduleinfo
  20. import blazeface.data_feed as D
  21. @moduleinfo(
  22. name="blazeface",
  23. type="CV/image_editing",
  24. author="paddlepaddle",
  25. author_email="",
  26. summary="blazeface is a face key point detection model.",
  27. version="1.0.0")
  28. class Detector(object):
  29. """
  30. Args:
  31. config (object): config of model, defined by `Config(model_dir)`
  32. model_dir (str): root path of __model__, __params__ and infer_cfg.yml
  33. use_gpu (bool): whether use gpu
  34. run_mode (str): mode of running(fluid/trt_fp32/trt_fp16)
  35. threshold (float): threshold to reserve the result for output.
  36. """
  37. def __init__(self,
  38. min_subgraph_size=60,
  39. use_gpu=False,
  40. run_mode='fluid',
  41. threshold=0.5):
  42. model_dir = os.path.join(self.directory, 'blazeface_keypoint')
  43. self.predictor = D.load_predictor(
  44. model_dir,
  45. run_mode=run_mode,
  46. min_subgraph_size=min_subgraph_size,
  47. use_gpu=use_gpu)
  48. def face_img_process(self,
  49. image,
  50. mean=[104., 117., 123.],
  51. std=[127.502231, 127.502231, 127.502231]):
  52. image = np.array(image)
  53. # HWC to CHW
  54. if len(image.shape) == 3:
  55. image = np.swapaxes(image, 1, 2)
  56. image = np.swapaxes(image, 1, 0)
  57. # RBG to BGR
  58. image = image[[2, 1, 0], :, :]
  59. image = image.astype('float32')
  60. image -= np.array(mean)[:, np.newaxis, np.newaxis].astype('float32')
  61. image /= np.array(std)[:, np.newaxis, np.newaxis].astype('float32')
  62. image = [image]
  63. image = np.array(image)
  64. return image
  65. def transform(self, image, shrink):
  66. im_info = {
  67. 'scale': [1., 1.],
  68. 'origin_shape': None,
  69. 'resize_shape': None,
  70. 'pad_shape': None,
  71. }
  72. if isinstance(image, str):
  73. with open(image, 'rb') as f:
  74. im_read = f.read()
  75. image = np.frombuffer(im_read, dtype='uint8')
  76. image = cv2.imdecode(image, 1) # BGR mode, but need RGB mode
  77. image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
  78. im_info['origin_shape'] = image.shape[:2]
  79. else:
  80. im_info['origin_shape'] = image.shape[:2]
  81. image_shape = [3, image.shape[0], image.shape[1]]
  82. h, w = shrink, shrink
  83. image = cv2.resize(image, (w, h))
  84. im_info['resize_shape'] = image.shape[:2]
  85. image = self.face_img_process(image)
  86. inputs = D.create_inputs(image, im_info)
  87. return inputs, im_info
  88. def postprocess(self, boxes_list, lmks_list, im_info, threshold=0.5):
  89. assert len(boxes_list) == len(lmks_list)
  90. best_np_boxes, best_np_lmk = boxes_list[0], lmks_list[0]
  91. for i in range(1, len(boxes_list)):
  92. #judgment detection score
  93. if boxes_list[i][0][1] > 0.9:
  94. break
  95. face_width = boxes_list[i][0][4] - boxes_list[i][0][2]
  96. if boxes_list[i][0][1] - best_np_boxes[0][
  97. 1] > 0.01 and face_width > 0.2:
  98. best_np_boxes, best_np_lmk = boxes_list[i], lmks_list[i]
  99. # postprocess output of predictor
  100. results = {}
  101. results['landmark'] = D.lmk2out(best_np_boxes, best_np_lmk, im_info,
  102. threshold)
  103. w, h = im_info['origin_shape']
  104. best_np_boxes[:, 2] *= h
  105. best_np_boxes[:, 3] *= w
  106. best_np_boxes[:, 4] *= h
  107. best_np_boxes[:, 5] *= w
  108. expect_boxes = (best_np_boxes[:, 1] > threshold) & (
  109. best_np_boxes[:, 0] > -1)
  110. best_np_boxes = best_np_boxes[expect_boxes, :]
  111. for box in best_np_boxes:
  112. print('class_id:{:d}, confidence:{:.4f},'
  113. 'left_top:[{:.2f},{:.2f}],'
  114. ' right_bottom:[{:.2f},{:.2f}]'.format(
  115. int(box[0]), box[1], box[2], box[3], box[4], box[5]))
  116. results['boxes'] = best_np_boxes
  117. return results
  118. def predict(self,
  119. image,
  120. threshold=0.5,
  121. repeats=1,
  122. visualization=False,
  123. with_lmk=True,
  124. save_dir='blaze_result'):
  125. '''
  126. Args:
  127. image (str/np.ndarray): path of image/ np.ndarray read by cv2
  128. threshold (float): threshold of predicted box' score
  129. Returns:
  130. results (dict): include 'boxes': np.ndarray: shape:[N,6], N: number of box,
  131. matix element:[class, score, x_min, y_min, x_max, y_max]
  132. '''
  133. shrink = [960, 640, 480, 320, 180]
  134. boxes_list = []
  135. lmks_list = []
  136. for sh in shrink:
  137. inputs, im_info = self.transform(image, shrink=sh)
  138. np_boxes, np_lmk = None, None
  139. input_names = self.predictor.get_input_names()
  140. for i in range(len(input_names)):
  141. input_tensor = self.predictor.get_input_tensor(input_names[i])
  142. input_tensor.copy_from_cpu(inputs[input_names[i]])
  143. t1 = time.time()
  144. for i in range(repeats):
  145. self.predictor.zero_copy_run()
  146. output_names = self.predictor.get_output_names()
  147. boxes_tensor = self.predictor.get_output_tensor(output_names[0])
  148. np_boxes = boxes_tensor.copy_to_cpu()
  149. if with_lmk == True:
  150. face_index = self.predictor.get_output_tensor(output_names[
  151. 1])
  152. landmark = self.predictor.get_output_tensor(output_names[2])
  153. prior_boxes = self.predictor.get_output_tensor(output_names[
  154. 3])
  155. np_face_index = face_index.copy_to_cpu()
  156. np_prior_boxes = prior_boxes.copy_to_cpu()
  157. np_landmark = landmark.copy_to_cpu()
  158. np_lmk = [np_face_index, np_landmark, np_prior_boxes]
  159. t2 = time.time()
  160. ms = (t2 - t1) * 1000.0 / repeats
  161. print("Inference: {} ms per batch image".format(ms))
  162. # do not perform postprocess in benchmark mode
  163. results = []
  164. if reduce(lambda x, y: x * y, np_boxes.shape) < 6:
  165. print('[WARNNING] No object detected.')
  166. results = {'boxes': np.array([])}
  167. else:
  168. boxes_list.append(np_boxes)
  169. lmks_list.append(np_lmk)
  170. results = self.postprocess(
  171. boxes_list, lmks_list, im_info, threshold=threshold)
  172. if visualization:
  173. if not os.path.exists(save_dir):
  174. os.makedirs(save_dir)
  175. output = D.visualize_box_mask(
  176. im=image, results=results, labels=["background", "face"])
  177. name = str(time.time()) + '.png'
  178. save_path = os.path.join(save_dir, name)
  179. output.save(save_path)
  180. img = cv2.cvtColor(np.array(output), cv2.COLOR_RGB2BGR)
  181. results['image'] = img
  182. return results