cv程序员必备 随时更新哦

目录

目标检测两阶段和一阶段的核心区别
目标检测两阶段比一阶段的算法精度高的原因
如何解决目标检测中密集遮挡问题
“狭长形状”目标检测有什么合适方法
如何解决动态目标检测FPN的作用
为什么FPN采用融合以后效果要比使用pyramidal feature hierarchy这种方式要好?
FPN在RPN中的应用如何解决小目标识别问题
介绍目标检测RCNN系列和Yolo系列的区别
YOLO和SSD区别
前景背景样本不均衡解决方案:Focal Loss,GHM与PISA
如何解决训练数据样本过少的问题
如何解决类别不平衡的问题
手撕代码IOU
手撕代码NMS
NMS的改进思路
IOU相关优化(giou,diou,ciou)

目标检测两阶段和一阶段的核心区别

目标检测技术从阶段上分为两种,一阶段和二阶段。二阶段的核心思想是首先提出proposal框,通过第一阶段的网络回归出目标框的大概位置、大小及是前景的概率,第二阶段是通过另一个网络回归出目标框的位置、大小及类别;而一阶段网络的核心是,对于输入图像,通过网络直接回归出目标大小、位置和类别。

目标检测两阶段比一阶段的算法精度高的原因

1.正负样本的不均衡性

当某一类别的样本数特别多的时候,训练出来的网络对该类的检测精度往往会比较高。而当某一类的训练样本数较少的时候,模型对该类目标的检测精度就会有所下降,这就是所谓样本的不均衡性导致的检测精度的差异。

对于一阶段的目标检测来说,它既要做定位又要做分类,最后几层中1×1的卷积层的loss都混合在一起,没有明确的分工哪部分专门做分类,哪部分专门做预测框的回归,这样的话对于每个参数来说,学习的难度就增加了。

对于二阶段的目标检测来说(Faster RCNN),在RPN网络结构中进行了前景和背景的分类和检测,这个过程与一阶段的目标检测直接一上来就进行分类和检测要简单的很多,有了前景和背景的区分,就可以选择性的挑选样本,是的正负样本变得更加的均衡,然后重点对一些参数进行分类训练。训练的分类难度会比一阶段目标检测直接做混合分类和预测框回归要来的简单很多。

2.样本的不一致性

怎么理解样本不一致性呢?首先我们都知道在RPN获得多个anchors的时候,会使用一个NMS。在进行回归操作的时候,预测框和gt的IoU同回归后预测框和gt的IOU相比,一般会有较大的变化,但是NMS使用的时候用的是回归前的置信度,这样就会导致一些回归后高IoU的预测框被删除。这就使得回归前的置信度并不能完全表征回归后的IoU大小。这样子也会导致算法精度的下降。在第一次使用NMS时候这种情况会比较明显,第二次使用的时候就会好很多,因此一阶段只使用一次NMS是会对精度有影响的,而二阶段目标检测中会在RPN之后进行一个更为精细的回归,在该处也会用到NMS,此时检测的精度就会好很多。

如何解决目标检测中密集遮挡问题

遮挡本身也可以分为两种类型,一种是由于非目标造成的遮挡,一种是由于也是需要检测的目标造成的遮挡。这两种遮挡分别被叫做occlusion和crowded。

对于前一种类型遮挡,很难有针对性的办法去解决,最好的办法也就是使用更多的数据和更强的feature。可以从训练数据入手。加掩膜,加扰动,提高算法对遮挡的应对能力。

对于第二种遮挡,提出了两个针对这个问题的loss,

通过设置损失函数的方式,即Repulsion Loss,使预测框和所负责的真实目标框的距离缩小,而使得其与周围非负责目标框(包含真实目标框和预测框)的距离加大 。如下式,如果与周围目标的距离越大,损失值会越小。

opencv面试宝典1_目标检测

除了常用的smooth L1使回归目标与GT接近之外,这两个loss一个的目标是使proposal和要尽量远离和它overlap的第二大的GT,另一个目标是要上被assign到不同GT的proposal之间尽量远离。通过这两个loss,不仅仅使得proposal可以向正确的目标靠近,也可以使其远离错误的目标,从而减少NMS时候的误检。

opencv面试宝典1_人工智能_02

opencv面试宝典1_目标检测_03

“狭长形状”目标检测有什么合适方法

使用可旋转bonding box进行标注

手工设计anchors

如何解决动态目标检测

1.光流法

光流是空间运动物体被观测面上的像素点运动产生的瞬时速度场,包含了物体表面结构和动态行为的重要信息。光流计算法大致可分为三类:

(1)基于匹配的光流计算方法,包括基于特征和基于区域的两种。基于特征的方法是不断地对目标主要特征进行定位和跟踪,对大目标的运动和亮度变化具有鲁棒性,存在的问题是光流通常很稀疏,而且特征提取和精确匹配也十分困难;基于区域的方法先对类似的区域进行定位,然后通过相似区域的位移计算光流,这种方法在视频编码中得到了广泛的应用,但它计算的光流仍不稠密。

(2)基于频域的方法利用速度可调的滤波组输出频率或相位信息,虽然能获得很高精度的初始光流估计,但往往涉及复杂的计算,而且可靠性评价也十分困难。

(3)基于梯度的方法利用图像序列的时空微分计算2D速度场(光流)。由于计算简单和较好的实验结果,基于梯度的方法得到了广泛应用。

2.相邻帧差法

相邻帧差法是在运动目标检测中使用的最多的一类算法。原理就是将前后两帧图像对应的像素值相减,在环境亮度变化不大的情况下,如果对应像素值相差值很小,可认为此处景物是静止的,反之,则是运动物体。

相邻帧差法对于动态环境具有较强的自适应性,鲁棒性较好,能够适应各种动态环境,但一般不能完全提取出所有相关的特征像素点,这样在运动实体内部容易产生空洞现象。

3.背景差法

背景差法是常用的运动目标检测方法之一。它的基本思想是将输入图像与背景模型进行比较,通过判定灰度等特征的变化,或用直方图等统计信息的变化来判断异常情况的发生和分割运动目标。

与帧间差法比较,背景差法可以检测视频中停止运动的物体,其缺点是背景的更新导致算法的复杂性增加,实时性变差。

opencv面试宝典1_数据集_04

4. 基于事件相机来做

事件相机是具有微秒反应时间的仿生传感器,可记录每像素亮度变化的异步流,称为“事件”。事件相机通过检测每个像素的亮度变化来生成一个事件,相比于传统相机,更适合在高动态和高速度的环境下使用,具有高动态范围 (HDR)、高时间分辨率和无运动模糊的优势。

  1. 高动态范围:对于传统相机来说,在黑暗的情况下,传统的相机几乎没有办法使用,但对于事件相机来说,只检测正在运动的物体,所以无论是黑暗情况还是有光亮的情况,事件相机都可以发挥作用。
  2. 低延时:相邻事件之间的时间可以小于1毫秒
  3. 无运动模糊:即使是高速运动的物体,事件相机也可以捕获到
FPN的作用

FPN是在卷积神经网络中图像金字塔的应用。图像金字塔在多尺度识别中有重要的作用,尤其是小目标检测。顶层特征上采样后和底层特征融合,每层独立预测。

fpn设计动机:

1.高层特征向低层特征融合,增加低层特征表达能力,提升性能

2.不同尺度的目标可以分配到不同层预测,达到分而治之。

opencv面试宝典1_人工智能_05

FPN每层做特征融合的特征图有两个,首先是前向传播,然后取了每个特征图做上采样(最近邻插值),对应前向传播的特征图做融合。融合的方式是:通过1x1卷积调整通道数,然后直接add。之后进行3x3卷积操作,目的是消除上采样的混叠效应。

其实,fpn真正起作用的是分而治之的策略,特征融合的作用其实很有限,此外fpn存在消耗大量显存,降低推理速度。

为什么FPN采用融合以后效果要比使用pyramidal feature hierarchy这种方式要好?

 

opencv面试宝典1_数据_06

卷积虽然能够高效地向上提取语义,但是也存在像素错位问题,通过上采样还原特征图很好地缓解了像素不准的问题。

backbone可以分为浅层网络和深层网络,浅层网络负责提取目标边缘等底层特征,而深层网络可以构建高级的语义信息,通过使用FPN这种方式,让深层网络更高级语义的部分的信息能够融合到稍浅层的网络,指导浅层网络进行识别。

从感受野的角度思考,浅层特征的感受野比较小,深层网络的感受野比较大,浅层网络主要负责小目标的检测,深层的网络负责大目标的检测(比如人脸检测中的SSH就使用到了这个特点)。

FPN在RPN中的应用

rpn在faster rcnn中用于生成proposals,原版rpn生成在每个image的最后一张特征图上生成3x3个proposal。但实际上,小目标下采样到最后一个特征图,已经很小了。fpn可以在之前的多个特征图上获得proposal,具体做法是:在每个feature map上获得1:1、1:2、2:1长宽比的框,尺寸是{32^2、64^2、128^2、256^2、512^2}分别对应{P2、P3、P4、P5、P6}这五个特征层上。P6是专门为了RPN网络而设计的,用来处理512大小的候选框。它由P5经过下采样得到。

如何解决小目标识别问题

通用的定义来自 COCO 数据集(),定义小于 32x32 pix 的为小目标。

小目标检测的难点:可利用特征少,现有数据集中小目标占比少,小目标聚集问题

首先小目标本身分辨率低,图像模糊,携带的信息少。由此所导致特征表达能力弱,也就是在提取特征的过程中,能提取到的特征非常少,这不利于我们对小目标的检测。

另外通常网络为了减少计算量,都使用到了下采样,而下采样过多,会导致小目标的信息在最后的特征图上只有几个像素(甚至更少),信息损失较多。

  1. 数据。
    提高图像采集的分辨率:基于 GAN 的方法解决的也是小目标本身判别性特征少的问题,其想法非常简单但有效:利用 GAN 生成高分辨率图片或者高分辨率特征。
  2. Data Augmentation。一些特别有用的小物体检测增强包括随机裁剪、随机旋转和马赛克增强。copy pasting, 增加小目标数量。缩放与拼接,增加中小目标数量
  3. 修改模型输入尺寸。提高模型的输入分辨率,也就是减少或者不压缩原图像。tiling,将图像切割后形成batch,可以在保持小输入分辨率的同时提升小目标检测,但是推理时也需要 tiling,然后把目标还原到原图,整体做一次 NMS。
  4. 修改 Anchor。适合小目标的 Anchor
  5. Anchor Free。锚框设计难以获得平衡小目标召回率与计算成本之间的矛盾,而且这种方式导致了小目标的正样本与大目标的正样本极度不均衡,使得模型更加关注于大目标的检测性能,从而忽视了小目标的检测。
  6. 多尺度学习。FPN, 空洞卷积,通过多尺度可以将下采样前的特征保留,尽量保留小目标
  7. 减小下采样率。比如对于 YOLOv5 的 stride 为 32, 可以调整其 stride 来减小下采样率,从而保留某些比较小的特征。
  8. SPP 模块。增加感受野,对小目标有效果,SPP size 的设置解决输入 feature map 的size 可能效果更好。
  9. 损失函数。小目标大权重,此外也可以尝试 Focal Loss。
介绍目标检测RCNN系列和Yolo系列的区别

YOLO所属类别为one-stage,Fast-Rcnn所属类别为two-stage

two stage:

先进行区域生成,该区域称为region proposal(RP,一个有可能包含物体的预选框);再通过卷积神经网络进行样本分类,精度高,适合做高检测精度的任务

任务流程:特征提取—生成RP—分类/定位回归

opencv面试宝典1_数据_07

one stage:

不用RP,直接在网络中提取特征来预测物体的分类和位置,速度非常快,适合做实时检测任务,但是效果不会太好

任务流程:特征提取—分类/定位回归

opencv面试宝典1_目标检测_08

YOLO和SSD区别

YOLO将物体检测这个问题定义为bounding box和分类置信度的回归问题。

将整张图像作为输入,划分成SxS grid,每个cell预测B个bounding box(x, y, w, h)及对应的分类置信度(class-specific confidence score)。分类置信度是bounding box是物体的概率及其与真实值IOU相乘的结果。

SSD将物体检测这个问题的解空间,抽象为一组预先设定好(尺度,长宽比,1,2,3,1/2,1/3)的bounding box。在每个bounding box,预测分类label,以及box offset来更好的框出物体。对一张图片,结合多个大小不同的feature map的预测结果,能够处理大小不同的物体。

区别:

YOLO在卷积层后接全连接层,即检测时只利用了最高层Feature maps。而SSD采用金字塔结构,即利用了conv4-3/fc7/conv6-2/conv7-2/conv8_2/conv9_2这些大小不同的feature maps,在多个feature maps上同时进行softmax分类和位置回归

SSD还加入了Prior box(先验框)

前景背景样本不均衡解决方案:Focal Loss,GHM与PISA

我们可以将前景背景类不平衡的解决方案分为四类:(i)硬采样方法,(ii)软抽样方法( Soft Sampling Methods),(iii)无抽样方法和(iv)生成方法。

1.  软抽样方法

软采样调整每个样本在训练过程中迭代的权重(wi),这与硬采样不同,没有样本被丢弃,整个数据集用于更新参数中。该方法同样也可以应用在分类任务中。

1.1 Focal Loss

opencv面试宝典1_目标检测_09

虽然 α 平衡了正负样本,但对难易样本的不平衡没有任何帮助。其中易分样本(即,置信度高的样本)对模型的提升效果非常小,即模型无法从中学习大量的有效信息。所以模型应该主要关注于那些难分样本。(这个假设是有问题的,GHM对其进行了改进)。

我们希望模型能更关注容易错分的数据,反向思考,就是让模型别那么关注容易分类的样本。因此,Focal Loss的思路就是,把高置信度的样本损失降低

opencv面试宝典1_数据_10

1.2 Gradient Harmonizing Mechanism (GHM)

Focal Loss对容易分类的样本进行了损失衰减,让模型更关注难分样本,并通过 α \alpha α和 γ \gamma γ进行调参。这样相比CE loss 可以提高效果,但是也存在一些问题:

Focal loss有两个超参数( α和 γ),调整起来十分费力。

Focal loss 是个静态loss,不会自适应于数据的分布,在训练的过程中会一直的变化。

GHM认为,类别不均衡可总结为难易分类样本的不均衡,而这种难分样本的不均衡又可视为梯度密度分布的不均衡。假设一个正样本被正确分类,它就是正易样本,损失不大,模型不能从中获益。而一个错误分类的样本,更能促进模型迭代。实际应用中,大量的样本都是属于容易分类的类型,这种样本一个起不了太大作用,但量级过大,在模型进行梯度更新时,起主要作用,使得模型朝这类数据更新

GHM中提到:有一部分难分样本就是离群点,不应该给他太多关注;样本不均衡的基本效果可以通过梯度密度直接统计得到,不需要调参。

简而言之:Focal Loss是从置信度p来调整loss,GHM通过一定范围置信度p的样本数来调整loss。

opencv面试宝典1_数据_11

g的值表示样本的属性(easy/hard), 意味着对全局梯度的影响。尽管梯度的严格定义应该是在整个参数空间,但是g是样本梯度的成比例的norm,在这片论文中g被称作gradient norm。

不同属性的样本(hard/easy,pos/neg)可以由 gradient norm的分布来表示。在图1左中可以看出变化非常大。具有 小 gradient norm 的样本具有很大的密度,它们对应于大量的负样本(背景)。由于大量的简单负样本,我们使用log轴来显示样本的分数,以演示具有不同属性的样本的方差的细节。尽管一个easy样本在全局梯度上相比hard样本具有更小的贡献,但是大量的easy样本的全部贡献会压倒少数hard样本的贡献,所以训练过程变得无效。除此之外,论文还发现具有非常 大gradient norm的样本(very hard examples)的密度微大于中间样本的密度。并且发现这些very hard样本大多数是outliers,因为即使模型收敛它们始终稳定存在。如果收敛模型被强制学习分类这些outliers,对其他样本的分类可能不会那么的准确

根据gradient norm分布的分析,GHM关注于不同样本梯度贡献的协调。大量由easy样本产生的累积梯度可以被largely down-weighted并且outliers也可以被相对的down-weighted。最后,每种类型的样本分布将会使平衡的训练会更加的稳定和有效

opencv面试宝典1_数据_12

1.3 PrIme Sample Attention (PISA)

PISA 方法和 Focal loss 和 GHM 出发点不一样, Focal loss 和 GHM 是利用 loss 来度量样本的难易分类程度,而本篇论文做者从 mAP 出发来度量样本的难易程度。

多标签图像分类任务中图片的标签不止一个,因此评价不能用普通单标签图像分类的标准,即mean accuracy,该任务采用的是和信息检索中类似的方法—mAP(mean Average Precision),虽然其字面意思和mean accuracy看起来差不多,但是计算方法要繁琐得多。

该作者提出改论文的方法考虑了两个方面:

样本之间不该是相互独立的或同等对待。基于区域的目标检测是从大量候选框中选取一小部分边界框,以覆盖图像中的全部目标。所以,不一样样本的选择是相互竞争的,而不是独立的。通常来讲,检测器更可取的作法是在确保全部感兴趣的目标都被充分覆盖时,在每一个目标周围的边界框产生高分,而不是对全部正样本产生高分。作者研究代表关注那些与gt目标有最高IOU的样本是实现这一目标的有效方法。

目标的分类和定位是有联系的。定位目标周围的样本很是重要,这一观察具备深入的意义,即目标的分类和定位密切相关。具体地,定位好的样本须要具备高置信度好的分类。

PISA由两个部分组成:

基于重要性的样本重加权(ISR)

分类感知回归损失(CARL)。

ISR(Importance-based Sample Reweighting)

ISR由正样本重加权和负样本重加权组成,分别表示为ISR-P和ISR-N。对于阳性样本,我们采用IoU-HLR作为重要性度量;对于阴性样本,我们采用Score-HLR。给定重要性度量,剩下的问题是如何将重要性映射到适当的损失权重。

oU-HLR:

为了计算IoU-HLR,首先将所有样本根据其最近的gt目标划分为不同的组。接下来,使用与gt的IoU降序对每个组中的样本进行排序,并获得IoU局部排名(IoU-LR)。随后,以相同的IoU-LR采样并按降序对其进行排序。具体来说,收集并分类所有top1 IoU-LR样本,其次是top2,top3,依此类推。这两个步骤将对所有样本进行排序

opencv面试宝典1_目标检测_13

Score-HLR:

以类似于IoU-HLR的方式计算负样本的Score-HLR。与由每个gt目标自然分组的正样本不同,负样本也可能出现在背景区域,因此我们首先使用NMS将它们分组到不同的群集中。将所有前景类别中的最高分数用作负样本的得分,然后执行与计算IoU-HLR相同的步骤。

opencv面试宝典1_人工智能_14

如何解决训练数据样本过少的问题

利用预训练模型进行迁移微调(fine-tuning),预训练模型通常在特征上拥有很好的语义表达。此时,只需将模型在小数据集上进行微调就能取得不错的效果。这也是目前大部分小数据集常用的训练方式。视觉领域内,通常会ImageNet上训练完成的模型。自然语言处理领域,也有BERT模型等预训练模型可以使用。

单样本或者少样本学习(one-shot,few-shot learning),这种方式适用于样本类别远远大于样本数量的情况等极端数据集。例如有1000个类别,每个类别只提供1-5个样本。少样本学习同样也需要借助预训练模型,但有别于微调的在于,微调通常仍然在学习不同类别的语义,而少样本学习通常需要学习样本之间的距离度量。例如孪生网络(Siamese Neural Networks)就是通过训练两个同种结构的网络来判别输入的两张图片是否属于同一类。3. 以上两种是常用训练小样本数据集的方式。此外,也有些常用的方式:数据集增强、正则或者半监督学习等方式来解决小样本数据集的训练问题。

如何解决类别不平衡的问题

机器学习中,解决样本不均衡问题主要有2种思路:数据角度和算法角度。从数据角度出发,有扩大数据集、数据类别均衡采样等方法。在算法层面,目标检测方法使用的方法主要有:

Faster RCNN、SSD等算法在正负样本的筛选时,根据样本与真实物体的IoU大小,设置了3∶1的正负样本比例,这一点缓解了正负样本的不均衡,同时也对难易样本不均衡起到了作用。

Faster RCNN在RPN模块中,通过前景得分排序筛选出了2000个左右的候选框,这也会将大量的负样本与简单样本过滤掉,缓解了前两个不均衡问题。

权重惩罚:对于难易样本与类别间的不均衡,可以增大难样本与少类别的损失权重,从而增大模型对这些样本的惩罚,缓解不均衡问题。

数据增强:从数据侧入手,可以在当前数据集上使用随机生成和添加扰动的方法,也可以利用网络爬虫数据等增加数据集的丰富性,从而缓解难易样本和类别间样本等不均衡问题,可以参考SSD的数据增强方法。

近年来,不少的研究者针对样本不均衡问题进行了深入研究,比较典型的有OHEM(在线困难样本挖掘)、S-OHEM、Focal Loss、GHM(梯度均衡化)。

  1. OHEM:在线难例挖掘
    OHEM算法(online hard example miniing,发表于2016年的CVPR)主要是针对训练过程中的困难样本自动选择,其核心思想是根据输入样本的损失进行筛选,筛选出困难样本(即对分类和检测影响较大的样本),然后将筛选得到的这些样本应用在随机梯度下降中训练。
  2. Focal loss:专注难样本
    为了解决一阶网络中样本的不均衡问题,何凯明等人首先改善了分类过程中的交叉熵函数,提出了可以动态调整权重的Focal Loss。
  3. GHM:损失函数梯度均衡化机制

前面讲到的OHEM算法和Focal loss各有利弊:

1、OHEM算法会丢弃loss比较低的样本,使得这些样本无法被学习到。

2、FocalLoss则是对正负样本进行加权,使得全部的样本可以得到学习,容易分类的负样本赋予低权值,hard examples赋予高权值。但是在所有的anchor examples中,出了大量的易分类的负样本外,还存在很多的outlier,FocalLoss对这些outlier并没有相关策略处理。并且FocalLoss存在两个超参,根据不同的数据集,调试两个超参需要大量的实验,一旦确定参数无法改变,不能根据数据的分布动态的调整。

GHM主要思想:GHM做法则是从样本的梯度范数出发,通过梯度范数所占的样本比例,对样本进行动态的加权,使得具有小梯度的容易分类的样本降权,具有中梯度的hard expamle升权,具有大梯度的outlier降权。

手撕代码IOU
import numpy as np
def ComputeIOU(boxA, boxB):
    ## 计算相交框的坐标
    ## bboxA[0][1] 左上角坐标  bboxA[2][3] 右下角坐标
    x1 = np.max([boxA[0], boxB[0]])
    y1 = np.max([boxA[1], boxB[1]])
    x2 = np.min([boxA[2], boxB[2]])
    y2 = np.min([boxA[3], boxB[3]])
    ## 计算交区域,并区域,及IOU
    S_A = (boxA[2]-boxA[0]+1)*(boxA[3]-boxA[1]+1)
    S_B = (boxB[2]-boxB[0]+1)*(boxB[3]-boxB[1]+1)
    interArea = np.max([x2-x1+1, 0])*np.max([y2-y1+1,0])	##一定要和0比较大小,如果是负数就说明压根不相交
    unionArea = S_A + S_B - interArea
    iou = interArea/unionArea
    return iou
boxA = [1,1,3,3]
boxB = [2,2,4,4]
IOU = ComputeIOU(boxA, boxB)
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
手撕代码NMS
对整个bboxes排序的写法
import numpy as np
def nms(dets, iou_thred, cfd_thred):
    if len(dets)==0: return []
    bboxes = np.array(dets)
    ## 对整个bboxes排序
    bboxes = bboxes[np.argsort(bboxes[:,4])]
    pick_bboxes = []
#     print(bboxes)
    while bboxes.shape[0] and bboxes[-1,-1] >= cfd_thred:
        bbox = bboxes[-1]
        x1 = np.maximum(bbox[0], bboxes[:-1,0])
        y1 = np.maximum(bbox[1], bboxes[:-1,1])
        x2 = np.minimum(bbox[2], bboxes[:-1,2])
        y2 = np.minimum(bbox[3], bboxes[:-1,3])
        inters = np.maximum(x2-x1+1, 0) * np.maximum(y2-y1+1, 0)
        unions = (bbox[2]-bbox[0]+1)*(bbox[3]-bbox[1]+1) + (bboxes[:-1,2]-bboxes[:-1,0]+1)*(bboxes[:-1,3]-bboxes[:-1,1]+1) - inters
        ious = inters/unions
        keep_indices = np.where(ious<iou_thred)
        bboxes = bboxes[keep_indices]	## indices一定不包括自己
        pick_bboxes.append(bbox)
    return np.asarray(pick_bboxes)
dets = [[187, 82, 337, 317, 0.9], [150, 67, 305, 282, 0.75], [246, 121, 368, 304, 0.8]]
dets_nms =  nms(dets, 0.5, 0.3)
print(dets_nms)
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  1. 不改变bboxes,维护orders的写法

始终维护orders,代表到原bboxes的映射(map) 优化1:仅维护orders,不改变原bboxes 优化2:提前计算好bboxes的面积,以免在循环中多次重复计算

import numpy as np
def nms(dets, iou_thred, cfd_thred):
    if len(dets)==0: return []
    bboxes = np.array(dets)
    ## 维护orders
    orders = np.argsort(bboxes[:,4])
    pick_bboxes = []
    x1 = bboxes[:,0]
    y1 = bboxes[:,1]
    x2 = bboxes[:,2]
    y2 = bboxes[:,3]
    areas = (x2-x1+1)*(y2-y1+1) ## 提前计算好bboxes面积,防止在循环中重复计算
    while orders.shape[0] and bboxes[orders[-1],-1] >= cfd_thred:
        bbox = bboxes[orders[-1]]
        xx1 = np.maximum(bbox[0], x1[orders[:-1]])
        yy1 = np.maximum(bbox[1], y1[orders[:-1]])
        xx2 = np.minimum(bbox[2], x2[orders[:-1]])
        yy2 = np.minimum(bbox[3], y2[orders[:-1]])
        inters = np.maximum(xx2-xx1+1, 0) * np.maximum(yy2-yy1+1, 0)
        unions = areas[orders[-1]] + areas[orders[:-1]] - inters
        ious = inters/unions
        keep_indices = np.where(ious<iou_thred)
        pick_bboxes.append(bbox)
        orders = orders[keep_indices]
    return np.asarray(pick_bboxes)
dets = [[187, 82, 337, 317, 0.9], [150, 67, 305, 282, 0.75], [246, 121, 368, 304, 0.8]]
dets_nms = nms(dets, 0.5, 0.3)
print(dets_nms)
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
NMS的改进思路
  1. 根据手动设置阈值的缺陷,通过自适应的方法在目标系数时使用小阈值,目标稠密时使用大阈值。例如Adaptive NMS
  2. 将低于阈值的直接置为0的做法太hard,通过将其根据IoU大小来进行惩罚衰减,则变得更加soft。例如Soft NMS,Softer NMS。
  3. 只能在CPU上运行,速度太慢的改进思路有三个,一个是设计在GPU上的NMS,如CUDA NMS,一个是设计更快的NMS,如Fast NMS,最后一个是掀桌子,设计一个神经网络来实现NMS,如 ConvNMS。
  4. IoU的做法存在一定缺陷,改进思路是将目标尺度、距离引进IoU的考虑中。如DIoU
IOU相关优化(giou,diou,ciou)

GIOU

普通IOU是对两个框的距离不敏感的,下面两张图中,左图预测框的坐标要比右图预测框的坐标更接近真实框。但两者的IOU皆为0,如果直接把IOU当作loss函数进行优化,则loss=0,没有梯度回传,所以无法进行训练。

opencv面试宝典1_目标检测_15

opencv面试宝典1_数据集_16

但是,GIOU也存在它的缺点:当两个预测框高宽相同,且处于同一水平面时,GIOU就退化为IOU。此外,GIOU和IOU还有两个缺点:收敛较慢、回归不够准确。

DIOU

opencv面试宝典1_人工智能_17

在介绍DIOU之前,先来介绍采用DIOU的效果:如图,黑色代表anchor box, 蓝色红色代表default box,绿色代表真实目标存在的框GT box的位置,期望红蓝框与绿框尽可能重合。第一行是使用GIOU训练网络,让预测边界框尽可能回归到真实目标边界框中,迭代到400次后才勉强重合。第二行使用DIOU训练网络,到达120步时,发现与目标边界框已经完全重合。可以看出,相对于GIOU,DIOU的不仅收敛速度更快,准确率也更高。 

opencv面试宝典1_目标检测_18

我们再看一组图,图中给出了3组目标边界框与目标边界框的重合关系,显然他们的重合位置不相同的,我们期望第三种重合(两个box中心位置尽可能重合。这三组计算的IOU loss和GIoU loss是一模一样的,因此这两种损失不能很好表达边界框重合关系)。但是DIOU计算出的三种情况的损失是不一样的,显然DIOU更加合理。 

opencv面试宝典1_数据_19

opencv面试宝典1_数据_20

 

从公式和示意图中,我们可以看到,DIoU有几个优点:

DIoU的惩罚项是基于中心点的距离和对角线距离的比值,避免了像GIoU在两框距离较远时,产生较大的外包框,Loss值较大难以优化(因为它的惩罚项是 A ∪ B 比上最小外包框的面积)。所以DIoU Loss收敛速度会比GIoU Loss快。

即使在一个框包含另一个框的情况下,c值不变,但d值也可以进行有效度量。

CIOU LOSS:

论文中,作者表示一个优秀的回归定位损失应该考虑三种几何参数:重叠面积、中心点距离、长宽比。CIoU就是在DIoU的基础上增加了检测框尺度的loss,增加了长和宽的loss,这样预测框就会更加的符合真实框。

opencv面试宝典1_人工智能_21

opencv面试宝典1_人工智能_22