首先,调用pycocotools工具包中cocoeval中的evaluateImg(计算单张图片在特征类别,特定面积阈值,特定最大检测结果下的结果), accumulate(将每张图片的评估结果累计到一起,并把结果存在self.eval变量中)以及summarize(输出给定检测指标、给定iouThr、给定面积阈值、给定最大检测结果时想要的指标)函数,具体是怎么实现的可以参考这篇博客:COCO API-深入解析cocoeval在det中的应用
在调用完accumulate函数后,可以从实例化的coco_evaluator下面找到输出的eval字典,绘制pr曲线只需要其中的precision键值对即可。而coco_eval.eval['precision']是一个5维的数组,shape为[T, R, K, A, M],其中:
T = len(p.iouThrs) # IoU的10个阈值,从0.5到0.95间隔0.05
R = len(p.recThrs) # 101个recall 阈值,从0到1.01
K = len(p.catIds) if p.useCats else 1 # 特定的检测类别
A = len(p.areaRng) # area 目标的大小范围 (all,small, medium, large)
M = len(p.maxDets) # maxDets 单张图像中最多检测框的数量 三种 1,10,100
precision = -np.ones((T,R,K,A,M)) # -1 for the precision of absent categories
然后将cocoeval的结果保存到本地的json文件格式:
# 将cocoeval的结果保存到本地文件中
cocoeval_result = coco_evaluator.coco_eval['bbox'].eval
keys_to_extract = ['precision', 'recall', 'scores']
# 将numpy格式的多维数组转成列表存储,不然会报错
cocoeval_result_new = {key : cocoeval_result[key].tolist() for key in keys_to_extract if key in cocoeval_result}
with open(path_cocoevalresult,"w") as f:
json.dump(cocoeval_result_new, f)
接下来就是对保存的检测结果进行处理绘制pr曲线:
import json
import numpy as np
import matplotlib.pyplot as plt
with open('cocoevalresult.json','r',encoding='utf-8') as f:
eval = json.load(f)
# 取出iouThr=0.5和0.75,类别为0类,不限定检测面积区间,单张图片最大检测数量为100时的precision
pr_array1 = np.array(eval['precision'])[0, :, 0, 0, 2]
pr_array2 = np.array(eval['precision'])[5, :, 0, 0, 2]
x = np.arange(0.0, 1.01, 0.01)
plt.xlabel('recall')
plt.ylabel('precision')
plt.xlim(0, 1.0)
plt.ylim(0, 1.01)
plt.grid(True)
plt.plot(x, pr_array1, 'b-', label='IoU=0.5')
plt.plot(x, pr_array2, 'y-', label='IoU=0.75')
plt.legend(loc='lower left')
plt.show()
最后画出来的pr曲线: