database.py 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. import os
  2. import json
  3. import numpy as np
  4. from .image import *
  5. PERSON_CLASSES = ['background', 'person']
  6. # DBBase
  7. class Database(object):
  8. def __init__(self, gtpath=None, dtpath=None, body_key=None, head_key=None, mode=0):
  9. """
  10. mode=0: only body; mode=1: only head
  11. """
  12. self.images = dict()
  13. self.eval_mode = mode
  14. self.loadData(gtpath, body_key, head_key, True)
  15. self.loadData(dtpath, body_key, head_key, False)
  16. self._ignNum = sum([self.images[i]._ignNum for i in self.images])
  17. self._gtNum = sum([self.images[i]._gtNum for i in self.images])
  18. self._imageNum = len(self.images)
  19. self.scorelist = None
  20. def loadData(self, fpath, body_key=None, head_key=None, if_gt=True):
  21. assert os.path.isfile(fpath), fpath + " does not exist!"
  22. with open(fpath, "r") as f:
  23. lines = f.readlines()
  24. records = [json.loads(line.strip('\n')) for line in lines]
  25. if if_gt:
  26. for record in records:
  27. self.images[record["ID"]] = Image(self.eval_mode)
  28. self.images[record["ID"]].load(record, body_key, head_key, PERSON_CLASSES, True)
  29. else:
  30. for record in records:
  31. self.images[record["ID"]].load(record, body_key, head_key, PERSON_CLASSES, False)
  32. self.images[record["ID"]].clip_all_boader()
  33. def compare(self, thres=0.5, matching=None):
  34. """
  35. match the detection results with the groundtruth in the whole database
  36. """
  37. assert matching is None or matching == "VOC", matching
  38. scorelist = list()
  39. for ID in self.images:
  40. if matching == "VOC":
  41. result = self.images[ID].compare_voc(thres)
  42. else:
  43. result = self.images[ID].compare_caltech(thres)
  44. scorelist.extend(result)
  45. # In the descending sort of dtbox score.
  46. scorelist.sort(key=lambda x: x[0][-1], reverse=True)
  47. self.scorelist = scorelist
  48. def eval_MR(self, ref="CALTECH_-2"):
  49. """
  50. evaluate by Caltech-style log-average miss rate
  51. ref: str - "CALTECH_-2"/"CALTECH_-4"
  52. """
  53. # find greater_than
  54. def _find_gt(lst, target):
  55. for idx, item in enumerate(lst):
  56. if item >= target:
  57. return idx
  58. return len(lst)-1
  59. assert ref == "CALTECH_-2" or ref == "CALTECH_-4", ref
  60. if ref == "CALTECH_-2":
  61. # CALTECH_MRREF_2: anchor points (from 10^-2 to 1) as in P.Dollar's paper
  62. ref = [0.0100, 0.0178, 0.03160, 0.0562, 0.1000, 0.1778, 0.3162, 0.5623, 1.000]
  63. else:
  64. # CALTECH_MRREF_4: anchor points (from 10^-4 to 1) as in S.Zhang's paper
  65. ref = [0.0001, 0.0003, 0.00100, 0.0032, 0.0100, 0.0316, 0.1000, 0.3162, 1.000]
  66. if self.scorelist is None:
  67. self.compare()
  68. tp, fp = 0.0, 0.0
  69. fppiX, fppiY = list(), list()
  70. for i, item in enumerate(self.scorelist):
  71. if item[1] == 1:
  72. tp += 1.0
  73. elif item[1] == 0:
  74. fp += 1.0
  75. fn = (self._gtNum - self._ignNum) - tp
  76. recall = tp / (tp + fn)
  77. precision = tp / (tp + fp)
  78. missrate = 1.0 - recall
  79. fppi = fp / self._imageNum
  80. fppiX.append(fppi)
  81. fppiY.append(missrate)
  82. score = list()
  83. for pos in ref:
  84. argmin = _find_gt(fppiX, pos)
  85. if argmin >= 0:
  86. score.append(fppiY[argmin])
  87. score = np.array(score)
  88. MR = np.exp(np.log(score).mean())
  89. return MR, (fppiX, fppiY)
  90. def eval_AP(self):
  91. """
  92. :meth: evaluate by average precision
  93. """
  94. # calculate general ap score
  95. def _calculate_map(recall, precision):
  96. assert len(recall) == len(precision)
  97. area = 0
  98. for i in range(1, len(recall)):
  99. delta_h = (precision[i-1] + precision[i]) / 2
  100. delta_w = recall[i] - recall[i-1]
  101. area += delta_w * delta_h
  102. return area
  103. tp, fp = 0.0, 0.0
  104. rpX, rpY = list(), list()
  105. total_det = len(self.scorelist)
  106. total_gt = self._gtNum - self._ignNum
  107. total_images = self._imageNum
  108. fpn = []
  109. recalln = []
  110. thr = []
  111. fppi = []
  112. for i, item in enumerate(self.scorelist):
  113. if item[1] == 1:
  114. tp += 1.0
  115. elif item[1] == 0:
  116. fp += 1.0
  117. fn = total_gt - tp
  118. recall = tp / (tp + fn)
  119. precision = tp / (tp + fp)
  120. rpX.append(recall)
  121. rpY.append(precision)
  122. fpn.append(fp)
  123. recalln.append(tp)
  124. thr.append(item[0][-1])
  125. fppi.append(fp/total_images)
  126. AP = _calculate_map(rpX, rpY)
  127. return AP, (rpX, rpY, thr, fpn, recalln, fppi)