目标检测任务=分类+定位
xmin,ymin,xmax,ymax
)即左上角坐标和右下角坐标x_center,y_center,w,h
)PASCAL VOC数据集 和 MS COCO数据集。
PASCAL VOC包含约10,000张带有边界框的图片用于训练和验证。常用的是VOC2007和VOC2012两个版本数据,共20个类别,分别是:
其目录结构如下:
JPEGImages存放图片文件
Annotations下存放的是xml文件,描述了图片信息(每个图片都对应一个xml文件)。如下图所示:
ImageSets包含以下4个文件夹:
全称是Microsoft Common Objects in Context
目前为止目标检测的最大数据集,提供的类别有80 类,有超过33 万张图片,其中20 万张有标注,整个数据集中个体的数目超过150 万个。
coco的标签文件:标记每个segmentation+bounding box的精确坐标
{“segmentation”:[[392.87, 275.77, 402.24, 284.2, 382.54, 342.36, 375.99, 356.43, 372.23, 357.37, 372.23, 397.7, 383.48, 419.27,407.87, 439.91, 427.57, 389.25, 447.26, 346.11, 447.26, 328.29, 468.84, 290.77,472.59, 266.38], [429.44,465.23, 453.83, 473.67, 636.73, 474.61, 636.73, 392.07, 571.07, 364.88, 546.69,363.0]], “area”: 28458.996150000003, “iscrowd”: 0,“image_id”: 503837, “bbox”: [372.23, 266.38, 264.5,208.23], “category_id”: 4, “id”: 151109},
IoU(intersection over union,交并比)是2个矩形框之间相似度:IoU = 两个矩形框相交的面积 / 两个矩形框相并的面积
如图:
实现方法:
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.0), int(box1[1] - box1[3]/2.0)
xmax1, ymax1 = int(box1[0] + box1[2]/2.0), int(box1[1] + box1[3]/2.0)
# 第二个框转换
xmin2, ymin2 = int(box2[0] - box2[2]/2.0), int(box2[1] + box2[3]/2.0)
xmax2, ymax2 = int(box2[0] + box2[2]/2.0), int(box2[1] + box2[3]/2.0)
# 相交框的左上角坐标和右下角,左上角取大,右下角取小
xx1 = np.max([xmin1, xmin2])
yy1 = np.max([ymin1, ymin2])
xx2 = np.min([xmax1, xmax2])
yy2 = np.min([ymax1, ymax2])
# 计算相交框面积
inter_area = (np.max([0, xx2 - xx1])) * (np.max([yy2 - yy1]))
# 计算并的面积 两个框面积-相交面积
area1 = (xmax1 - xmin1) * (ymax1 - ymin1)
area2 = (xmax2 - xmin2) * (ymax2 - ymin2)
uion_area = area1 + area2 - inter_area
return inter_area / (uion_area + 1e-6)
现在有一张狗的图片,对其设置真实框和预测框,并显示。
import matplotlib.pyplot as plt
import matplotlib.patches as patches
# 真实框与预测框
True_bbox, predict_bbox = [100, 35, 398, 400], [40, 150, 355, 398]
# bbox是bounding box的缩写
img = plt.imread('/tmp/pycharm_project_236/dog.jpeg')
fig = plt.imshow(img)
# 绘制真实框和预测框
fig.axes.add_patch(plt.Rectangle(
xy=(True_bbox[0], True_bbox[1]), width=True_bbox[2]-True_bbox[0], height=True_bbox[3]-True_bbox[1],
fill=False, edgecolor="blue", linewidth=2))
# 预测框绘制
fig.axes.add_patch(plt.Rectangle(
xy=(predict_bbox[0], predict_bbox[1]), width=predict_bbox[2]-predict_bbox[0], height=predict_bbox[3]-predict_bbox[1],
fill=False, edgecolor="red", linewidth=2))
调用方法计算IOU
IoU(True_bbox, predict_bbox)
上一节中IOU只是对定位进行评估,为了衡量定位+分类用AP
mAP是指多个分类任务的AP平均值,而AP是PR曲线下的面积。
TP FP FN TN的概念
查全率 查准率 (精确率 召回率)
AP与mAP具体计算过程:
初始情况如下:7张图片->15个GT框->24个预测框(A-Y并带有类别置信度)
定义:预测边框与 GT 的 IOU 值大于等于 0.3 就标记为 TP;若一个 GT 有多个预测边框,则认为 IOU 最大且大于等于 0.3 的预测框标记为 TP,其他的标记为 FP,即一个 GT 只能有一个预测框标记为 TP。第一步:对每张图像每个检测框与GT计算IOU,大于阈值为TP,否则为FP,结果如下图
第二步,根据类别置信度对预测框进行排序,再逐行计算查准率§和查全率®,如下图
Precision=TP/(ACC TP+ACC FP)=1/(1+0)=1
以及Recall=TP/(TP+FN)=TP/(
all ground truths)=1/15=0.0666
Precision=TP/(TP+FP)=1/(1+1)=0.5
以及 Recall=TP/(TP+FN)=TP/(
all ground truths)=1/15=0.0666
Precision=TP/(TP+FP)=2/(2+1)=0.6666
以及 Recall=TP/(TP+FN)=TP/(
all ground truths)=2/15=0.1333
第三步,绘制PR曲线,并计算AP(PR曲线下的面积),计算方式有两种,PR曲线绘制如下
目标检测任务中,如RCNN,有2000个预测框,如何得到正确预测的框呢?同时2000个框中也会存在多个框都能表达同一个GT,如何取舍呢?需要用到NMS来筛选出最终的最优结果。
如下图:
NMS原理:对于预测框的列表B及其对应的置信度S,选择具有最大score的检测框M,将其从B集合中移除并加入到最终的检测结果D中.通常将B中剩余检测框中与M的IoU大于阈值Nt的框从B中移除.重复这个过程,直到B为空。
NMS举例:
NMS代码:
import numpy as np
def nms(bboxes, confidence_score, threshold):
"""非极大抑制过程
:param bboxes: 同类别候选框坐标
:param confidence: 同类别候选框分数
:param threshold: iou阈值
:return:
"""
# 1、传入无候选框返回空
if len(bboxes) == 0:
return [], []
# 强转数组
bboxes = np.array(bboxes)
score = np.array(confidence_score)
# 取出n个的极坐标点
x1 = bboxes[:, 0]
y1 = bboxes[:, 1]
x2 = bboxes[:, 2]
y2 = bboxes[:, 3]
# 2、对候选框进行NMS筛选
# 返回的框坐标和分数
picked_boxes = []
picked_score = []
# 对置信度进行排序, 获取排序后的下标序号(argsort返回的下标), argsort默认从小到大排序
order = np.argsort(score)
areas = (x2 - x1) * (y2 - y1)
while order.size > 0:
# 将当前置信度最大的框加入返回值列表中
index = order[-1]
#保留该类剩余box中得分最高的一个
picked_boxes.append(bboxes[index])
picked_score.append(confidence_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]])
# 计算相交的面积,不重叠时面积为0
w = np.maximum(0.0, x22 - x11)
h = np.maximum(0.0, y22 - y11)
intersection = w * h
# 利用相交的面积和两个框自身的面积计算框的交并比
ratio = intersection / (areas[index] + areas[order[:-1]] - intersection)
# 保留IoU小于阈值的box
keep_boxes_indics = np.where(ratio < threshold)
# 保留剩余的框
order = order[keep_boxes_indics]
# 返回NMS后的框及分类结果
return picked_boxes, picked_score