评价目标检测中的各种标准,如map,ROC通常用于分类算法中,按照混淆矩阵的计算方式:
ROC计算方式
ROC 为FPR(假阳率)为横坐标,TPR(真阳率)为纵坐标,围成的面积即为ROC值:
而在目标检测中,因为负样本(TN)的值很大,所以在目标检测中会直接考虑使用groundtruth个数,作为(TP + FN)个数;
ROC的实现
这里参考python 实现目标检测中roc
该文中因为只有人脸一个类别,实现完在自己的检测结果的ROC曲线有点问题
这里基于ROC的计算方式,对代码做了局部修改。
2.1 数据预处理
需要从算法端的检测结果保存成以下格式,将检测到的不同label的结果保存到一个txt中:
同一label检测结果保存成
[ 文件名
目标数
label xmin/ymin/xmax/ymax、conf] ,
同时检测的时候需要将conf的阈值设成很小的值,比如0.0001,这样ROC曲线的recall才能保证接近100%,保存成绝对长度就不需要再去读取图片获取长宽了;
2.2 代码实现
对于每个label,实现ROC :
import numpy as np
import cv2
import matplotlib.pyplot as plt
def load(txtfile):
'''
读取检测结果或 groundtruth 的文档, 若为椭圆坐标, 转换为矩形坐标
:param txtfile: 读入的.txt文件, 格式要求与FDDB相同
:return imagelist: list, 每张图片的信息单独为一行, 第一列是图片名称, 第二列是个数, 后面的列均为列表, 包含4个矩形坐标和1个分数
:return num_allboxes: int, 矩形框的总个数
'''
imagelist = [] # 包含所有图片的信息的列表
txtfile = open(txtfile, 'r')
lines = txtfile.readlines() # 一次性全部读取, 得到一个list
num_gt = 0
i = 0
while i < len(lines): # 在lines中循环一遍
image = [] # 包含一张图片信息的列表
image.append(lines[i].strip()) # 去掉首尾的空格和换行符, 向image中写入图片名称
num_ = int(lines[i + 1])
if num_ != 0:
num_gt = num_gt + 1
image.append(num_) # 向image中写入个数
if num_ > 0:
for num in range(num_):
boundingbox = lines[i + 2 + num].strip() # 去掉首尾的空格和换行符
boundingbox = boundingbox.split()[1: ] # 按中间的空格分割成多个元素
boundingbox = list(map(float, boundingbox)) # 转换成浮点数列表
image.append(boundingbox) # 向image中写入包含矩形坐标和分数的浮点数列表
imagelist.append(image) # 向imagelist中写入一张图片的信息
i = i + num_ + 2 # 增加index至下张图片开始的行数
txtfile.close()
return imagelist
def cal_IoU(detectedbox, groundtruthbox):
"""
计算两个水平竖直的矩形的交并比
:param detectedbox: list, [leftx_det, topy_det, width_det, height_det, confidence]
:param groundtruthbox: list, [leftx_gt, topy_gt, width_gt, height_gt, 1]
:return iou: 交并比
"""
leftx_det, topy_det, width_det, height_det, _ = detectedbox
leftx_gt, topy_gt, width_gt, height_gt = groundtruthbox
centerx_det = leftx_det + width_det / 2
centerx_gt = leftx_gt + width_gt / 2
centery_det = topy_det + height_det / 2
centery_gt = topy_gt + height_gt / 2
distancex = abs(centerx_det - centerx_gt) - (width_det + width_gt) / 2
distancey = abs(centery_det - centery_gt) - (height_det + height_gt) / 2
if distancex <= 0 and distancey <= 0:
intersection = distancex * distancey
union = width_det * height_det + width_gt * height_gt - intersection
iou = intersection / union
return iou
else:
return 0
def thres(maxiou_confidence, threshold = 0.5):
"""
将大于阈值的最大交并比记为1, 反正记为0
:param maxiou_confidence: np.array, 存放所有检测框对应的最大交并比和置信度
:param threshold: 阈值
:return tf_confidence: np.array, 存放所有检测框对应的tp或fp和置信度
"""
tf_confidence = maxiou_confidence[maxiou_confidence[:, 0] > threshold, :]
# tf_confidence = np.array([true_or_flase, confidences])
#tf_confidence = tf_confidence.T
if tf_confidence.size == 0:
tf_confidence = np.array([0])
else:
tf_confidence = tf_confidence[np.argsort(-tf_confidence[:, 1]), 1]
return tf_confidence
def match(resultsfile, groundtruthfile):
"""
匹配检测框和标注框, 为每一个检测框得到一个最大交并比
:param resultsfile: 包含检测结果的.txt文件
:param groundtruthfile: 包含标准答案的.txt文件
:param show_images: 是否显示图片
:return maxiou_confidence: np.array, 存放所有检测框对应的最大交并比和置信度
:return num_detectedbox: int, 检测框的总数
:return num_groundtruthbox: int, 标注框的总数
"""
results = load(resultsfile)
groundtruth = load(groundtruthfile)
print(results)
print(groundtruth)
assert len(results) == len(groundtruth), "数量不匹配: 标准答案中图片数量为%d, 而检测结果中图片数量为%d" % (
len(groundtruth), len(results))
results_predlist = []
results_name = []
for i in range(len(results)):
results_name.append(results[i][0])
for i in range(len(groundtruth)):# 对每个图片
results_pred = []
maxiou_confidence = np.array([])
if groundtruth[i][0] in results_name:
m = results_name.index(results[i][0])
else:
print("Not found ,Error")
results_pred.append(groundtruth[i][0])
if len(groundtruth[i]) == 2:
results_pred.append(0)
if len(results[m]) == 2:
maxiou_confidence = 0
else:
for k in range(2, len(results[m])): # 匹配这张图片中的每一个检测框
detectedbox = results[m][k]
confidence = detectedbox[-1]
maxiou_confidence = np.append(maxiou_confidence, confidence)
maxiou_confidence = max(maxiou_confidence)
results_pred.append(maxiou_confidence)
else:
results_pred.append(1)
for j in range(2, len(groundtruth[i])):#图片中每个真实框
iou_array = np.array([])
groundtruthbox = groundtruth[i][j]
if len(results[m]) == 2:
maxiou_confidence = np.append(maxiou_confidence, [0, 0])
else:
for k in range(2, len(results[m])): #匹配这张图片中的每一个检测框
detectedbox = results[m][k]
confidence = detectedbox[-1]
iou = cal_IoU(detectedbox, groundtruthbox)
iou_array = np.r_[iou_array, [iou, confidence]]
# iou_array = np.append(iou_array, [iou, confidence], axis=0) # 得到一个交并比的数组
# maxiou_index = np.argmax(iou_array[0], axis=0) # 最大交并比
# maxiou_confidence = np.append(maxiou_confidence, [maxiou, confidence])
maxiou_confidence = np.append(maxiou_confidence, iou_array)
maxiou_confidence = maxiou_confidence.reshape(-1, 2)
maxiou_confidence = maxiou_confidence[np.argsort(-maxiou_confidence[:, 1])] #置信度从大到小排列
tf_confidence = thres(maxiou_confidence, threshold=0.5)
tf_confidence = max(tf_confidence)
results_pred.append(tf_confidence)
results_predlist.append(results_pred)
# maxiou_confidence = maxiou_confidence[np.argsort(-maxiou_confidence[:, 1])] # 按置信度从大到小排序
return results_predlist
def draw_curves(resultsfile, groundtruthfile, show_images = False, threshold = 0.1):
"""
读取包含检测结果和标准答案的两个.txt文件, 画出ROC曲线和PR曲线
:param resultsfile: 包含检测结果的.txt文件
:param groundtruthfile: 包含标准答案的.txt文件
:param show_images: 是否显示图片, 若需可视化, 需修改Calculate.match中的代码, 找到存放图片的路径
:param threshold: IoU阈值
"""
print("---")
results_predlist = match(resultsfile, groundtruthfile)
# tf_confidence = thres(results_predlist, threshold)
return results_predlist
def plot(results_predlist, lvyaoyao_predlist):
"""
从上到下截取tf_confidence, 计算并画图
:param tf_confidence: np.array, 存放所有检测框对应的tp或fp和置信度
:param num_groundtruthbox: int, 标注框的总数
"""
fp_list = []
recall_list = []
precision_list = []
auc = 0
mAP = 0
gt_num = 0
ng_num = 0
for num in range(len(results_predlist)):
results_pred = results_predlist[num]
gt = results_pred[1] # gt
if gt == 0:
ng_num = ng_num + 1
else:
gt_num = gt_num + 1
print("tf_confidence", results_predlist)
for num in range(len(results_predlist)):
results_pred = results_predlist[num]
conf = results_pred[2] # confidence
print("conf", conf)
fp = 0
tp = 0
for j in range(len(results_predlist)):
results_pred = results_predlist[j]
gt = results_pred[1] # gt
if gt == 0:
if results_pred[2] >= conf:
fp = fp + 1
else:
if results_pred[2] >= conf:
tp = tp + 1
recall_list.append(tp)
fp_list.append(fp)
if num > 0:
auc = auc + (fp_list[-1] - fp_list[-2])/gt_num * (recall_list[-1] + recall_list[-2])/ng_num / 2
print("auc=", auc)
recall_list_1 = [x/gt_num for x in recall_list ]
fp_list_1 = [x / ng_num for x in fp_list]
print(recall_list_1)
print(fp_list_1)
#-------------------------------------------------------------------------------------
fp_list = []
recall_list = []
precision_list = []
auc2 = 0
mAP = 0
gt_num = 0
ng_num = 0
for num in range(len(lvyaoyao_predlist)):
results_pred = lvyaoyao_predlist[num]
gt = results_pred[1] # gt
if gt == 0:
ng_num = ng_num + 1
else:
gt_num = gt_num + 1
print("tf_confidence", lvyaoyao_predlist)
for num in range(len(lvyaoyao_predlist)):
results_pred = lvyaoyao_predlist[num]
conf = results_pred[2] # confidence
print("conf", conf)
fp = 0
tp = 0
for j in range(len(lvyaoyao_predlist)):
results_pred = lvyaoyao_predlist[j]
gt = results_pred[1] # gt
if gt == 0:
if results_pred[2] >= conf:
fp = fp + 1
else:
if results_pred[2] >= conf:
tp = tp + 1
recall_list.append(tp)
fp_list.append(fp)
if num > 0:
auc2 = auc2 + (fp_list[-1] - fp_list[-2]) / gt_num * (recall_list[-1] + recall_list[-2]) / ng_num / 2
print("auc=", auc2)
recall_list_2 = [x / gt_num for x in recall_list]
fp_list_2 = [x / ng_num for x in fp_list]
print(recall_list_2)
print(fp_list_2)
"draw picture"
fig = plt.figure()
ax1 = fig.add_subplot(111)
plt.title('ROC')
plt.xlabel('False Positives')
plt.xscale('log')
plt.ylabel('True Positive rate')
plt.ylim(0, 1)
ax1.plot(fp_list_1, recall_list_1, label='AUC: ' + str(auc))
ax1.plot(fp_list_2, recall_list_2, label='AUC: ' + str(auc2))
plt.legend()
# plt.figure()
# plt.title('Precision-Recall')
# plt.xlabel('Recall')
# plt.ylabel('Precision')
# plt.axis([0, 1, 0, 1])
# plt.plot(recall_list, precision_list, label='mAP: ' + str(mAP))
# plt.legend()
plt.show()
if __name__ == '__main__':
gt_txt = r"G:\all_gt.txt"
pred_txt =r"G:\all_1012_pred_rcnn.txt"
lvy_pred = r"G:\lvyy.txt"
results_predlist = draw_curves(pred_txt, gt_txt)
lvyy_predlist = draw_curves(lvy_pred, gt_txt)
results_predlist.sort(key=lambda x: x[2], reverse=True)
lvyy_predlist.sort(key=lambda x: x[2], reverse=True)
# results_predlist.sort(lambda x, y:cmp(x[2], y[2]),reverse=True)
# results_predlist = results_predlist[np.argsort(-results_predlist[:, 2])]
plot(results_predlist, lvyy_predlist)
在自己的检测结果上,实现:
版权声明:本文为CSDN博主「所向披靡的张大刀」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/zqwwwm/article/details/121356241
暂无评论