深度学习|目标检测评价指标&NMS


1.目标检测

目标检测(Object Detection)的任务是找出图像中所有感兴趣的目标,并确定它们的类别和位置。
目标检测的位置信息一般由两种格式(以图片左上角为原点(0,0)):
1、极坐标表示:(xmin, ymin, xmax, ymax)

  • xmin,ymin:x,y坐标的最小值
  • xmin,ymin:x,y坐标的最大值

2、中心点坐标:(x_center, y_center, w, h)

  • x_center, y_center:目标检测框的中心点坐标
  • w,h:目标检测框的宽、高

image

那么按中心坐标如下:
image

2.常用的评价指标

2.1 Iou

在目标检测算法中,IoU(intersection over union,交并比)是目标检测算法中用来评价2个矩形框之间相似度的指标:
IoU = 两个矩形框相交的面积 / 两个矩形框相并的面积
通过一个例子看下在目标检测中的应用:
image
其中上图蓝色框框为检测结果,红色框框为真实标注。
一般我们会设置应该阈值,一旦IoU大于阈值,我们就认为检测到目标物体。
代码实现:

import numpy as np
def Iou(box1,box2,wh=False):
	# 判断是否按中心坐标
	 if wh == False:
	 	# 使用极坐标
	 	xmin1,ymin1,xmax1,ymax1 = box1
	 	xmin2,ymin2,xmax2,ymax2 = box2
	 else:
	 	# 使用中心坐标
	 	xmin1,ymin1 = int(box1[0]-box1[2]/2),int(box1[1]-box1[3]/2)
	 	xmax1,ymax1 = int(box1[0]+box1[2]/2),int(box1[1]+box1[3]/2)

		xmin2,ymin2 = int(box2[0]-box2[2]/2),int(box2[1]-box2[3]/2)
	 	xmax2,ymax2 = int(box2[0]+box2[2]/2),int(box2[1]+box2[3]/2)

	# 获取交集的左上和右下的坐标
	xx1 = np.max([xmin1,xmin2])
	yy1 = np.max([ymin1,ymin2])

	xx2 = np.min([xmax1,xmax2])
	yy2 = np.min([ymax1,ymax2])
	# 计算两个矩形的面积
	area1 = (xmax1-xmin1) * (ymax1-ymin1)
	area2 = (xmax2-xmin2) * (ymax2-ymin2)
	# 计算交集的面积
	inter_area = (np.max([0.0,xx2-xx1]))*(np.max([0.0,yy2-yy1]))
	# 计算Iou
	iou = inter_area/(area2+area1-inter_area+1e-6)
	return iou

2.2 mAP

目标检测问题中的每个图片都可能包含一些不同类别的物体,需要评估模型的物体分类和定位性能。因此,用于图像分类问题的标准指标precision不能直接应用于此。 在目标检测中,mAP是主要的衡量指标。
mAP是多个分类任务的AP的平均值,而AP(average precision)是PR曲线下的面积,所以在介绍mAP之前我们要先得到PR曲线。
TP、FP、FN、TN

  • TP:Iou大于阈值的检测框数量
  • FP:Iou小于阈值的检测框数量,或者是检测到同一个GT(Ground Truth,真实框)的多余检测框的数量
  • FN:没有被检测到的GT的数量
  • TN:在mAP没有用到,无实际意义

查准率、查全率

  • 查准率:TP/(TP+FP)
  • 查全率:TP/(TP+NP)

查全率(Recall)做横坐标,查准率(Precision)做纵坐标
image
AP 是计算某一类 P-R 曲线下的面积,mAP 则是计算所有类别 P-R 曲线下面积的平均值。
使用例子帮助理解
假设我们有 7 张图片(Images1-Image7),这些图片有 15 个目标(绿色的框,GT 的数量,上文提及的 all ground truths)以及 24 个预测边框(红色的框,A-Y 编号表示,并且有一个置信度值):
image
根据上图以及说明,我们可以列出以下表格,其中 Images 代表图片的编号,Detections 代表预测边框的编号,Confidences 代表预测边框的置信度,TP or FP 代表预测的边框是标记为 TP 还是 FP(认为预测边框与 GT 的 IOU 值大于等于 0.3 就标记为 TP;若一个 GT 有多个预测边框,则认为 IOU 最大且大于等于 0.3 的预测框标记为 TP,其他的标记为 FP,即一个 GT 只能有一个预测框标记为 TP),这里的 0.3 是随机取的一个值。
image
因为此时的到的只是一组固定P、R,不能绘制P-R 曲线,以此我们引入累加的概念。根据置信度从大到小排序所有的预测框,然后就可以计算 Precision 和 Recall 的值,见下表。
image

  • 每一行的Precision = ACCTP/(ACCTP+ACCFP):比如标号为10的Precision=3/(7+3)=0.3
  • 每一行的Recall = ACCTP/(GT):比如标号为10的Recall=3/15=0.2
    以此类推,按Confidences算出所有预测框的Precision和Recall
    然后就可以绘制出 P-R 曲线
    image
    得到 P-R 曲线就可以计算 AP(P-R 曲线下的面积),要计算 P-R 下方的面积,有两种方法:
    在VOC2010以前,只需要选取当Recall >= 0, 0.1, 0.2, ..., 1共11个点时的Precision最大值,然后AP就是这11个Precision的平均值,取 11 个点 [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1] 的插值所得
    image
    当Recall=0.2时,>=0.2的Precision最大值为0.4,故为0.4,>0.5以后Recall都为0
    这时我们得到一个类别的AP结果:
    image
    在VOC2010及以后,需要针对每一个不同的Recall值(包括0和1),选取其大于等于这些Recall值时的Precision最大值,如下图所示:
    image
    然后计算PR曲线下面积作为AP值:
    image
    image
    计算mAP就是将所有类别的相加再除以类别个数。

3.NMS(非极大值抑制)

非极大值抑制(Non-Maximum Suppression,NMS),顾名思义就是抑制不是极大值的元素。我们在检测一个真实框时,可能出现很多备选测试框,这时我们选择某一指标最大的窗口,并且抑制那些分数低的窗口。
在目标检测中,NMS的目的就是要去除冗余的检测框,保留最好的一个,如下图所示:
image
NMS的原理是对于预测框的列表B及其对应的置信度S,选择具有最大score的检测框M,将其从B集合中移除并加入到最终的检测结果D中.通常将B中剩余检测框中与M的IoU大于阈值Nt的框从B中移除.重复这个过程,直到B为空。
使用流程如下图所示:

  • 首先是检测出一系列的检测框
  • 将检测框按照类别进行分类
  • 对同一类别的检测框应用NMS获取最终的检测结果

通过一个例子看些NMS的使用方法,假设定位车辆,算法就找出了一系列的矩形框,我们需要判别哪些矩形框是没用的,需要使用NMS的方法来实现。
image
假设现在检测窗口有:A、B、C、D、E 5个候选框,接下来进行迭代计算:

  • 第一轮:因为B是得分最高的,与B的IoU>0.5删除。A,CDE中现在与B计算IoU,DE结果>0.5,剔除DE,B作为一个预测结果,有个检测框留下B,放入集合
  • 第二轮:A的得分最高,与A计算IoU,C的结果>0.5,剔除C,A作为一个结果

最终结果为在这个5个中检测出了两个目标为A和B。
代码实现如下:

def nms(boxes,score,threshold):
	if len(boxes)==0:
		return [],[]
	# 类型转换
	boxes = np.array(boxes)
	score = np.array(score)
	# 获取坐标
	x1 = boxes[:,0]
	y1 = boxes[:,1]
	x2 = boxes[:,2]
	y2 = boxes[:,3]
	# 计算面积
	areas = (x2-x1)*(y2-y1)

	picked_boxed = []
	picked_score = []

	#按score排序,从小到大,返回索引值
	order = np.argsort(score)
	while order.size>0:
		# 获取score最大值的索引
		index = order[-1]
		picked_boxed.append(boxes[index]) 
		picked_score.append(score[index])
		# 计算交集的面积
		x11 = np.maximum(x1[index],x1[order[:-1]])
		y11 = np.maximum(y1[index],y1[order[:-1]])
		x22 = np.minimum(x2[index],x2[order[:-1]])
		y22 = np.minimum(y2[index],y2[order[:-1]])
		inter_area = np.maximum(0.0,x22-x11)*np.maximum(0.0,y22-y11)
		keep_boxes = np.where(iou<threshold)
		order = order[keep_boxes]
	return picked_boxed,picked_score

假设有检测结果如下:

bounding = [(187, 82, 337, 317), (150, 67, 305, 282), (246, 121, 368, 304)]
confidence_score = [0.9, 0.65, 0.8]
threshold = 0.3
picked_boxes, picked_score = nms(bounding, confidence_score, threshold)
print('阈值threshold为:', threshold)
print('NMS后得到的bbox是:', picked_boxes)
print('NMS后得到的bbox的confidences是:', picked_score)

返回结果:
阈值threshold为: 0.3
NMS后得到的bbox是: [array([187, 82, 337, 317])]
NMS后得到的bbox的confidences是: [0.9]


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM