目标检测
物体检测和数据集
边缘框
一个边缘框可以,通过4个数字定义。一个边缘可以通过四个数字定义。
- 左上角和右下角的点,每个点需要x和y坐标
- 左上角的x和y,然后记录宽高
- 还有中间点与高宽
物体识别的数据集通常比图像识别的数据集要小很多。
目标检测数据集中每一行表示一个物体,其中包括了图片文件名,物体类别,边缘框
COCO数据集:80个物体33w张图片,150万物体
import torch
from d2l import torch as d2l
d2l.set_figsize()
img = d2l.plt.imread("../img/catdog.png")
d2l.plt.imshow(img)
d2l.plt.show()
# 定义俩中表示之间转换的函数 从,左上角右下转到中间,宽度,高度
def box_corner_to_center(boxes):
# boxes[:, 0]选取所有行的第0列元素
x1, y1, x2, y2 = boxes[:, 0], boxes[:, 1], boxes[:, 2], boxes[:, 3]
cx = (x1 + x2) / 2
cy = (y1 + y2) / 2
w = x2 - x1
h = y2 - y1
# stack是在固定维度进行累计
boxes = torch.stack((cx, cy, w, h), axis=1)
return boxes
def box_center_to_corner(boxes):
"""从(中间,宽度,高度)转换到(左上,右下)"""
cx, cy, w, h = boxes[:, 0], boxes[:, 1], boxes[:, 2], boxes[:, 3]
x1 = cx - 0.5 * w
y1 = cy - 0.5 * h
x2 = cx + 0.5 * w
y2 = cy + 0.5 * h
boxes = torch.stack((x1, y1, x2, y2), axis=-1)
return boxes
# 框出来
def bbox_to_rect(bbox, color):
# 将边界框(左上x,左上y,右下x,右下y)格式转换成matplotlib格式:
# ((左上x,左上y),宽,高)
return d2l.plt.Rectangle(
xy=(bbox[0], bbox[1]), width=bbox[2]-bbox[0], height=bbox[3]-bbox[1],
fill=False, edgecolor=color, linewidth=2)
dog_bbox, cat_bbox = [60.0, 45.0, 378.0, 516.0], [400.0, 112.0, 655.0, 493.0]
# 可以通过俩次转换函数的准确性
boxes = torch.tensor((dog_bbox, cat_bbox))
print(box_center_to_corner(box_corner_to_center(boxes)) == boxes)
fig = d2l.plt.imshow(img)
fig.axes.add_patch(bbox_to_rect(dog_bbox, "blue"))
fig.axes.add_patch(bbox_to_rect(cat_bbox, "red"))
d2l.plt.show()
锚框
目标检测算法通常会在输入图像中采样大量的区域,然后判断这些区域中是否包含我们感兴趣的目标,并调整区域边界从而更准确地预测目标的真实边界框(ground-truth bounding box)。其中一个方法。
以每个像素为中心生成多个缩放和宽高比不同的边界。这些边界被称为锚框。(简单理解为猜测的边框)
- 提出多个被称为锚框的区域(边缘框)
- 预测每个锚框里是否含有关注物体
- 他如果是,预测从这个锚框到真实边缘的距离
IOU交并比
IOU用来计算俩个框之间的相似度,0表示无重叠,1表示重叠
其实就是交集除以并集,它也被经常用来算集合的相似度
$$ J(A,B)=\frac{|A\cap B|}{|A\cup B|} $$
赋予锚框标号
- 每个锚框是一个训练样本
- 将每个锚框,要么标注成背景,要么关联上一个真实边缘框
- 我们可能会生成大量的锚框,这可能导致大量负嘞的样本
上图假设有四个物体需要标注。每个物体有四。每个锚框和边缘算IOU值
9个框对应四个,4个物体的各自情况。消去这一行,它的几何意义其实就是我已经找到了我当前边框最大IOU的值,所就消去。删除这一列表示找到了目标边框的最大IOU值。
锚框一般是固定生成的或者根据图片生成的,1张图片如果有9个锚框就会生成9个训练样本
NMS
非极大抑制输出
- 每个锚框都需要预测一个边缘框
- 去掉所有其他和它IOU值大于$\theta$的预测
- 重复上述过程,直到所有预测要么被选中,要么被删掉
当有许多锚框时,可能会输出许多相似的具有明显重叠的预测边界框,都围绕着同一目标。 为了简化输出,我们可以使用非极大值抑制(non-maximum suppression,NMS)合并属于同一目标的类似的预测边界框。
以下是非极大值抑制的工作原理。 对于一个预测边界框B,目标检测模型会计算每个类别的预测概率。 假设最大的预测概率为p,则该概率所对应的类别B即为预测的类别。 具体来说,我们将p称为预测边界框B的置信度(confidence)。 在同一张图像中,所有预测的非背景边界框都按置信度降序排序,以生成列表L。然后我们通过以下步骤操作排序列表L。
- 从L中选取置信度最高的预测边界框B1作为基准,然后将所有与B1的IoU超过预定阈值ϵ的非基准预测边界框从L中移除。这时,L保留了置信度最高的预测边界框,去除了与其太过相似的其他预测边界框。简而言之,那些具有非极大值置信度的边界框被抑制了。
- 从L中选取置信度第二高的预测边界框B2作为又一个基准,然后将所有与B2的IoU大于ϵ的非基准预测边界框从L中移除。
- 重复上述过程,直到L中的所有预测边界框都曾被用作基准。此时,L中任意一对预测边界框的IoU都小于阈值ϵ;因此,没有一对边界框过于相似。
- 输出列表L中的所有预测边界框。
以下nms
函数按降序对置信度进行排序并返回其索引。
要生成多个不同形状的锚框,我们设置许多缩放比scale取值$s_n$和许多宽高比asect ratio$r_m$
当使用这些比例和宽比的所有组合以每个像素为中心时,输入图像将总共有whnm个锚框。尽管这些锚框可能会覆盖所有真实边界框,但计算复杂性很容易过高。 在实践中,我们只考虑包含s1或r1的组合
如果一个锚框没有被分配真实边界框,我们只需将锚框的类别标记为背景(background)。 背景类别的锚框通常被称为负类锚框,其余的被称为正类锚框。
总流程
- 一类目标检测算法基于锚框来预测
- 首先生成大量锚框,并赋予标号,每个锚框作为一个样本进行训练
- 在预测时,使用NMS来去掉冗余的预测
物体检测算法
R-CNN
基于区域的CNN
- 使用其发生搜索算法来选择锚框
- 使用预训练模型来对每个锚框抽取特征
- 训练一个SVM来对类别进行分类
- 训练一个线性回归模型来预测边缘框偏移。
兴趣区域(ROI)池化层
给定一个锚框,均匀分割成nxm块,输出每块的最大值
不管锚框多大,总是输出nm个值
可以让每个锚框变成自己想要的形状。
在传统的卷积神经网络(CNN)中,输入图像通常是固定大小的,这样可以保证输出的特征图也是固定大小的。然而,在目标检测任务中,候选区域(即 ROI)的大小和比例各不相同,这就导致了从这些不同大小的区域中提取的特征图大小也会有所不同。
fast RCNN
使用CNN对图片抽取特征,如果要对每个锚框抽取特征,那么代价太大了。
fastRCNN的思想是对每张图抽特征,抽取完毕后在做锚框。
先做CNN然后在做完CNN的图像上抽取锚框,然后再用ROI池化层对每个锚框抽取特征。比如一个锚框变成了2x2的像素,那么抽取之后,如果有100个锚框那就是2x2x100x通道数=400x通道数的数量。然后将他们直接送到全连接神经网络中。
思想是不对每个锚框做cnn抽取特征,而是一次性抽取完毕。再添加锚框做预测。
faster R-CNN
使用一个区域提议网络来替代启发式搜索来获得更好的性能。
它在生成锚框之后会进行一个二分类问题,预测这个锚框是否框主了物体。是一个多阶段网络。
fasterRCNN主要应用在对于精度特别关心的时候。
mask R-CNN
如果有像素级别的标号,使用FCN来利用这些信息。
单发多框检测SSD
Single Shot multibox Detector
- 一个基础网络来抽取特征,然后多个卷积层另开减半高宽
- 每个阶段都生成锚框,底部来你和小物体,顶部段来拟合大物体
- 对每个锚框预测类别和边缘框
简单来说就是通过单神经网络来检测模型,以每个像素为中心产生多个锚框,在多个输出段进行预测。
主题思路:
- 生成一对锚框
- 根据真实标签为每个锚框打标(类别偏移mask)
- 模型为每个锚框做一个预测(类别偏移)
- 计算上述俩者的差异损失。
YOLO
全称为You Only Look Once,你只能看一次
SSD中锚框大量重叠,因此浪费了很多计算
YOLO将图片均匀分成SxS个锚框
每个锚框预测B个边缘
后续V2,V3,V4版本有持续改进