get_map.py 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. import os
  2. import xml.etree.ElementTree as ET
  3. from PIL import Image
  4. from tqdm import tqdm
  5. from utils.utils import get_classes
  6. from utils.utils_map import get_coco_map, get_map
  7. from frcnn import FRCNN
  8. if __name__ == "__main__":
  9. '''
  10. Recall和Precision不像AP是一个面积的概念,因此在门限值(Confidence)不同时,网络的Recall和Precision值是不同的。
  11. 默认情况下,本代码计算的Recall和Precision代表的是当门限值(Confidence)为0.5时,所对应的Recall和Precision值。
  12. 受到mAP计算原理的限制,网络在计算mAP时需要获得近乎所有的预测框,这样才可以计算不同门限条件下的Recall和Precision值
  13. 因此,本代码获得的map_out/detection-results/里面的txt的框的数量一般会比直接predict多一些,目的是列出所有可能的预测框,
  14. '''
  15. #------------------------------------------------------------------------------------------------------------------#
  16. # map_mode用于指定该文件运行时计算的内容
  17. # map_mode为0代表整个map计算流程,包括获得预测结果、获得真实框、计算VOC_map。
  18. # map_mode为1代表仅仅获得预测结果。
  19. # map_mode为2代表仅仅获得真实框。
  20. # map_mode为3代表仅仅计算VOC_map。
  21. # map_mode为4代表利用COCO工具箱计算当前数据集的0.50:0.95map。需要获得预测结果、获得真实框后并安装pycocotools才行
  22. #-------------------------------------------------------------------------------------------------------------------#
  23. map_mode = 0
  24. #--------------------------------------------------------------------------------------#
  25. # 此处的classes_path用于指定需要测量VOC_map的类别
  26. # 一般情况下与训练和预测所用的classes_path一致即可
  27. #--------------------------------------------------------------------------------------#
  28. classes_path = './/model_data/voc_classes.txt'
  29. #--------------------------------------------------------------------------------------#
  30. # MINOVERLAP用于指定想要获得的mAP0.x,mAP0.x的意义是什么请同学们百度一下。
  31. # 比如计算mAP0.75,可以设定MINOVERLAP = 0.75。
  32. #
  33. # 当某一预测框与真实框重合度大于MINOVERLAP时,该预测框被认为是正样本,否则为负样本。
  34. # 因此MINOVERLAP的值越大,预测框要预测的越准确才能被认为是正样本,此时算出来的mAP值越低,
  35. #--------------------------------------------------------------------------------------#
  36. MINOVERLAP = 0.5
  37. #--------------------------------------------------------------------------------------#
  38. # 受到mAP计算原理的限制,网络在计算mAP时需要获得近乎所有的预测框,这样才可以计算mAP
  39. # 因此,confidence的值应当设置的尽量小进而获得全部可能的预测框。
  40. #
  41. # 该值一般不调整。因为计算mAP需要获得近乎所有的预测框,此处的confidence不能随便更改。
  42. # 想要获得不同门限值下的Recall和Precision值,请修改下方的score_threhold。
  43. #--------------------------------------------------------------------------------------#
  44. confidence = 0.02
  45. #--------------------------------------------------------------------------------------#
  46. # 预测时使用到的非极大抑制值的大小,越大表示非极大抑制越不严格。
  47. #
  48. # 该值一般不调整。
  49. #--------------------------------------------------------------------------------------#
  50. nms_iou = 0.5
  51. #---------------------------------------------------------------------------------------------------------------#
  52. # Recall和Precision不像AP是一个面积的概念,因此在门限值不同时,网络的Recall和Precision值是不同的。
  53. #
  54. # 默认情况下,本代码计算的Recall和Precision代表的是当门限值为0.5(此处定义为score_threhold)时所对应的Recall和Precision值。
  55. # 因为计算mAP需要获得近乎所有的预测框,上面定义的confidence不能随便更改。
  56. # 这里专门定义一个score_threhold用于代表门限值,进而在计算mAP时找到门限值对应的Recall和Precision值。
  57. #---------------------------------------------------------------------------------------------------------------#
  58. score_threhold = 0.5
  59. #-------------------------------------------------------#
  60. # map_vis用于指定是否开启VOC_map计算的可视化
  61. #-------------------------------------------------------#
  62. map_vis = False
  63. #-------------------------------------------------------#
  64. # 指向VOC数据集所在的文件夹
  65. # 默认指向根目录下的VOC数据集
  66. #-------------------------------------------------------#
  67. VOCdevkit_path = './/VOCdevkit/VOC2007'
  68. #-------------------------------------------------------#
  69. # 结果输出的文件夹,默认为map_out
  70. #-------------------------------------------------------#
  71. map_out_path = 'map_out'
  72. path_temp = ".//VOCdevkit/VOC2007/ImageSets/Main/test.txt"
  73. image_ids = open(path_temp).read().strip().split()
  74. if not os.path.exists(map_out_path):
  75. os.makedirs(map_out_path)
  76. if not os.path.exists(os.path.join(map_out_path, 'ground-truth')):
  77. os.makedirs(os.path.join(map_out_path, 'ground-truth'))
  78. if not os.path.exists(os.path.join(map_out_path, 'detection-results')):
  79. os.makedirs(os.path.join(map_out_path, 'detection-results'))
  80. if not os.path.exists(os.path.join(map_out_path, 'images-optional')):
  81. os.makedirs(os.path.join(map_out_path, 'images-optional'))
  82. class_names, _ = get_classes(classes_path)
  83. if map_mode == 0 or map_mode == 1:
  84. print("Load model.")
  85. frcnn = FRCNN(confidence = confidence, nms_iou = nms_iou)
  86. print("Load model done.")
  87. print("Get predict result.")
  88. for image_id in tqdm(image_ids):
  89. img_path = ".//VOCdevkit/VOC2007/JPEGImages/"
  90. image_path = os.path.join(img_path + image_id+".jpg")
  91. image = Image.open(image_path)
  92. if map_vis:
  93. image.save(os.path.join(map_out_path, "images-optional/" + image_id + ".jpg"))
  94. frcnn.get_map_txt(image_id, image, class_names, map_out_path)
  95. print("Get predict result done.")
  96. if map_mode == 0 or map_mode == 2:
  97. print("Get ground truth result.")
  98. for image_id in tqdm(image_ids):
  99. with open(os.path.join(map_out_path, "ground-truth/"+image_id+".txt"), "w") as new_f:
  100. root_path = ".//VOCdevkit/VOC2007/Annotations/"
  101. root = ET.parse(os.path.join(root_path + image_id+".xml")).getroot()
  102. for obj in root.findall('object'):
  103. difficult_flag = False
  104. if obj.find('difficult')!=None:
  105. difficult = obj.find('difficult').text
  106. if int(difficult)==1:
  107. difficult_flag = True
  108. obj_name = obj.find('name').text
  109. if obj_name not in class_names:
  110. continue
  111. bndbox = obj.find('bndbox')
  112. left = bndbox.find('xmin').text
  113. top = bndbox.find('ymin').text
  114. right = bndbox.find('xmax').text
  115. bottom = bndbox.find('ymax').text
  116. if difficult_flag:
  117. new_f.write("%s %s %s %s %s difficult\n" % (obj_name, left, top, right, bottom))
  118. else:
  119. new_f.write("%s %s %s %s %s\n" % (obj_name, left, top, right, bottom))
  120. print("Get ground truth result done.")
  121. if map_mode == 0 or map_mode == 3:
  122. print("Get map.")
  123. get_map(MINOVERLAP, True, score_threhold = score_threhold, path = map_out_path)
  124. print("Get map done.")
  125. if map_mode == 4:
  126. print("Get map.")
  127. get_coco_map(class_names = class_names, path = map_out_path)
  128. print("Get map done.")