keypoint_metrics.py 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. # Copyright (c) 2021 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 copy
  15. import os
  16. import json
  17. from collections import OrderedDict
  18. from collections import defaultdict
  19. import numpy as np
  20. from pycocotools.coco import COCO
  21. from pycocotools.cocoeval import COCOeval
  22. from ..modeling.keypoint_utils import oks_nms
  23. __all__ = ['KeyPointTopDownCOCOEval']
  24. class KeyPointTopDownCOCOEval(object):
  25. def __init__(self,
  26. anno_file,
  27. num_samples,
  28. num_joints,
  29. output_eval,
  30. iou_type='keypoints',
  31. in_vis_thre=0.2,
  32. oks_thre=0.9):
  33. super(KeyPointTopDownCOCOEval, self).__init__()
  34. self.coco = COCO(anno_file)
  35. self.num_samples = num_samples
  36. self.num_joints = num_joints
  37. self.iou_type = iou_type
  38. self.in_vis_thre = in_vis_thre
  39. self.oks_thre = oks_thre
  40. self.output_eval = output_eval
  41. self.res_file = os.path.join(output_eval, "keypoints_results.json")
  42. self.reset()
  43. def reset(self):
  44. self.results = {
  45. 'all_preds': np.zeros(
  46. (self.num_samples, self.num_joints, 3), dtype=np.float32),
  47. 'all_boxes': np.zeros((self.num_samples, 6)),
  48. 'image_path': []
  49. }
  50. self.eval_results = {}
  51. self.idx = 0
  52. def update(self, inputs, outputs):
  53. kpts, _ = outputs['keypoint'][0]
  54. num_images = inputs['image'].shape[0]
  55. self.results['all_preds'][self.idx:self.idx + num_images, :, 0:
  56. 3] = kpts[:, :, 0:3]
  57. self.results['all_boxes'][self.idx:self.idx + num_images, 0:
  58. 2] = inputs['center'].numpy()[:, 0:2]
  59. self.results['all_boxes'][self.idx:self.idx + num_images, 2:
  60. 4] = inputs['scale'].numpy()[:, 0:2]
  61. self.results['all_boxes'][self.idx:self.idx + num_images, 4] = np.prod(
  62. inputs['scale'].numpy() * 200, 1)
  63. self.results['all_boxes'][self.idx:self.idx + num_images,
  64. 5] = np.squeeze(inputs['score'].numpy())
  65. self.results['image_path'].extend(inputs['im_id'].numpy())
  66. self.idx += num_images
  67. def _write_coco_keypoint_results(self, keypoints):
  68. data_pack = [{
  69. 'cat_id': 1,
  70. 'cls': 'person',
  71. 'ann_type': 'keypoints',
  72. 'keypoints': keypoints
  73. }]
  74. results = self._coco_keypoint_results_one_category_kernel(data_pack[0])
  75. if not os.path.exists(self.output_eval):
  76. os.makedirs(self.output_eval)
  77. with open(self.res_file, 'w') as f:
  78. json.dump(results, f, sort_keys=True, indent=4)
  79. try:
  80. json.load(open(self.res_file))
  81. except Exception:
  82. content = []
  83. with open(self.res_file, 'r') as f:
  84. for line in f:
  85. content.append(line)
  86. content[-1] = ']'
  87. with open(self.res_file, 'w') as f:
  88. for c in content:
  89. f.write(c)
  90. def _coco_keypoint_results_one_category_kernel(self, data_pack):
  91. cat_id = data_pack['cat_id']
  92. keypoints = data_pack['keypoints']
  93. cat_results = []
  94. for img_kpts in keypoints:
  95. if len(img_kpts) == 0:
  96. continue
  97. _key_points = np.array(
  98. [img_kpts[k]['keypoints'] for k in range(len(img_kpts))])
  99. _key_points = _key_points.reshape(_key_points.shape[0], -1)
  100. result = [{
  101. 'image_id': img_kpts[k]['image'],
  102. 'category_id': cat_id,
  103. 'keypoints': _key_points[k].tolist(),
  104. 'score': img_kpts[k]['score'],
  105. 'center': list(img_kpts[k]['center']),
  106. 'scale': list(img_kpts[k]['scale'])
  107. } for k in range(len(img_kpts))]
  108. cat_results.extend(result)
  109. return cat_results
  110. def get_final_results(self, preds, all_boxes, img_path):
  111. _kpts = []
  112. for idx, kpt in enumerate(preds):
  113. _kpts.append({
  114. 'keypoints': kpt,
  115. 'center': all_boxes[idx][0:2],
  116. 'scale': all_boxes[idx][2:4],
  117. 'area': all_boxes[idx][4],
  118. 'score': all_boxes[idx][5],
  119. 'image': int(img_path[idx])
  120. })
  121. # image x person x (keypoints)
  122. kpts = defaultdict(list)
  123. for kpt in _kpts:
  124. kpts[kpt['image']].append(kpt)
  125. # rescoring and oks nms
  126. num_joints = preds.shape[1]
  127. in_vis_thre = self.in_vis_thre
  128. oks_thre = self.oks_thre
  129. oks_nmsed_kpts = []
  130. for img in kpts.keys():
  131. img_kpts = kpts[img]
  132. for n_p in img_kpts:
  133. box_score = n_p['score']
  134. kpt_score = 0
  135. valid_num = 0
  136. for n_jt in range(0, num_joints):
  137. t_s = n_p['keypoints'][n_jt][2]
  138. if t_s > in_vis_thre:
  139. kpt_score = kpt_score + t_s
  140. valid_num = valid_num + 1
  141. if valid_num != 0:
  142. kpt_score = kpt_score / valid_num
  143. # rescoring
  144. n_p['score'] = kpt_score * box_score
  145. keep = oks_nms([img_kpts[i] for i in range(len(img_kpts))],
  146. oks_thre)
  147. if len(keep) == 0:
  148. oks_nmsed_kpts.append(img_kpts)
  149. else:
  150. oks_nmsed_kpts.append([img_kpts[_keep] for _keep in keep])
  151. self._write_coco_keypoint_results(oks_nmsed_kpts)
  152. def accumulate(self):
  153. self.get_final_results(self.results['all_preds'],
  154. self.results['all_boxes'],
  155. self.results['image_path'])
  156. coco_dt = self.coco.loadRes(self.res_file)
  157. coco_eval = COCOeval(self.coco, coco_dt, 'keypoints')
  158. coco_eval.params.useSegm = None
  159. coco_eval.evaluate()
  160. coco_eval.accumulate()
  161. coco_eval.summarize()
  162. keypoint_stats = []
  163. for ind in range(len(coco_eval.stats)):
  164. keypoint_stats.append((coco_eval.stats[ind]))
  165. self.eval_results['keypoint'] = keypoint_stats
  166. def log(self):
  167. stats_names = [
  168. 'AP', 'Ap .5', 'AP .75', 'AP (M)', 'AP (L)', 'AR', 'AR .5',
  169. 'AR .75', 'AR (M)', 'AR (L)'
  170. ]
  171. num_values = len(stats_names)
  172. print(' '.join(['| {}'.format(name) for name in stats_names]) + ' |')
  173. print('|---' * (num_values + 1) + '|')
  174. print(' '.join([
  175. '| {:.3f}'.format(value) for value in self.eval_results['keypoint']
  176. ]) + ' |')
  177. def get_results(self):
  178. return self.eval_results