data_feed.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  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 base64
  16. import cv2
  17. import numpy as np
  18. from PIL import Image, ImageDraw
  19. import paddle.fluid as fluid
  20. def create_inputs(im, im_info):
  21. """generate input for different model type
  22. Args:
  23. im (np.ndarray): image (np.ndarray)
  24. im_info (dict): info of image
  25. Returns:
  26. inputs (dict): input of model
  27. """
  28. inputs = {}
  29. inputs['image'] = im
  30. origin_shape = list(im_info['origin_shape'])
  31. resize_shape = list(im_info['resize_shape'])
  32. pad_shape = list(im_info['pad_shape']) if im_info[
  33. 'pad_shape'] is not None else list(im_info['resize_shape'])
  34. scale_x, scale_y = im_info['scale']
  35. scale = scale_x
  36. im_info = np.array([resize_shape + [scale]]).astype('float32')
  37. inputs['im_info'] = im_info
  38. return inputs
  39. def visualize_box_mask(im,
  40. results,
  41. labels=None,
  42. mask_resolution=14,
  43. threshold=0.5):
  44. """
  45. Args:
  46. im (str/np.ndarray): path of image/np.ndarray read by cv2
  47. results (dict): include 'boxes': np.ndarray: shape:[N,6], N: number of box,
  48. matix element:[class, score, x_min, y_min, x_max, y_max]
  49. MaskRCNN's results include 'masks': np.ndarray:
  50. shape:[N, class_num, mask_resolution, mask_resolution]
  51. labels (list): labels:['class1', ..., 'classn']
  52. mask_resolution (int): shape of a mask is:[mask_resolution, mask_resolution]
  53. threshold (float): Threshold of score.
  54. Returns:
  55. im (PIL.Image.Image): visualized image
  56. """
  57. if not labels:
  58. labels = ['background', 'person']
  59. if isinstance(im, str):
  60. im = Image.open(im).convert('RGB')
  61. else:
  62. im = cv2.cvtColor(im, cv2.COLOR_BGR2RGB)
  63. im = Image.fromarray(im)
  64. if 'masks' in results and 'boxes' in results:
  65. im = draw_mask(
  66. im,
  67. results['boxes'],
  68. results['masks'],
  69. labels,
  70. resolution=mask_resolution)
  71. if 'boxes' in results:
  72. im = draw_box(im, results['boxes'], labels)
  73. if 'segm' in results:
  74. im = draw_segm(
  75. im,
  76. results['segm'],
  77. results['label'],
  78. results['score'],
  79. labels,
  80. threshold=threshold)
  81. if 'landmark' in results:
  82. im = draw_lmk(im, results['landmark'])
  83. return im
  84. def get_color_map_list(num_classes):
  85. """
  86. Args:
  87. num_classes (int): number of class
  88. Returns:
  89. color_map (list): RGB color list
  90. """
  91. color_map = num_classes * [0, 0, 0]
  92. for i in range(0, num_classes):
  93. j = 0
  94. lab = i
  95. while lab:
  96. color_map[i * 3] |= (((lab >> 0) & 1) << (7 - j))
  97. color_map[i * 3 + 1] |= (((lab >> 1) & 1) << (7 - j))
  98. color_map[i * 3 + 2] |= (((lab >> 2) & 1) << (7 - j))
  99. j += 1
  100. lab >>= 3
  101. color_map = [color_map[i:i + 3] for i in range(0, len(color_map), 3)]
  102. return color_map
  103. def expand_boxes(boxes, scale=0.0):
  104. """
  105. Args:
  106. boxes (np.ndarray): shape:[N,4], N:number of box,
  107. matix element:[x_min, y_min, x_max, y_max]
  108. scale (float): scale of boxes
  109. Returns:
  110. boxes_exp (np.ndarray): expanded boxes
  111. """
  112. w_half = (boxes[:, 2] - boxes[:, 0]) * .5
  113. h_half = (boxes[:, 3] - boxes[:, 1]) * .5
  114. x_c = (boxes[:, 2] + boxes[:, 0]) * .5
  115. y_c = (boxes[:, 3] + boxes[:, 1]) * .5
  116. w_half *= scale
  117. h_half *= scale
  118. boxes_exp = np.zeros(boxes.shape)
  119. boxes_exp[:, 0] = x_c - w_half
  120. boxes_exp[:, 2] = x_c + w_half
  121. boxes_exp[:, 1] = y_c - h_half
  122. boxes_exp[:, 3] = y_c + h_half
  123. return boxes_exp
  124. def draw_mask(im, np_boxes, np_masks, labels, resolution=14, threshold=0.5):
  125. """
  126. Args:
  127. im (PIL.Image.Image): PIL image
  128. np_boxes (np.ndarray): shape:[N,6], N: number of box,
  129. matix element:[class, score, x_min, y_min, x_max, y_max]
  130. np_masks (np.ndarray): shape:[N, class_num, resolution, resolution]
  131. labels (list): labels:['class1', ..., 'classn']
  132. resolution (int): shape of a mask is:[resolution, resolution]
  133. threshold (float): threshold of mask
  134. Returns:
  135. im (PIL.Image.Image): visualized image
  136. """
  137. color_list = get_color_map_list(len(labels))
  138. scale = (resolution + 2.0) / resolution
  139. im_w, im_h = im.size
  140. w_ratio = 0.4
  141. alpha = 0.7
  142. im = np.array(im).astype('float32')
  143. rects = np_boxes[:, 2:]
  144. expand_rects = expand_boxes(rects, scale)
  145. expand_rects = expand_rects.astype(np.int32)
  146. clsid_scores = np_boxes[:, 0:2]
  147. padded_mask = np.zeros((resolution + 2, resolution + 2), dtype=np.float32)
  148. clsid2color = {}
  149. for idx in range(len(np_boxes)):
  150. clsid, score = clsid_scores[idx].tolist()
  151. clsid = int(clsid)
  152. xmin, ymin, xmax, ymax = expand_rects[idx].tolist()
  153. w = xmax - xmin + 1
  154. h = ymax - ymin + 1
  155. w = np.maximum(w, 1)
  156. h = np.maximum(h, 1)
  157. padded_mask[1:-1, 1:-1] = np_masks[idx, int(clsid), :, :]
  158. resized_mask = cv2.resize(padded_mask, (w, h))
  159. resized_mask = np.array(resized_mask > threshold, dtype=np.uint8)
  160. x0 = min(max(xmin, 0), im_w)
  161. x1 = min(max(xmax + 1, 0), im_w)
  162. y0 = min(max(ymin, 0), im_h)
  163. y1 = min(max(ymax + 1, 0), im_h)
  164. im_mask = np.zeros((im_h, im_w), dtype=np.uint8)
  165. im_mask[y0:y1, x0:x1] = resized_mask[(y0 - ymin):(y1 - ymin), (
  166. x0 - xmin):(x1 - xmin)]
  167. if clsid not in clsid2color:
  168. clsid2color[clsid] = color_list[clsid]
  169. color_mask = clsid2color[clsid]
  170. for c in range(3):
  171. color_mask[c] = color_mask[c] * (1 - w_ratio) + w_ratio * 255
  172. idx = np.nonzero(im_mask)
  173. color_mask = np.array(color_mask)
  174. im[idx[0], idx[1], :] *= 1.0 - alpha
  175. im[idx[0], idx[1], :] += alpha * color_mask
  176. return Image.fromarray(im.astype('uint8'))
  177. def draw_box(im, np_boxes, labels):
  178. """
  179. Args:
  180. im (PIL.Image.Image): PIL image
  181. np_boxes (np.ndarray): shape:[N,6], N: number of box,
  182. matix element:[class, score, x_min, y_min, x_max, y_max]
  183. labels (list): labels:['class1', ..., 'classn']
  184. Returns:
  185. im (PIL.Image.Image): visualized image
  186. """
  187. draw_thickness = min(im.size) // 320
  188. draw = ImageDraw.Draw(im)
  189. clsid2color = {}
  190. color_list = get_color_map_list(len(labels))
  191. for dt in np_boxes:
  192. clsid, bbox, score = int(dt[0]), dt[2:], dt[1]
  193. xmin, ymin, xmax, ymax = bbox
  194. w = xmax - xmin
  195. h = ymax - ymin
  196. if clsid not in clsid2color:
  197. clsid2color[clsid] = color_list[clsid]
  198. color = tuple(clsid2color[clsid])
  199. # draw bbox
  200. draw.line(
  201. [(xmin, ymin), (xmin, ymax), (xmax, ymax), (xmax, ymin),
  202. (xmin, ymin)],
  203. width=draw_thickness,
  204. fill=color)
  205. # draw label
  206. text = "{} {:.4f}".format(labels[clsid], score)
  207. tw, th = draw.textsize(text)
  208. draw.rectangle(
  209. [(xmin + 1, ymin - th), (xmin + tw + 1, ymin)], fill=color)
  210. draw.text((xmin + 1, ymin - th), text, fill=(255, 255, 255))
  211. return im
  212. def draw_segm(im,
  213. np_segms,
  214. np_label,
  215. np_score,
  216. labels,
  217. threshold=0.5,
  218. alpha=0.7):
  219. """
  220. Draw segmentation on image
  221. """
  222. mask_color_id = 0
  223. w_ratio = .4
  224. color_list = get_color_map_list(len(labels))
  225. im = np.array(im).astype('float32')
  226. clsid2color = {}
  227. np_segms = np_segms.astype(np.uint8)
  228. index = np.where(np_label == 0)[0]
  229. index = np.where(np_score[index] > threshold)[0]
  230. person_segms = np_segms[index]
  231. person_mask = np.sum(person_segms, axis=0)
  232. person_mask[person_mask > 1] = 1
  233. person_mask = np.expand_dims(person_mask, axis=2)
  234. person_mask = np.repeat(person_mask, 3, axis=2)
  235. im = im * person_mask
  236. return Image.fromarray(im.astype('uint8'))
  237. def load_predictor(model_dir,
  238. run_mode='fluid',
  239. batch_size=1,
  240. use_gpu=False,
  241. min_subgraph_size=3):
  242. """set AnalysisConfig, generate AnalysisPredictor
  243. Args:
  244. model_dir (str): root path of __model__ and __params__
  245. use_gpu (bool): whether use gpu
  246. Returns:
  247. predictor (PaddlePredictor): AnalysisPredictor
  248. Raises:
  249. ValueError: predict by TensorRT need use_gpu == True.
  250. """
  251. if not use_gpu and not run_mode == 'fluid':
  252. raise ValueError(
  253. "Predict by TensorRT mode: {}, expect use_gpu==True, but use_gpu == {}"
  254. .format(run_mode, use_gpu))
  255. if run_mode == 'trt_int8':
  256. raise ValueError("TensorRT int8 mode is not supported now, "
  257. "please use trt_fp32 or trt_fp16 instead.")
  258. precision_map = {
  259. 'trt_int8': fluid.core.AnalysisConfig.Precision.Int8,
  260. 'trt_fp32': fluid.core.AnalysisConfig.Precision.Float32,
  261. 'trt_fp16': fluid.core.AnalysisConfig.Precision.Half
  262. }
  263. config = fluid.core.AnalysisConfig(
  264. os.path.join(model_dir, '__model__'),
  265. os.path.join(model_dir, '__params__'))
  266. if use_gpu:
  267. # initial GPU memory(M), device ID
  268. config.enable_use_gpu(100, 0)
  269. # optimize graph and fuse op
  270. config.switch_ir_optim(True)
  271. else:
  272. config.disable_gpu()
  273. if run_mode in precision_map.keys():
  274. config.enable_tensorrt_engine(
  275. workspace_size=1 << 10,
  276. max_batch_size=batch_size,
  277. min_subgraph_size=min_subgraph_size,
  278. precision_mode=precision_map[run_mode],
  279. use_static=False,
  280. use_calib_mode=False)
  281. # disable print log when predict
  282. config.disable_glog_info()
  283. # enable shared memory
  284. config.enable_memory_optim()
  285. # disable feed, fetch OP, needed by zero_copy_run
  286. config.switch_use_feed_fetch_ops(False)
  287. predictor = fluid.core.create_paddle_predictor(config)
  288. return predictor
  289. def cv2_to_base64(image):
  290. data = cv2.imencode('.jpg', image)[1]
  291. return base64.b64encode(data.tostring()).decode('utf8')
  292. def base64_to_cv2(b64str):
  293. data = base64.b64decode(b64str.encode('utf8'))
  294. data = np.fromstring(data, np.uint8)
  295. data = cv2.imdecode(data, cv2.IMREAD_COLOR)
  296. return data
  297. def lmk2out(bboxes, np_lmk, im_info, threshold=0.5, is_bbox_normalized=True):
  298. image_w, image_h = im_info['origin_shape']
  299. scale = im_info['scale']
  300. face_index, landmark, prior_box = np_lmk[:]
  301. xywh_res = []
  302. if bboxes.shape == (1, 1) or bboxes is None:
  303. return np.array([])
  304. prior = np.reshape(prior_box, (-1, 4))
  305. predict_lmk = np.reshape(landmark, (-1, 10))
  306. k = 0
  307. for i in range(bboxes.shape[0]):
  308. score = bboxes[i][1]
  309. if score < threshold:
  310. continue
  311. theindex = face_index[i][0]
  312. me_prior = prior[theindex, :]
  313. lmk_pred = predict_lmk[theindex, :]
  314. prior_h = me_prior[2] - me_prior[0]
  315. prior_w = me_prior[3] - me_prior[1]
  316. prior_h_center = (me_prior[2] + me_prior[0]) / 2
  317. prior_w_center = (me_prior[3] + me_prior[1]) / 2
  318. lmk_decode = np.zeros((10))
  319. for j in [0, 2, 4, 6, 8]:
  320. lmk_decode[j] = lmk_pred[j] * 0.1 * prior_w + prior_h_center
  321. for j in [1, 3, 5, 7, 9]:
  322. lmk_decode[j] = lmk_pred[j] * 0.1 * prior_h + prior_w_center
  323. if is_bbox_normalized:
  324. lmk_decode = lmk_decode * np.array([
  325. image_h, image_w, image_h, image_w, image_h, image_w, image_h,
  326. image_w, image_h, image_w
  327. ])
  328. xywh_res.append(lmk_decode)
  329. return np.asarray(xywh_res)
  330. def draw_lmk(image, lmk_results):
  331. draw = ImageDraw.Draw(image)
  332. for lmk_decode in lmk_results:
  333. for j in range(5):
  334. x1 = int(round(lmk_decode[2 * j]))
  335. y1 = int(round(lmk_decode[2 * j + 1]))
  336. draw.ellipse(
  337. (x1 - 2, y1 - 2, x1 + 3, y1 + 3), fill='green', outline='green')
  338. return image