最新要闻
- 特斯拉被曝动员中国供应商出海 去墨西哥复制“上海工厂”|每日报道
- 官方重要提醒!网易暴雪游戏退款申请即将截止
- 全球新资讯:一个游泳池里到底有多少尿?
- 世界热点评!一本书卖4.5万 日本研究员拆解比亚迪海豹视频流出:竟有些热血
- 全球微头条丨燃油绝唱! 第八代高尔夫终于改款:首次搭载大尺寸屏幕
- 天天热门:一字千年,方正字库的守正与创新
- 当前热文:青春的答卷
- 世界最新:当事博主否认被强制执行:特斯拉还想让平台封杀我 不是谁都给你面子
- 奶凶!沃尔沃史上最小SUV EX30发布!纯电续航480km 3.6秒破百
- 天天通讯!端午节假期火车票今日开售:调休放三天假 高速不免费
- 世界新动态:弯道强才是真的强!问界M5智驾版重庆山路实测:尽享丝滑
- 焦点快报!140W满功耗RTX 4060助力!618百亿补贴ROG魔霸7 Plus到手价仅8999元
- 天天时讯:郑外名师评卷·高考数学:反刷题、反套路,重视基础,稳中求新
- 龙湾开展“红色星期天”活动 让“一老一小”共享红色温暖 环球焦点
- 医保缴费多少年才可以终身享受待遇?多少钱一年?
- 欧盟将强制禁用华为5G设备 热点在线
手机
iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
- 警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- 男子被关545天申国赔:获赔18万多 驳回精神抚慰金
- 3天内26名本土感染者,辽宁确诊人数已超安徽
- 广西柳州一男子因纠纷杀害三人后自首
- 洱海坠机4名机组人员被批准为烈士 数千干部群众悼念
家电
深度学习应用篇-计算机视觉-目标检测[4]:综述、边界框bounding box、锚框(Anchor box)、交并比、非极大值抑制NMS、SoftNMS
深度学习应用篇-计算机视觉-目标检测[4]:综述、边界框bounding box、锚框(Anchor box)、交并比、非极大值抑制NMS、SoftNMS
1.目标检测综述
对计算机而言,能够“看到”的是图像被编码之后的数字,它很难理解高层语义概念,比如图像或者视频帧中出现的目标是人还是物体,更无法定位目标出现在图像中哪个区域。目标检测的主要目的是让计算机可以自动识别图片或者视频帧中所有目标的类别,并在该目标周围绘制边界框,标示出每个目标的位置,如 图1所示。
图1 图像分类和目标检测示意图
(资料图片)
- 图1(a)是图像分类任务,只需对这张图片进行类别识别。
- 图1(b)是目标检测任务,不仅要识别出这一张图片中的类别为斑马,还要标出图中斑马的位置。
1.1 应用场景
如 图2所示,如今的目标检测不论在日常生活中还是工业生产中都有着非常多的应用场景。
消费娱乐:智能手机的人脸解锁以及支付APP中的人脸支付;自动售货机使用的商品检测;视频网站中图片、视频审核等;
智慧交通:自动驾驶中的行人检测、车辆检测、红绿灯检测等;
工业生产:工业生产中的零件计数、缺陷检测;设备巡检场景下的设备状态监控;厂区中的烟火检测、安全帽检测等;
智慧医疗:眼底、肺部等器官病变检测;新冠疫情中的口罩检测等。
图2 目标检测应用场景
1.2 目标检测发展历程
在图像分类任务中,我们会先使用卷积神经网络提取图像特征,然后再用这些特征预测分类概率,根据训练样本标签建立起分类损失函数,开启端到端的训练,如 图3所示。
图3 图像分类流程示意图
但对于目标检测问题,按照 图3的流程则行不通。因为在对整张图提取特征的过程中无法体现出不同目标之间的区别,最终也就没法分别标示出每个物体所在的位置。
为了解决这个问题,结合图片分类任务取得的成功经验,我们可以将目标检测任务进行拆分。假设我们使用某种方式在输入图片上生成一系列可能包含物体的区域,这些区域称为候选区域。对于每个候选区域,可以单独当成一幅图像来看待,使用图像分类模型对候选区域进行分类,看它属于哪个类别或者背景(即不包含任何物体的类别)。上一节我们已经学过如何解决图像分类任务,使用卷积神经网络对一幅图像进行分类不再是一件困难的事情。
那么,现在问题的关键就是如何产生候选区域?比如我们可以使用穷举法来产生候选区域,如 图4所示。
图4 候选区域
A为图像上的某个像素点,B为A右下方另外一个像素点,A、B两点可以确定一个矩形框,记作AB。
- 如图4(a)所示:A在图片左上角位置,B遍历除A之外的所有位置,生成矩形框$A_1B_1, …, A_1B_n, …$
- 如图4(b)所示:A在图片中间某个位置,B遍历A右下方所有位置,生成矩形框$A_kB_1, …, A_kB_n, …$
当A遍历图像上所有像素点,B则遍历它右下方所有的像素点,最终生成的矩形框集合${A_iB_j}$将会包含图像上所有可以选择的区域。
只要我们对每个候选区域的分类足够的准确,则一定能找到跟实际物体足够接近的区域来。穷举法也许能得到正确的预测结果,但其计算量也是非常巨大的,其所生成的总候选区域数目约为$\frac{W^2 H^2}{4}$,假设$H=W=100$,总数将会达到$2.5 \times 10^{7}$个,如此多的候选区域使得这种方法几乎没有什么实用性。但是通过这种方式,我们可以看出,假设分类任务完成的足够完美,从理论上来讲检测任务也是可以解决的,亟待解决的问题是如何设计出合适的方法来产生候选区域。
科学家们开始思考,是否可以应用传统图像算法先产生候选区域,然后再用卷积神经网络对这些区域进行分类?
- 2013年,Ross Girshick等人于首次将CNN的方法应用在目标检测任务上,他们使用传统图像算法Selective Search产生候选区域,取得了极大的成功,这就是对目标检测领域影响深远的区域卷积神经网络(R-CNN[1])模型。
- 2015年,Ross Girshick对此方法进行了改进,提出了Fast R-CNN[2]模型。通过将不同区域的物体共用卷积层的计算,大大缩减了计算量,提高了处理速度,而且还引入了调整目标物体位置的回归方法,进一步提高了位置预测的准确性。
- 2015年,Shaoqing Ren等人提出了Faster R-CNN[3]模型,提出了RPN的方法来产生物体的候选区域,这一方法不再需要使用传统的图像处理算法来产生候选区域,进一步提升了处理速度。
- 2017年,Kaiming He等人提出了Mask R-CNN[4]模型,只需要在Faster R-CNN模型上添加比较少的计算量,就可以同时实现目标检测和物体实例分割两个任务。
以上都是基于R-CNN系列的著名模型,对目标检测方向的发展有着较大的影响力。此外,还有一些其他模型,比如SSD[5]、YOLO[6,7,8]、R-FCN[9]等也都是目标检测领域流行的模型结构。图5为目标检测综述文章[10]中的一幅图,梳理了近些年目标检测算法的发展流程。
图5 目标检测算法发展流程
其中,由于上文所述的R-CNN的系列算法将目标检测任务分成两个阶段,先在图像上产生候选区域,再对候选区域进行分类并预测目标物体位置,所以它们通常被叫做两阶段检测算法。而SSD和YOLO系列算法则是使用一个网络同时产生候选区域并预测出物体的类别和位置,所以它们通常被叫做单阶段检测算法。
上文中提到,穷举法来获取候选区域是不现实的。因此在后来的经典算法中,常用的一个思路是使用Anchor提取候选目标框,Anchor是预先设定好比例的一组候选框集合,在图片上进行滑动就可以获取候选区域了。
由于这类算法都是使用Anchor提取候选目标框。在特征图的每一个点上,对Anchor进行分类和回归。所以这些算法也统称为基于Anchor的算法。
但是这种基于Anchor的方法,在实际应用中存在一些问题:
- Anchor是人为手工设计的,那我们换个数据集,应该设置多少?设置多大?长宽比如何设置?
- Anchor这种密集框,数量多,训练时如何选择正负样本?
- Anchor设置也导致超参数较多,实际业务扩展中,相对来说,就有点麻烦。
由于上述缺点的存在,近些年研究者们还提出了另外一类效果优异的算法,这些算法不再使用anchor回归预测框,因此也称作Anchor-free的算法,例如:CornerNet[11]和CenterNet[12]等。图6为大家简单罗列了经典的Anchor-base和Anchor-free的算法。
图6 基于深度学习的目标检测算法发展流程
Anchor-base和Anchor-free的算法也各具优势,下表为大家简单对比了几类算法各自的优缺点。
Anchor-Based单阶段 | Anchor-Based两阶段 | Anchor-Free | |
---|---|---|---|
网络结构 | 简单 | 复杂 | 简单 |
精度 | 优 | 更优 | 较优 |
预测速度 | 快 | 稍慢 | 快 |
超参数 | 较多 | 多 | 相对少 |
扩展性 | 一般 | 一般 | 较好 |
1.3 常用数据集
在目标检测领域,常用的开源数据集主要包含以下4个:Pascal VOC[13]、COCO[14]、Object365[15]、OpenImages[16]。这些数据集的类别数、图片数、目标框的总数量各不相同,因此难易也各不相同。这里整理了4个数据集的具体情况,如下表所示。
数据集 | 类别数 | train图片数,box数 | val图片数,box数 | boxes/Image |
---|---|---|---|---|
Pascal VOC-2012 | 20 | 5717, 1.3万+ | 5823, 1.3万+ | 2.4 |
COCO | 80 | 118287, 4万+ | 5000,3.6万+ | 7.3 |
Object365 | 365 | 600k, 9623k | 38k, 479k | 16 |
OpenImages18 | 500 | 1643042, 86万+ | 100000,69.6万+ | 7.0 |
- Pascal VOC-2012:VOC数据集是 PASCAL VOC挑战赛使用的数据集,包含了20种常见类别的图片,是目标检测领域的经典学术数据集之一。
- COCO:COCO数据集是一个经典的大规模目标检测、分割、姿态估计数据集,图片数据主要从复杂的日常场景中截取,共80类。目前的学术论文经常会使用COCO数据集进行精度评测。
- Object365:旷世科技发布的大规模通用物体检测数据集,共365类。
- OpenImages18:谷歌发布的超大规模数据集,共500类。
- 参考文献
[1] Rich feature hierarchies for accurate object detection and semantic segmentation
[2] Fast R-CNN
[3] Faster R-CNN: Towards Real-Time Object Detection with Region Proposal Networks
[4] Mask R-CNN
[5] SSD: Single Shot MultiBox Detector
[6] You Only Look Once: Unified, Real-Time Object Detection
[7] YOLO9000: Better, Faster, Stronger
[8] YOLOv3: An Incremental Improvement
[9] R-FCN: Object Detection via Region-based Fully Convolutional Networks
[10] Object Detection in 20 Years: A Survey
[11] CornerNet: Detecting Objects as Paired Keypoints
[12] Objects as Points
[13] Pascal VOC
[14] COCO
[15] Object365
[16] OpenImages
2.边界框(bounding box)
在检测任务中,我们需要同时预测物体的类别和位置,因此需要引入一些跟位置相关的概念。通常使用边界框(bounding box,bbox)来表示物体的位置,边界框是正好能包含物体的矩形框,如 图1所示,图中3个人分别对应3个边界框。
图1 边界框
通常表示边界框的位置有两种方式:
- 即$(x_1, y_1, x_2, y_2)$,其中$(x_1, y_1)$是矩形框左上角的坐标,$(x_2, y_2)$是矩形框右下角的坐标。图1中3个红色矩形框用$xyxy$格式表示如下:
- 左:$(40.93, 141.1, 226.99, 515.73)$。
- 中:$(214.29, 325.03, 399.82, 631.37)$。
- 右:$(247.2, 131.62, 480.0, 639.32)$。
- $xywh$,即$(x, y, w, h)$,其中$(x, y)$是矩形框中心点的坐标,$w$是矩形框的宽度,$h$是矩形框的高度。
在检测任务中,训练数据集的标签里会给出目标物体真实边界框所对应的$(x_1, y_1, x_2, y_2)$,这样的边界框也被称为真实框(ground truth box),图1画出了3个人像所对应的真实框。模型会对目标物体可能出现的位置进行预测,由模型预测出的边界框则称为预测框(prediction box)。
要完成一项检测任务,我们通常希望模型能够根据输入的图片,输出一些预测的边界框,以及边界框中所包含的物体的类别或者说属于某个类别的概率,例如这种格式: $[L, P, x_1, y_1, x_2, y_2]$,其中$L$是预测出的类别标签,$P$是预测物体属于该类别的概率。一张输入图片可能会产生多个预测框,接下来让我们一起学习如何完成这项任务。
注意:
- 在阅读代码时,请注意使用的是哪一种格式的表示方式。
- 图片坐标的原点在左上角,$x$轴向右为正方向,$y$轴向下为正方向。
3.锚框(Anchor box)
目标检测算法通常会在输入图像中采样大量的区域,然后判断这些区域中是否包含我们感兴趣的目标,并调整区域边缘从而更准确地预测目标的真实边界框(ground-truth bounding box)。不同的模型使用的区域采样方法可能不同。这里我们介绍其中的一种方法:它以每个像素为中心生成多个大小和宽高比(aspect ratio)不同的边界框。这些边界框被称为锚框(anchor box)。
在目标检测任务中,我们会先设定好锚框的大小和形状,再以图像上某一个点为中心画出这些锚框,将这些锚框当成可能的候选区域。
目前,常用的锚框尺寸选择方法有:
- 人为经验选取
- k-means聚类
- 作为超参数进行学习
模型对这些候选区域是否包含物体进行预测,如果包含目标物体,则还需要进一步预测出物体所属的类别。还有更为重要的一点是,模型需要预测出微调的幅度。这是因为锚框位置是固定的,它不大可能刚好跟物体边界框重合,所以需要在锚框的基础上进行微调以形成能准确描述物体位置的预测框。
在训练过程中,模型通过学习不断的调整参数,最终能学会如何判别出锚框所代表的候选区域是否包含物体,如果包含物体的话,物体属于哪个类别,以及物体边界框相对于锚框位置需要调整的幅度。而不同的模型往往有着不同的生成锚框的方式。
在下图中,以像素点[300, 500]为中心可以使用下面的程序生成3个框,如 图2中蓝色框所示,其中锚框A1跟人像区域非常接近。
图2 锚框
#画图展示如何绘制边界框和锚框import numpy as npimport matplotlib.pyplot as pltimport matplotlib.patches as patchesfrom matplotlib.image import imreadimport math#定义画矩形框的程序 def draw_rectangle(currentAxis, bbox, edgecolor = "k", facecolor = "y", fill=False, linestyle="-"): # currentAxis,坐标轴,通过plt.gca()获取 # bbox,边界框,包含四个数值的list, [x1, y1, x2, y2] # edgecolor,边框线条颜色 # facecolor,填充颜色 # fill, 是否填充 # linestype,边框线型 # patches.Rectangle(xy, width, height,linewidth,edgecolor,facecolor,fill, linestyle) # xy:左下角坐标; width:矩形框的宽; height:矩形框的高; linewidth:线宽; edgecolor:边界颜色; facecolor:填充颜色; fill:是否填充; linestyle:线断类型 rect=patches.Rectangle((bbox[0], bbox[1]), bbox[2]-bbox[0]+1, bbox[3]-bbox[1]+1, linewidth=1, edgecolor=edgecolor,facecolor=facecolor,fill=fill, linestyle=linestyle) currentAxis.add_patch(rect) plt.figure(figsize=(10, 10))#传入图片路径filename = "/home/aistudio/work/images/section3/000000086956.jpg"im = imread(filename)plt.imshow(im)#使用xyxy格式表示物体真实框bbox1 = [214.29, 325.03, 399.82, 631.37]bbox2 = [40.93, 141.1, 226.99, 515.73]bbox3 = [247.2, 131.62, 480.0, 639.32]currentAxis=plt.gca()#绘制3个真实框draw_rectangle(currentAxis, bbox1, edgecolor="r")draw_rectangle(currentAxis, bbox2, edgecolor="r")draw_rectangle(currentAxis, bbox3,edgecolor="r")#绘制锚框def draw_anchor_box(center, length, scales, ratios, img_height, img_width): """ 以center为中心,产生一系列锚框 其中length指定了一个基准的长度 scales是包含多种尺寸比例的list ratios是包含多种长宽比的list img_height和img_width是图片的尺寸,生成的锚框范围不能超出图片尺寸之外 """ bboxes = [] for scale in scales: for ratio in ratios: h = length*scale*math.sqrt(ratio) w = length*scale/math.sqrt(ratio) x1 = max(center[0] - w/2., 0.) y1 = max(center[1] - h/2., 0.) x2 = min(center[0] + w/2. - 1.0, img_width - 1.0) y2 = min(center[1] + h/2. - 1.0, img_height - 1.0) print(center[0], center[1], w, h) bboxes.append([x1, y1, x2, y2]) for bbox in bboxes: draw_rectangle(currentAxis, bbox, edgecolor = "b")img_height = im.shape[0]img_width = im.shape[1] #绘制锚框draw_anchor_box([300., 500.], 100., [2.0], [0.5, 1.0, 2.0], img_height, img_width)################# 以下为添加上图中的文字说明和箭头###############################plt.text(285, 285, "G1", color="red", fontsize=20)plt.arrow(300, 288, 30, 40, color="red", width=0.001, length_includes_head=True, \ head_width=5, head_length=10, shape="full")plt.text(190, 320, "A1", color="blue", fontsize=20)plt.arrow(200, 320, 30, 40, color="blue", width=0.001, length_includes_head=True, \ head_width=5, head_length=10, shape="full")plt.text(160, 370, "A2", color="blue", fontsize=20)plt.arrow(170, 370, 30, 40, color="blue", width=0.001, length_includes_head=True, \ head_width=5, head_length=10, shape="full")plt.text(115, 420, "A3", color="blue", fontsize=20)plt.arrow(127, 420, 30, 40, color="blue", width=0.001, length_includes_head=True, \ head_width=5, head_length=10, shape="full")plt.show()
锚框的概念最早在Faster rcnn[1]目标检测算法中被提出,后来被YOLOv2[2]等各种目标检测算法借鉴。对比于早期目标检测算法中使用的滑动窗口或Selective Search方法,使用锚框来提取候选区域大大减少了时间开销。而对比YOLOv1[3]中直接回归坐标值来计算检测框,使用锚框可以简化目标检测问题,使得网络仅仅学习锚框的位置偏移量即可,从而使得网络模型更容易学习。
[1] Faster R-CNN: Towards Real-Time Object Detection with Region Proposal Networks
[2] YOLO9000: Better, Faster, Stronger
[3] You Only Look Once: Unified, Real-Time Object Detection
4.交并比
在目标检测任务中,通常会使用交并比(Intersection of Union,IoU)作为衡量指标,来衡量两个矩形框之间的关系。例如在基于锚框的目标检测算法中,我们知道当锚框中包含物体时,我们需要预测物体类别并微调锚框的坐标,从而获得最终的预测框。此时,判断锚框中是否包含物体就需要用到交并比,当锚框与真实框交并比足够大时,我们就可以认为锚框中包含了该物体;而锚框与真实框交并比很小时,我们就可以认为锚框中不包含该物体。此外,在后面NMS的计算过程中,同样也要使用交并比来判断不同矩形框是否重叠。
交并比这一概念来源于数学中的集合,用来描述两个集合$A$和$B$之间的关系,它等于两个集合的交集里面所包含的元素个数,除以它们的并集里面所包含的元素个数,具体计算公式如下:
$$IoU = \frac{A\cap B}{A \cup B}$$
我们将用这个概念来描述两个框之间的重合度。两个框可以看成是两个像素的集合,它们的交并比等于两个框重合部分的面积除以它们合并起来的面积。下图“交集”中青色区域是两个框的重合面积,下图“并集”中蓝色区域是两个框的相并面积。用这两个面积相除即可得到它们之间的交并比,如 图1所示。
图1 交并比
假设两个矩形框A和B的位置分别为:
$$A: [x_{a1}, y_{a1}, x_{a2}, y_{a2}]$$
$$B: [x_{b1}, y_{b1}, x_{b2}, y_{b2}]$$
假如位置关系如 图2所示:
图2 计算交并比
如果二者有相交部分,则相交部分左上角坐标为:
$$x_1 = max(x_{a1}, x_{b1}), \ \ \ \ \ y_1 = max(y_{a1}, y_{b1})$$
相交部分右下角坐标为:
$$x_2 = min(x_{a2}, x_{b2}), \ \ \ \ \ y_2 = min(y_{a2}, y_{b2})$$
计算先交部分面积:
$$intersection = max(x_2 - x_1 + 1.0, 0) \cdot max(y_2 - y_1 + 1.0, 0)$$
矩形框A和B的面积分别是:
$$S_A = (x_{a2} - x_{a1} + 1.0) \cdot (y_{a2} - y_{a1} + 1.0)$$
$$S_B = (x_{b2} - x_{b1} + 1.0) \cdot (y_{b2} - y_{b1} + 1.0)$$
计算相并部分面积:
$$union = S_A + S_B - intersection$$
计算交并比:
$$IoU = \frac{intersection}{union}$$
交并比实现代码如下:
- 当矩形框的坐标形式为xyxy时
import numpy as np#计算IoU,矩形框的坐标形式为xyxydef box_iou_xyxy(box1, box2): # 获取box1左上角和右下角的坐标 x1min, y1min, x1max, y1max = box1[0], box1[1], box1[2], box1[3] # 计算box1的面积 s1 = (y1max - y1min + 1.) * (x1max - x1min + 1.) # 获取box2左上角和右下角的坐标 x2min, y2min, x2max, y2max = box2[0], box2[1], box2[2], box2[3] # 计算box2的面积 s2 = (y2max - y2min + 1.) * (x2max - x2min + 1.) # 计算相交矩形框的坐标 xmin = np.maximum(x1min, x2min) ymin = np.maximum(y1min, y2min) xmax = np.minimum(x1max, x2max) ymax = np.minimum(y1max, y2max) # 计算相交矩形行的高度、宽度、面积 inter_h = np.maximum(ymax - ymin + 1., 0.) inter_w = np.maximum(xmax - xmin + 1., 0.) intersection = inter_h * inter_w # 计算相并面积 union = s1 + s2 - intersection # 计算交并比 iou = intersection / union return ioubbox1 = [100., 100., 200., 200.]bbox2 = [120., 120., 220., 220.]iou = box_iou_xyxy(bbox1, bbox2)print("IoU is {}".format(iou))
- 当矩形框的坐标形式为xywh时
import numpy as np#计算IoU,矩形框的坐标形式为xywhdef box_iou_xywh(box1, box2): x1min, y1min = box1[0] - box1[2]/2.0, box1[1] - box1[3]/2.0 x1max, y1max = box1[0] + box1[2]/2.0, box1[1] + box1[3]/2.0 s1 = box1[2] * box1[3] x2min, y2min = box2[0] - box2[2]/2.0, box2[1] - box2[3]/2.0 x2max, y2max = box2[0] + box2[2]/2.0, box2[1] + box2[3]/2.0 s2 = box2[2] * box2[3] xmin = np.maximum(x1min, x2min) ymin = np.maximum(y1min, y2min) xmax = np.minimum(x1max, x2max) ymax = np.minimum(y1max, y2max) inter_h = np.maximum(ymax - ymin, 0.) inter_w = np.maximum(xmax - xmin, 0.) intersection = inter_h * inter_w union = s1 + s2 - intersection iou = intersection / union return ioubbox1 = [100., 100., 200., 200.]bbox2 = [120., 120., 220., 220.]iou = box_iou_xywh(bbox1, bbox2)print("IoU is {}".format(iou))
为了直观的展示交并比的大小跟重合程度之间的关系,图3示意了不同交并比下两个框之间的相对位置关系,从 IoU = 0.95 到 IoU = 0。
图3 不同交并比下两个框之间相对位置示意图
问题:
什么情况下两个矩形框的IoU等于1?
答案:两个矩形框完全重合。
什么情况下两个矩形框的IoU等于0?
答案:两个矩形框完全不相交。
5.非极大值抑制NMS
在实际的目标检测过程中,不管是用什么方式获取候选区域,都会存在一个通用的问题,那就是网络对同一个目标可能会进行多次检测。这也就导致对于同一个物体,会产生多个预测框。因此需要消除重叠较大的冗余预测框。具体的处理方法就是非极大值抑制(NMS)。
假设使用模型对图片进行预测,一共输出了11个预测框及其得分,在图上画出预测框如 图1所示。在每个人像周围,都出现了多个预测框,需要消除冗余的预测框以得到最终的预测结果。
图1 预测框示意图
输出11个预测框及其得分的代码实现如下:
#画图展示目标物体边界框import numpy as npimport matplotlib.pyplot as pltimport matplotlib.patches as patchesfrom matplotlib.image import imreadimport math#定义画矩形框的程序 def draw_rectangle(currentAxis, bbox, edgecolor = "k", facecolor = "y", fill=False, linestyle="-"): # currentAxis,坐标轴,通过plt.gca()获取 # bbox,边界框,包含四个数值的list, [x1, y1, x2, y2] # edgecolor,边框线条颜色 # facecolor,填充颜色 # fill, 是否填充 # linestype,边框线型 # patches.Rectangle(xy, width, height,linewidth,edgecolor,facecolor,fill, linestyle) # xy:左下角坐标; width:矩形框的宽; height:矩形框的高; linewidth:线宽; edgecolor:边界颜色; facecolor:填充颜色; fill:是否填充; linestyle:线断类型 rect=patches.Rectangle((bbox[0], bbox[1]), bbox[2]-bbox[0]+1, bbox[3]-bbox[1]+1, linewidth=1, edgecolor=edgecolor,facecolor=facecolor,fill=fill, linestyle=linestyle) currentAxis.add_patch(rect) plt.figure(figsize=(10, 10))#传入图片路径filename = "/home/aistudio/work/images/section3/000000086956.jpg"im = imread(filename)plt.imshow(im)currentAxis=plt.gca()#预测框位置,由网络预测得到boxes = np.array([[4.21716537e+01, 1.28230896e+02, 2.26547668e+02, 6.00434631e+02], [3.18562988e+02, 1.23168472e+02, 4.79000000e+02, 6.05688416e+02], [2.62704697e+01, 1.39430557e+02, 2.20587097e+02, 6.38959656e+02], [4.24965363e+01, 1.42706665e+02, 2.25955185e+02, 6.35671204e+02], [2.37462646e+02, 1.35731537e+02, 4.79000000e+02, 6.31451294e+02], [3.19390472e+02, 1.29295090e+02, 4.79000000e+02, 6.33003845e+02], [3.28933838e+02, 1.22736115e+02, 4.79000000e+02, 6.39000000e+02], [4.44292603e+01, 1.70438187e+02, 2.26841858e+02, 6.39000000e+02], [2.17988785e+02, 3.02472412e+02, 4.06062927e+02, 6.29106628e+02], [2.00241089e+02, 3.23755096e+02, 3.96929321e+02, 6.36386108e+02], [2.14310303e+02, 3.23443665e+02, 4.06732849e+02, 6.35775269e+02]])#预测框得分,由网络预测得到scores = np.array([0.5247661 , 0.51759845, 0.86075854, 0.9910175 , 0.39170712, 0.9297706 , 0.5115228 , 0.270992 , 0.19087596, 0.64201415, 0.879036])#画出所有预测框for box in boxes: draw_rectangle(currentAxis, box)
这里使用非极大值抑制(Non-Maximum Suppression, NMS)来消除冗余框。基本思想是,如果有多个预测框都对应同一个物体,则只选出得分最高的那个预测框,剩下的预测框被丢弃掉。
如何判断两个预测框对应的是同一个物体呢,标准该怎么设置?
如果两个预测框的类别一样,而且他们的位置重合度比较大,则可以认为他们是在预测同一个目标。非极大值抑制的做法是,选出某个类别得分最高的预测框,然后看哪些预测框跟它的IoU大于阈值,就把这些预测框给丢弃掉。这里IoU的阈值是超参数,需要提前设置,这里我们参考YOLOv3算法,里面设置的是0.5。
比如在上面的程序中,boxes里面一共对应11个预测框,scores给出了它们预测"人"这一类别的得分,NMS的具体做法如下。
- Step0:创建选中列表,keep_list = []
- Step1:对得分进行排序,remain_list = [ 3, 5, 10, 2, 9, 0, 1, 6, 4, 7, 8],
- Step2:选出boxes[3],此时keep_list为空,不需要计算IoU,直接将其放入keep_list,keep_list = [3], remain_list=[5, 10, 2, 9, 0, 1, 6, 4, 7, 8]
- Step3:选出boxes[5],此时keep_list中已经存在boxes[3],计算出IoU(boxes[3], boxes[5]) = 0.0,显然小于阈值,则keep_list=[3, 5], remain_list = [10, 2, 9, 0, 1, 6, 4, 7, 8]
- Step4:选出boxes[10],此时keep_list=[3, 5],计算IoU(boxes[3], boxes[10])=0.0268,IoU(boxes[5], boxes[10])=0.0268 = 0.24,都小于阈值,则keep_list = [3, 5, 10],remain_list=[2, 9, 0, 1, 6, 4, 7, 8]
- Step5:选出boxes[2],此时keep_list = [3, 5, 10],计算IoU(boxes[3], boxes[2]) = 0.88,超过了阈值,直接将boxes[2]丢弃,keep_list=[3, 5, 10],remain_list=[9, 0, 1, 6, 4, 7, 8]
- Step6:选出boxes[9],此时keep_list = [3, 5, 10],计算IoU(boxes[3], boxes[9]) = 0.0577,IoU(boxes[5], boxes[9]) = 0.205,IoU(boxes[10], boxes[9]) = 0.88,超过了阈值,将boxes[9]丢弃掉。keep_list=[3, 5, 10],remain_list=[0, 1, 6, 4, 7, 8]
- Step7:重复上述Step6直到remain_list为空。
非极大值抑制的具体实现代码如下面的nms
函数的定义。
#非极大值抑制def nms(bboxes, scores, score_thresh, nms_thresh): """ nms """ inds = np.argsort(scores) inds = inds[::-1] keep_inds = [] while(len(inds) > 0): cur_ind = inds[0] cur_score = scores[cur_ind] # if score of the box is less than score_thresh, just drop it if cur_score < score_thresh: break keep = True for ind in keep_inds: current_box = bboxes[cur_ind] remain_box = bboxes[ind] iou = box_iou_xyxy(current_box, remain_box) if iou > nms_thresh: keep = False break if keep: keep_inds.append(cur_ind) inds = inds[1:] return np.array(keep_inds)
最终得到keep_list=[3, 5, 10],也就是预测框3、5、10被最终挑选出来了,如 图2所示。
图2 NMS结果示意图
整个过程的实现代码如下:
#画图展示目标物体边界框import numpy as npimport matplotlib.pyplot as pltimport matplotlib.patches as patchesfrom matplotlib.image import imreadimport math#定义画矩形框的程序 def draw_rectangle(currentAxis, bbox, edgecolor = "k", facecolor = "y", fill=False, linestyle="-"): # currentAxis,坐标轴,通过plt.gca()获取 # bbox,边界框,包含四个数值的list, [x1, y1, x2, y2] # edgecolor,边框线条颜色 # facecolor,填充颜色 # fill, 是否填充 # linestype,边框线型 # patches.Rectangle需要传入左上角坐标、矩形区域的宽度、高度等参数 rect=patches.Rectangle((bbox[0], bbox[1]), bbox[2]-bbox[0]+1, bbox[3]-bbox[1]+1, linewidth=1, edgecolor=edgecolor,facecolor=facecolor,fill=fill, linestyle=linestyle) currentAxis.add_patch(rect) plt.figure(figsize=(10, 10))filename = "/home/aistudio/work/images/section3/000000086956.jpg"im = imread(filename)plt.imshow(im)currentAxis=plt.gca()boxes = np.array([[4.21716537e+01, 1.28230896e+02, 2.26547668e+02, 6.00434631e+02], [3.18562988e+02, 1.23168472e+02, 4.79000000e+02, 6.05688416e+02], [2.62704697e+01, 1.39430557e+02, 2.20587097e+02, 6.38959656e+02], [4.24965363e+01, 1.42706665e+02, 2.25955185e+02, 6.35671204e+02], [2.37462646e+02, 1.35731537e+02, 4.79000000e+02, 6.31451294e+02], [3.19390472e+02, 1.29295090e+02, 4.79000000e+02, 6.33003845e+02], [3.28933838e+02, 1.22736115e+02, 4.79000000e+02, 6.39000000e+02], [4.44292603e+01, 1.70438187e+02, 2.26841858e+02, 6.39000000e+02], [2.17988785e+02, 3.02472412e+02, 4.06062927e+02, 6.29106628e+02], [2.00241089e+02, 3.23755096e+02, 3.96929321e+02, 6.36386108e+02], [2.14310303e+02, 3.23443665e+02, 4.06732849e+02, 6.35775269e+02]]) scores = np.array([0.5247661 , 0.51759845, 0.86075854, 0.9910175 , 0.39170712, 0.9297706 , 0.5115228 , 0.270992 , 0.19087596, 0.64201415, 0.879036])left_ind = np.where((boxes[:, 0]<60) * (boxes[:, 0]>20))left_boxes = boxes[left_ind]left_scores = scores[left_ind]colors = ["r", "g", "b", "k"]# 画出最终保留的预测框inds = nms(boxes, scores, score_thresh=0.01, nms_thresh=0.5)# 打印最终保留的预测框是哪几个print(inds)for i in range(len(inds)): box = boxes[inds[i]] draw_rectangle(currentAxis, box, edgecolor=colors[i])
需要说明的是当数据集中含有多个类别的物体时,需要做多分类非极大值抑制,其实现原理与非极大值抑制相同,区别在于需要对每个类别都做非极大值抑制,实现代码如下面的multiclass_nms
所示。
#多分类非极大值抑制def multiclass_nms(bboxes, scores, score_thresh=0.01, nms_thresh=0.45, pre_nms_topk=1000, pos_nms_topk=100): """ This is for multiclass_nms """ batch_size = bboxes.shape[0] class_num = scores.shape[1] rets = [] for i in range(batch_size): bboxes_i = bboxes[i] scores_i = scores[i] ret = [] # 对每个类别都进行NMS操作 for c in range(class_num): scores_i_c = scores_i[c] keep_inds = nms(bboxes_i, scores_i_c, score_thresh, nms_thresh) if len(keep_inds) < 1: continue keep_bboxes = bboxes_i[keep_inds] keep_scores = scores_i_c[keep_inds] keep_results = np.zeros([keep_scores.shape[0], 6]) keep_results[:, 0] = c keep_results[:, 1] = keep_scores[:] keep_results[:, 2:6] = keep_bboxes[:, :] ret.append(keep_results) if len(ret) < 1: rets.append(ret) continue ret_i = np.concatenate(ret, axis=0) scores_i = ret_i[:, 1] if len(scores_i) > pos_nms_topk: inds = np.argsort(scores_i)[::-1] inds = inds[:pos_nms_topk] ret_i = ret_i[inds] rets.append(ret_i) return rets
6.Soft NMS
6.1Soft NMS 提出背景
NMS(非极大值抑制)方法是目标检测任务中常用的后处理方法,其基本思想是:如果有多个预测框都对应同一个物体,则只选出得分最高的那个预测框,剩下的预测框被丢弃掉。在这种方法的处理下,可以有效地减少冗余的检测框。但是,传统的 NMS 算法会存在以下缺点:IOU阈值难以确定,阈值太小,则容易发生漏检现象,当两个相同类别的物体重叠非常多的时候,类别得分较低的物体则会被舍弃;阈值太大,则难以消除大部分冗余框。
因此,在《Improving Object Detection With One Line of Code》[1]论文中,作者提出了 Soft NMS 方法来有效减轻上述问题。
6.2 Soft NMS 算法流程
假设当前得分最高的检测框为$M$,对于另一个类别得分为 $s_i$ 的检测框 $b_i$,传统的 NMS 算法的计算方式可以表示为下式:
$$s_i = {\begin{matrix}s_i,iou(M,b_i) 而 Soft NMS 算法的计算方式可以表示为下式: $$s_i = {\begin{matrix}s_i,iou(M,b_i) 但是,如果使用上述公式进行 Soft NMS 的计算,当IOU大于阈值时,边框得分会发生一个较大的变化。此时,检测结果有可能会也就会因此受到较大的影响。因此, Soft NMS 算法中,还提出了另一种边框得分的计算方式,如下式所示。$$s_i = s_ie^{-\frac {{iou(M,b_i)^2}}{\sigma}},\forall b_i\notin D$$此时,新的边界框得分变化较小,在后续的计算过程中也就又有了被计算为正确检测框的机会。 这里使用一个简单示例来说明 Soft NMS 算法的计算过程以及其与标准NMS算法的差异。 图1 SoftNMS算法示例 假设使用马匹检测模型对上述图像进行预测,得到如上的两个检测结果。其中红色检测框中的马匹类别得分为0.95,绿色虚线检测框中的马匹类别得分为0.8。可以看到,距离镜头更近的马匹几乎将距离镜头远的马匹完全遮挡住了,此时,两个检测框的IOU是非常大的。 在传统NMS算法中,对于这种检测框的IOU非常大,超过预先设定的阈值的情况,会仅仅保留得分最大的检测框,将得分较小的检测框的得分直接置0。此时,绿色虚线框中的马匹也就直接被舍弃掉了。但是,这两个检测框本身分别对应了两个不同的马匹,因此,这种NMS的方法会造成漏检的现象。 而在SoftNMS算法中,绿色虚线的检测框对应的新得分则不会被置0,而是使用上文中提到的两种计算方式进行计算。此时,绿色虚线框中的马匹不会直接被舍弃掉,而是降低了类别得分,继续参与后续计算。对应原图中的情况,两个马匹则有很大的概率在最后同时被保留,避免了漏检现象的发生。 更多文章请关注公重号:汀丶人工智能 [1] 《Improving Object Detection With One Line of Code》
关键词:
深度学习应用篇-计算机视觉-目标检测[4]:综述、边界框boundingbox、锚6.3 Soft NMS 算法示例
深度学习应用篇-计算机视觉-目标检测[4]:综述、边界框bounding box、锚框(Anchor box)、交并比、非极大值抑制NMS、SoftNMS
深度学习应用篇-计算机视觉-目标检测[4]:综述、边界框bounding box、锚框(Anchor box)、交并比、非极大值抑制NMS、SoftNMS
Openjob:更强大、更智能的新一代分布式任务调度框架|世界热推荐
特斯拉被曝动员中国供应商出海 去墨西哥复制“上海工厂”|每日报道
官方重要提醒!网易暴雪游戏退款申请即将截止
全球新资讯:一个游泳池里到底有多少尿?
世界热点评!一本书卖4.5万 日本研究员拆解比亚迪海豹视频流出:竟有些热血
全球微头条丨燃油绝唱! 第八代高尔夫终于改款:首次搭载大尺寸屏幕
天天热门:一字千年,方正字库的守正与创新
MySQL索引的数据结构 环球快资讯
焦点!原生AJAX案例浏览器报错:Cross origin requests are only supported for protocol
全球头条:springboot~jgroups实现节点间的通讯
轻松实现物联网通信的利器:MQTT网关神器——FluxMQ 当前视点
win10配置Electron安装环境以及解决报错-消息
当前热文:青春的答卷
世界最新:当事博主否认被强制执行:特斯拉还想让平台封杀我 不是谁都给你面子
奶凶!沃尔沃史上最小SUV EX30发布!纯电续航480km 3.6秒破百
天天通讯!端午节假期火车票今日开售:调休放三天假 高速不免费
世界新动态:弯道强才是真的强!问界M5智驾版重庆山路实测:尽享丝滑
焦点快报!140W满功耗RTX 4060助力!618百亿补贴ROG魔霸7 Plus到手价仅8999元
天天时讯:郑外名师评卷·高考数学:反刷题、反套路,重视基础,稳中求新
龙湾开展“红色星期天”活动 让“一老一小”共享红色温暖 环球焦点
世界微头条丨太卷了,史上最简单的监控系统 catpaw 简介
小车PID巡线调节 全球报资讯
易基因|一种全新的检测DNA羟甲基化的技术:ACE-Seq 环球时快讯
JPA单表存储List与模糊查询
医保缴费多少年才可以终身享受待遇?多少钱一年?
欧盟将强制禁用华为5G设备 热点在线
性价比口碑双冠王!魅族20 PRO成618四千档性能神机 天天热资讯
雾霾笼罩纽约 自由女神像被“吞没” :美国大片地区昏黄烟雾 宛如末日降临-世界热头条
世界头条:高考时没有一个孔子是饿着的:学子争相给先贤送吃的 期盼金榜题名
女子开门杀致骑手摔倒被罐车卷入车底:第一反应竟是观察车门|天天速递
Adata 展示其 1600W PSU 可以为四个 450W RTX 4090 供电
java~如何使用无符号整型 看热讯
文字效果 用背景渐变实现 波浪背景文字
P1585 魔法阵 题解
关注2023年河南高考丨免费午餐温暖高考学子
西安李姐茶叶蛋的家常做法?
有人在麦田插钢筋损坏收割机:钢筋还特意用麦子包裹 天天报道
帅不过3秒!RTX 4060游戏本挑战全景光追惨败 天天实时
黑龙江黑河村庄遭龙卷风袭击:多处房屋损毁|焦点关注
安卓阵营早已实现:iOS 17相机终于引入“水平”辅助线_天天报资讯
天天看点:买显卡“送”橘猫!COLORFIRE RTX 4060 Ti橘影橙8GB 评测:比公版强2%
当前时讯:文档在线预览(四)将word、txt、ppt、excel、图片转成pdf来实现在线预览
热讯:工会代表候选人初步人选推荐情况的报告_人选和候选人的区别是什么
组图|2023年海南陵水黎安国际教育创新试验区知识产权沙龙活动举行
多家饭店因在凉皮内放黄瓜丝被罚 网友吵翻:专家科普为大家好
第27次参加!高考钉子户梁实愁眉苦脸出考场 直言考得不好_世界今日报
天天实时:Epic祝福高考学子被指配图不佳 随后换成《原神》截图
天天信息:灵商的组成中包括(灵商)
吉视传媒:公司目前没有发展和推动有esim卡业务 今日精选
全球短讯!青海省邮政管理局联合相关部门调研“客货邮”融合发展情况
世界即时看!福达合金:截至本公告披露日 公司及其控股子公司担保余额为人民币约7.86亿元
职业发展战术设计:构建可持续积累的职业优势 每日关注
微控制器实时操作系统实践3任务信令和通信机制
癫痫一年发作一次严重吗
什么海鱼内脏比较好吃?
魔域私服有合宝宝挂吗_457833415@ com 求个 有的给个 谢谢啦|今日视点
全球滚动:卡霍夫卡水电站大坝遭袭 扎波罗热地方官员:核电站情况稳定
万亿美元发债潮将至 美国金融体系或酝酿流动性风险 环球新动态
新兴产业加速崛起 海洋经济破浪前行
江苏黄沙港特大桥顺利合龙 预计6月底完工
高温范围扩大 这些地区的高考考生和家长需注意_当前资讯
雷雨大风+冰雹+龙卷!黑龙江省发布龙卷预警 焦点短讯
临川区气象台发布雷电黄色预警信号【III级/较重】【2023-06-07】 每日速讯
世界看热讯:不回巴萨!曝梅西已决定加盟美国球队迈阿密国际
Mac游戏看齐Win系统 苹果新工具可快速移植游戏
2023高考来临 大学生考点摆摊卖9.85与21.1元花束:给学弟学妹加油
暗黑满级号死于掉线
梅西官宣加盟迈阿密国际 老板是贝克汉姆:5000万欧年薪+苹果分成等
【独家焦点】长城电工:6月7日融资买入130.37万元,融资融券余额8601.6万元
按照评价的不同目的可将课程评价分为-要闻
资讯推荐:金发科技:公司目前材料可应用于航天、军工领域,但暂无相关订单
手机版生存游戏推荐 自己采集物资生存
全球快资讯:读改变未来的九大算法笔记06_图形识别
麻江县气象台发布雷电黄色预警信号【Ⅲ/较重】【2023-06-07】
优博讯:公司目前生物识别技术主要为人脸识别 每日简讯
pdca管理体系是什么_pdca管理是什么意思
信濠光电:公司的3D玻璃产品销量保持快速增长,但目前收入占比相对不高-时快讯
世界热推荐:《蜘蛛侠:纵横宇宙》口碑登顶 用AI绘制自己的格温女友
最新预警!雷雨大风!|环球焦点
观焦点:中国奇谭、宝可梦、姆明……上海电视节线下放映排片来了,你最想看哪一部?
新中港06月07日主力资金大幅流出 当前热门
今日关注:B站刚崩,唯品会又崩:亿级用户网站的架构硬伤与解决方案
使用THREEJS实现一个可调节档位、可摇头的电风扇 世界短讯
【环球速看料】西力科技:中标1.26亿元国家电网电能表采购项目
焦点信息:中国的油车时代过去了!大众关闭在中国建的第一座工厂
只用45分钟!女驴友被秃鹫吃得只剩一副白骨
近6成应届生没工作 企业招聘要求扎心:名校出身仅排第5 更高学历根本不重要
天天微速讯:7大AI比拼高考作文 语文老师打分:一大批学生该恐慌了
腾讯《无畏契约》国服今日终测:服务器全天开放、20名英雄爽玩
小摩:予招商银行(03968)“增持”评级 目标价70港元
南开区市场监管局强化高考、中考期间食品安全监管保障工作
环球快看:广丰区气象台更新雷电黄色预警信号【III级/较重】【2023-06-08】
氧化铝6月19日期货挂牌交易 后市铝价走向如何?
聚焦:雷阵雨+8级阵风,将影响晚高峰!天津发布雷雨大风蓝色预警
每日视讯:天津向渤海湾增殖放流各种苗种超100万尾
宇宙最多的两个元素是氢和什么_宇宙最多的两个元素是什么
解析2023年高考北京数学卷:追根溯源考“四基” 创新情境查能力_环球要闻
2023年6月7日河南省铝矿石价格最新行情预测
每日热讯!佳木斯领导调研地面站项目