crowdhuman_evaluator.py 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. import os
  2. import json
  3. import time
  4. import numpy as np
  5. import torch
  6. from dataset.crowdhuman import CrowdHumanDataset
  7. from .crowdhuman_tools import compute_JI, compute_APMR
  8. class CrowdHumanEvaluator():
  9. def __init__(self, data_dir, device, image_set='val', transform=None):
  10. """
  11. Args:
  12. data_dir (str): dataset root directory
  13. device: (int): CUDA or CPU.
  14. image_set: train or val.
  15. transform: used to preprocess inputs.
  16. """
  17. # ----------------- Basic parameters -----------------
  18. self.eval_source = os.path.join(data_dir, 'annotation_val.odgt')
  19. self.image_set = image_set
  20. self.transform = transform
  21. self.device = device
  22. self.evalDir = os.path.join('det_results', 'eval', 'CrowdHuman', time.strftime("%Y%S"))
  23. os.makedirs(self.evalDir, exist_ok=True)
  24. # ----------------- Metrics -----------------
  25. self.map = 0.
  26. self.mr = 0.
  27. self.ji = 0.
  28. # ----------------- Dataset -----------------
  29. self.dataset = CrowdHumanDataset(data_dir=data_dir, image_set=image_set)
  30. def boxes_dump(self, boxes):
  31. if boxes.shape[-1] == 7:
  32. result = [{'box':[round(i, 1) for i in box[:4]],
  33. 'score':round(float(box[4]), 5),
  34. 'tag':int(box[5]),
  35. 'proposal_num':int(box[6])} for box in boxes]
  36. elif boxes.shape[-1] == 6:
  37. result = [{'box':[round(i, 1) for i in box[:4].tolist()],
  38. 'score':round(float(box[4]), 5),
  39. 'tag':int(box[5])} for box in boxes]
  40. elif boxes.shape[-1] == 5:
  41. result = [{'box':[round(i, 1) for i in box[:4]],
  42. 'tag':int(box[4])} for box in boxes]
  43. else:
  44. raise ValueError('Unknown box dim.')
  45. return result
  46. @torch.no_grad()
  47. def inference(self, model):
  48. model.eval()
  49. all_result_dicts = []
  50. num_images = len(self.dataset)
  51. print('total number of images: %d' % (num_images))
  52. # start testing
  53. for index in range(num_images): # all the data in val2017
  54. if index % 500 == 0:
  55. print('[Eval: %d / %d]'%(index, num_images))
  56. # load an image
  57. img, img_id = self.dataset.pull_image(index)
  58. orig_h, orig_w, _ = img.shape
  59. # load a gt
  60. gt_bboxes, gt_labels = self.dataset.pull_anno(index)
  61. gt_bboxes = np.array(gt_bboxes)[..., :4] # [N, 4]
  62. gt_tag = np.ones([gt_bboxes.shape[0], 1], dtype=gt_bboxes.dtype)
  63. gt_bboxes = np.concatenate([gt_bboxes, gt_tag], axis=-1)
  64. # preprocess
  65. x, _, deltas = self.transform(img)
  66. x = x.unsqueeze(0).to(self.device) / 255.
  67. # inference
  68. outputs = model(x)
  69. bboxes, scores, labels = outputs
  70. # rescale
  71. img_h, img_w = x.shape[-2:]
  72. bboxes[..., [0, 2]] = bboxes[..., [0, 2]] / (img_w - deltas[0]) * orig_w
  73. bboxes[..., [1, 3]] = bboxes[..., [1, 3]] / (img_h - deltas[1]) * orig_h
  74. # clip bboxes
  75. bboxes[..., [0, 2]] = np.clip(bboxes[..., [0, 2]], a_min=0., a_max=orig_w)
  76. bboxes[..., [1, 3]] = np.clip(bboxes[..., [1, 3]], a_min=0., a_max=orig_h)
  77. pd_tag = np.ones_like(scores)
  78. pd_bboxes = np.concatenate(
  79. [bboxes, scores[..., None], pd_tag[..., None]], axis=-1)
  80. # [x1, y1, x2, y2] -> [x1, y1, bw, bh]
  81. pd_bboxes[:, 2:4] -= pd_bboxes[:, :2]
  82. gt_bboxes[:, 2:4] -= gt_bboxes[:, :2]
  83. result_dict = dict(
  84. ID=img_id,
  85. height=int(orig_h),
  86. width=int(orig_w),
  87. dtboxes=self.boxes_dump(pd_bboxes.astype(np.float64)),
  88. gtboxes=self.boxes_dump(gt_bboxes.astype(np.float64))
  89. )
  90. all_result_dicts.append(result_dict)
  91. return all_result_dicts
  92. @torch.no_grad()
  93. def evaluate(self, model):
  94. # inference
  95. all_results = self.inference(model)
  96. # save json lines
  97. fpath = os.path.join(self.evalDir, 'dump-{}.json'.format('yolo_free'))
  98. with open(fpath,'w') as fid:
  99. for db in all_results:
  100. line = json.dumps(db)+'\n'
  101. fid.write(line)
  102. # evaluation
  103. eval_path = os.path.join(self.evalDir, 'eval-{}.json'.format('yolo_free'))
  104. eval_fid = open(eval_path,'w')
  105. res_line, JI = compute_JI.evaluation_all(fpath, 'box')
  106. for line in res_line:
  107. eval_fid.write(line+'\n')
  108. AP, MR = compute_APMR.compute_APMR(fpath, self.eval_source, 'box')
  109. line = 'AP:{:.4f}, MR:{:.4f}, JI:{:.4f}.'.format(AP, MR, JI)
  110. print(line)
  111. eval_fid.write(line+'\n')
  112. eval_fid.close()
  113. self.map = AP
  114. self.mr = MR
  115. self.ji = JI