在过去的十多年时间里,传统的机器视觉领域,通常采用特征描述子来应对目标识别任务,这些特征描述子最常见的就是 SIFT 和 HOG.而 OpenCV 有现成的 API 可供大家实现相关的操作
计算机视觉五大技术:图像分类、对象检测、目标跟踪、语义分割和实例分割
目前学术和工业界出现的目标检测算法分成3类:
1、传统的目标检测算法:Cascade + HOG/DPM + Haar/SVM以及上述方法的诸多改进、优化;
2、双阶段方法:候选区域/框 + 深度学习分类:通过提取候选区域,并对相应区域进行以深度学习方法为主的分类的方案, 如:R-CNN(Selective Search + CNN + SVM)SPP-net(ROI Pooling)Fast R-CNN(Selective Search + CNN + ROI)Faster R-CNN(RPN + CNN + ROI)R-FCN等系列方法;
3、单阶段方法: 基于深度学习的回归方法:YOLO/SSD/DenseBox 等方法, 及anchor based 和anchor free的方法。
HOG特征是一种在计算机视觉和图像处理中用来进行物体检测的特征描述子,是与SIFT、SURF、ORB属于同一类型的描述符。HOG不是基于颜色值而是基于梯度来计算直方图的,它通过计算和统计图像局部区域的梯度方向直方图来构建特征。HOG特征结合SVM分类器已经被广泛应用到图像识别中,尤其在行人检测中获得了极大的成功。
此方法的基本观点是:局部目标的外表和形状可以被局部梯度或边缘方向的分布很好的描述,即使我们不知道对应的梯度和边缘的位置。(本质:梯度的统计信息,梯度主要存在于边缘的地方)
参数说明:sift为实例化的sift函数
参数说明: kp表示生成的关键点,gray表示输入的灰度图,
参数说明:gray表示输入图片, kp表示关键点,img表示输出的图片
参数说明:kp表示输入的关键点,dst表示输出的sift特征向量,通常是128维的
BoW模型最初是为解决文档建模问题而提出的,因为文本本身就是由单词组成的。它忽略文本的词序,语法,句法,仅仅将文本当作一个个词的集合,并且假设每个词彼此都是独立的。这样就可以使用文本中词出现的频率来对文档进行描述,将一个文档表示成一个一维的向量。
将BoW引入到计算机视觉中,就是将一幅图像看着文本对象,图像中的不同特征可以看着构成图像的不同词汇。和文本的BoW类似,这样就可以使用图像特征在图像中出现的频率,使用一个一维的向量来描述图像。
BOW一般过程:
简略过程:
feature_detector = cv2.xfeatures2d.SIFT_create()
bow_kmeans_trainer = cv2.BOWKMeansTrainer(k)
voc = bow_kmeans_trainer.cluster()
bow_img_descriptor_extractor = cv2.BOWImgDescriptorExtractor(self.descriptor_extractor, flann)
bow_img_descriptor_extractor.setVocabulary(voc)
bow_img_descriptor_extractor.compute(im, feature_detector.detect(im))
结构:selective search →ROI →CNN→max score
也可参考:这篇文章
对一张图片,用各种大小的框(大牛们发明好多选定候选框的方法,比如EdgeBoxes和Selective Search。)将图片截取出来,输入到CNN,然后CNN会输出这个框的得分(classification)以及这个框图片对应的x,y,h,w(regression)候选区域方法(region proposal method)创建目标检测的感兴趣区域(ROI)。在选择性搜索(selective search,SS)中,我们首先将每个像素作为一组。然后,计算每一组的纹理,并将两个最接近的组结合起来。但是为了避免单个区域吞噬其他区域,我们首先对较小的组进行分组。我们继续合并区域,直到所有区域都结合在一起。能够生成候选区域的方法很多,比如: objectness、selective search、category-independen、object proposals、constrained parametric min-cuts(CPMC)、 multi-scale、 combinatorial grouping、Ciresan。 R-CNN 采用的是 Selective Search 算法。
**selective search:**
输入: 一张图片;
输出:候选的目标位置集合L
算法:
1: 利用切分方法得到候选的区域集合R = {r1,r2,…,rn}
2: 初始化相似集合S = ϕ
3: foreach 遍历邻居区域对(ri,rj) do
4: 计算相似度s(ri,rj)
5: S = S ∪ s(ri,rj)
6: while S not=ϕ do
7: 从S中得到最大的相似度s(ri,rj)=max(S)
8: 合并对应的区域rt = ri ∪ rj
9: 移除ri对应的所有相似度:S = S\s(ri,r*)
10: 移除rj对应的所有相似度:S = S\s(r*,rj)
11: 计算rt对应的相似度集合St
12: S = S ∪ St
13: R = R ∪ rt
14: L = R中所有区域对应的边框
下面展开进行介绍
1、生成候选区域
使用Selective Search(选择性搜索)方法对一张图像生成约2000-3000个候选区域,基本思路如下:
(1)使用一种过分割手段,将图像分割成小区域
(2)查看现有小区域,合并可能性最高的两个区域,重复直到整张图像合并成一个区域位置。优先合并以下区域:- 颜色(颜色直方图)相近的 -纹理(梯度直方图)相近的- 合并后总面积小的- 合并后,总面积在其BBOX中所占比例大的在合并时须保证合并操作的尺度较为均匀,避免一个大区域陆续“吃掉”其它小区域,保证合并后形状规则。
(3)输出所有曾经存在过的区域,即所谓候选区域
2、特征提取
使用深度网络提取特征之前,首先把候选区域归一化成同一尺寸227×227。
使用CNN模型进行训练,例如AlexNet,一般会略作简化,如下图:
3、类别判断
对每一类目标,使用一个线性SVM二类分类器进行判别。输入为深度网络(如上图的AlexNet)输出的4096维特征,输出是否属于此类。
4、位置精修
目标检测的衡量标准是重叠面积:许多看似准确的检测结果,往往因为候选框不够准确,重叠面积很小,故需要一个位置精修步骤,对于每一个类,训练一个线性回归模型去判定这个框是否框得完美。
R-CNN将深度学习引入检测领域后,一举将PASCAL VOC上的检测率从35.1%提升到53.7%。
位置精修方法:
G x = P x + P w ∗ t x , G y = P y + P w ∗ t y , G w = P w ∗ e t w , G h = P h ∗ e t h G_x= P_x+P_w*t_x, \\G_y= P_y+P_w*t_y, \\G_w= P_w*e^{t_w},\\G_h= P_h*e^{t_h} Gx=Px+Pw∗tx,Gy=Py+Pw∗ty,Gw=Pw∗etw,Gh=Ph∗eth
最大瓶颈是2k个候选区域都要经过一次CNN,速度非常慢。Kaiming He大神最先对此作出改进,提出了SPP-net,最大的改进是只需要将原图输入一次,就可以得到每个候选区域的特征。
[完结]
(金字塔池化) -> ROI POOLING
我们使用三层的金字塔池化层pooling,分别设置图片切分成多少块,论文中设置的分别是(1,4,16),然后按照层次对这个特征图feature A进行分别处理(用代码实现就是for(1,2,3层)),也就是在第一层对这个特征图feature A整个特征图进行池化(池化又分为:最大池化,平均池化,随机池化),论文中使用的是最大池化,得到1个特征。
第二层先将这个特征图feature A切分为4个(20,30)的小的特征图,然后使用对应的大小的池化核对其进行池化得到4个特征,
第三层先将这个特征图feature A切分为16个(10,15)的小的特征图,然后使用对应大小的池化核对其进行池化得到16个特征.
然后将这1+4+16=21个特征输入到全连接层,进行权重计算. 当然了,这个层数是可以随意设定的,以及这个图片划分也是可以随意的,只要效果好同时最后能组合成我们需要的特征个数即可
[完结]
也可参考这篇文章
一张完整图片–>CNN–>得到每张候选框的特征–>分类+回归
Fast R-CNN存在的问题:存在瓶颈:选择性搜索,找出所有的候选框,这个也非常耗时。那我们能不能找出一个更加高效的方法来求出这些候选框呢?
[完结]
通过上述介绍可以知道,Faster R-CNN与Fast R-CNN最大的区别就是提出了一个叫RPN(Region Proposal Networks)的网络,专门用来推荐候选区域的,RPN可以理解为一种全卷积网络,该网络可以进行end-to-end的训练,最终目的是为了推荐候选区域,如下图所示
解释一下上面这张图:
1)在原文中使用的是ZF model中,其Conv Layers中最后的conv5层num_output=256,对应生成256张特征图(feature maps),所以相当于feature map每个点都是256-dimensions
2)在conv5之后,做了rpn_conv/3x3卷积且num_output=256,相当于每个点又融合了周围3x3的空间信息),同时256-d不变
3)假设在conv5 feature map中每个点上有k个anchor(原文如上k=9),而每个anhcor要分foreground和background,所以每个点由256d feature转化为cls=2k scores;而每个anchor都有[x, y, w, h]对应4个偏移量,所以reg=4k coordinates(scores和coordinates为RPN的最终输出)
4)补充一点,全部anchors拿去训练太多了,训练程序会在合适的anchors中随机选取128个postive anchors+128个negative anchors进行训练(至于什么是合适的anchors接下来RPN的训练会讲)
RPN训练中对于正样本文章中给出两种定义。第一,与ground truth box有最大的IoU的anchors作为正样本;第二,与ground truth box的IoU大于0.7的作为正样本。文中采取的是第一种方式。文中定义的负样本为与ground truth box的IoU小于0.3的样本。
[完结]
也可参考这篇文章和这篇文章
Faster R-CNN的主要贡献是设计了提取候选区域的网络RPN,代替了费时的选择性搜索,使得检测速度大幅提高。
通过上面两张图可以看出Faster R-CNN由四个部分组成:
1)卷积层(conv layers),用于提取图片的特征,输入为整张图片,输出为提取出的特征称为feature maps
2)RPN网络(Region Proposal Network),用于推荐候选区域,这个网络是用来代替之前的search selective的。输入为图片(因为这里RPN网络和Fast R-CNN共用同一个CNN,所以这里输入也可以认为是featrue maps),输出为多个候选区域,这里的细节会在后面详细介绍。
3)RoI pooling,和Fast R-CNN一样,将不同大小的输入转换为固定长度的输出,输入输出和Faste R-CNN中RoI pooling一样。
通过上述介绍可以知道,Faster R-CNN与Fast R-CNN最大的区别就是提出了一个叫RPN(Region Proposal Networks)的网络,专门用来推荐候选区域的,RPN可以理解为一种全卷积网络,该网络可以进行end-to-end的训练,最终目的是为了推荐候选区域,如下图所示。
4)分类和回归,这一层的输出是最终目的,输出候选区域所属的类,和候选区域在图像中的精确位置。
[完结]
最后总结一下各大算法的步骤:
RCNN
1. 在图像中确定约1000-2000个候选框 (使用选择性搜索)
2. 每个候选框内图像块缩放至相同大小,并输入到CNN内进行特征提取
3. 对候选框中提取出的特征,使用分类器判别是否属于一个特定类
4. 对于属于某一特征的候选框,用回归器进一步调整其位置
Fast RCNN
采用selective search到feature map的映射,替换rcnn中每个selective search都输入cnn导致大量的重复运算
1. 在图像中确定约1000-2000个候选框 (使用选择性搜索)
2. 对整张图片输进CNN,得到feature map
3. 找到每个候选框在feature map上的映射patch,将此patch作为每个候选框的卷积特征输入到roi pooling 层, 得到固定尺寸的feature map
4. 对候选框中提取出的特征feature map,使用分类器判别是否属于一个特定类
5. 对于属于某一特征的候选框,用回归器进一步调整其位置
Faster RCNN
采用RPN替换selective search映射
1. 对整张图片输进CNN,得到feature map
2. 卷积特征输入到RPN,得到候选框的特征信息
3. 对候选框中提取出的特征,使用分类器判别是否属于一个特定类
4. 对于属于某一特征的候选框,用回归器进一步调整其位置
[完结]
扩展阅读:https://blog.csdn.net/wangdongwei0/article/details/83110305;
https://zhuanlan.zhihu.com/p/37998710
Mask RCNN可以看做是一个通用实例分割架构。
Mask RCNN以Faster RCNN原型,增加了一个分支用于分割任务。
Mask RCNN比Faster RCNN速度慢一些,达到了5fps。
可用于人的姿态估计等其他任务;
RoIAlign:
RoIPool的目的是为了从RPN网络确定的ROI中导出较小的特征图(a small feature map,eg 7x7),ROI的大小各不相同,但是RoIPool后都变成了7x7大小。RPN网络会提出若干RoI的坐标以[x,y,w,h]表示,然后输入RoI Pooling,输出7x7大小的特征图供分类和定位使用。问题就出在RoI Pooling的输出大小是7x7上,如果RON网络输出的RoI大小是8*8的,那么无法保证输入像素和输出像素是一一对应,首先他们包含的信息量不同(有的是1对1,有的是1对2),其次他们的坐标无法和输入对应起来(1对2的那个RoI输出像素该对应哪个输入像素的坐标?)。这对分类没什么影响,但是对分割却影响很大。RoIAlign的输出坐标使用插值算法得到,不再量化;每个grid中的值也不再使用max,同样使用差值算法。
实际上,Mask RCNN中还有一个很重要的改进,就是ROIAlign。Faster R-CNN存在的问题是:特征图与原始图像是不对准的(mis-alignment),所以会影响检测精度。而Mask R-CNN提出了RoIAlign的方法来取代ROI pooling,RoIAlign可以保留大致的空间位置。
双线性插值
RoIAlign采用双线性插值:
下面通过一个例子来讲解ROI Align操作。如下图所示,虚线部分表示feature map,实线表示ROI,这里将ROI切分成2x2的单元格。如果采样点数是4,那我们首先将每个单元格子均分成四个小方格(如红色线所示),每个小方格中心就是采样点。这些采样点的坐标通常是浮点数,所以需要对采样点像素进行双线性插值(如四个箭头所示),就可以得到该像素点的值了。然后对每个单元格内的四个采样点进行maxpooling,就可以得到最终的ROIAlign的结果。
[完结]
backbone:
anchor box:
在特征图的每个像素点处,生成不同宽高比的default box(anchor box),论文中设置的宽高比为{1,2,3,1/2,1/3}。假设每个像素点有k个default box,需要对每个default box进行分类和回归.
[完结]
详细内容请参考我的另一篇博客:RFB Net
RFB其实就是采用inception的结构+dilated convolution的方式。
yolo 与 SSD最大的区别:
1、SSD classes 里包含背景,yolo不包含而是做在conf里面;
2、yolo网格对应的anchors与目标的IOU比较,如果>thresh,但是目标的中心点不在该网格类,这类样本不参与训练。因此,这就是与SSD最大的不同了,在SSD里,看的是所有anchors与目标的IOU距离,如果IOU大于0.7,所在的anchors都是正例样本。而在YOLO里,只看中心点所在的网格对应的anchors,其他与之对应的anchors要么当作负样本了,要么就不参与训练了。
可以参考:https://blog.csdn.net/weixin_38570251/article/details/81853247
YOLO-V1
YOLO的核心思想就是利用整张图作为网络的输入,直接在输出层回归bounding box的位置和bounding box所属的类别。
把老狗放这比较合适。
faster RCNN中也直接用整张图作为输入,但是faster-RCNN整体还是采用了RCNN那种 proposal+classifier的思想,只不过是将提取proposal的步骤放在CNN中实现了,而YOLO则采用直接回归的思路,YOLO v1首先会把原始图片放缩到448×448的尺寸,然后将图片划分成SxS个单元格。如果一个对象的中心落在某个单元格上,那么这个单元格负责预测这个物体。每个单元格需要预测B个边界框(bbox)值(bbox值包括坐标和宽高),同时为每个bbox值预测一个置信度(confidence scores)。
[完结]
backbone:
将一幅图经过CNN后等到7X7X30的featuremap,30:SxSx(B∗5+C) = 7x7x(2*5 + 20)=7x7x30
2, 5,20:代表能预测2个框的5个参数(x,y,w,h,score)和20个种类。
损失函数:
[完结]
yolo-v2
backbone: darknet-19
1.添加Batch Normalization层;
2.引入anchor boxes, 在训练集(training set)Bounding Boxes上跑了一下k-means聚类,来找到几个比较好的anchor boxes。
loss function:
[完结]
yolo-v3
1.多尺度预测 (类FPN)
2.更好的基础分类网络(类似ResNet) darknet-53。
3.分类器-类别预测:
YOLOv3不使用Softmax对每个框进行分类,主要考虑因素有两个:
a.Softmax使得每个框分配一个类别(score最大的一个),而对于Open Images这种数据集,目标可能有重叠的类别标签,因此Softmax不适用于多标签分类。
b.Softmax可被独立的多个logistic分类器替代,且准确率不会下降。
分类损失采用binary cross-entropy loss.
backbone: darknet-53
结构如下图再合适不过了。
[完结]
YOLOv3-tiny-mobilenet:采用mobilenet的主干网络
动机:
左边的人脸框明显比右边的要准一点,但是脸太大,则导致loss最终反而比右边的大,然后我们就去惩罚这个loss,结果最后检测器对小人脸效果就不好了。
没啥好说的直接上原文中的图.
Repulsion Loss 的总损失函数为:
其中:
G A t t r P = a r g m a x G ∈ g I o U ( G , P ) 与 p r o p o s a l 最 大 的 那 个 g r o u n d t r u t h G^P_{Attr} = argmax_{G∈g}IoU(G,P)与proposal最大的那个groundtruth GAttrP=argmaxG∈gIoU(G,P)与proposal最大的那个groundtruth
LAttr 就是一个正常的回归loss,希望候选的正样本能够靠近其对应的标注框,正样本就是和候选框有最大的 IoU 的 ground truth。
此项的目的是使候选框与周围非其目标的ground true框排斥。给定一个候选框P∈ P+,文章把除了其目标框之外再与其具有最大IoU值的ground true框作为其排斥目标框.用来防止 proposal 靠近其周围不应该属于他的 ground-truth 目标,对于任何一个 positive proposal,其有一个和他最大 IoU 的 ground-truth 目标,除了这个目标之外和他 IoU 最大的 ground-truth 目标就是需要远离。
此项的目的是使候选框与其它目标不同的候选框排斥,这也使检测器对NMS操作更鲁棒。
[完结]
Motivation:
但直接用IoU作为损失函数会出现两个问题:
1,如果两个框没有相交,根据定义,IoU=0,不能反映两者的距离大小(重合度)。
2,同时因为loss=0,没有梯度回传,无法进行学习训练。
如下图: IoU无法精确的反映两者的重合度大小。如下图所示,三种情况IoU都相等,但看得出来他们的重合度是不一样的,左边的图回归的效果最好,右边的最差。
GIOU方法如下:很简单
传统NMS方法:
SOFT NMS方法:
SOFT NMS方法:
但是上面这个公式是不连续的,这样会导致box集合中的score出现断层,因此就有了下面这个Soft NMS式子,改进SOFT NMS:
[完结]
可参考我的另一篇博客 Adaptive NMS
概要:
先定义一个object density:
d i = M a x ( i o u ( b i , b j ) ) , 其 中 b i ∈ G , i ≠ j N M = M a x ( N t , d M ) , N t 为 G r e e d y N M S 中 的 阈 值 , d M 为 密 度 值 s i = { s i i o u ( M , b i ) < N M s i ∗ f ( i o u ( M , b i ) ) i o u ( M , b i ) > N M d_i = Max( iou(b_i,b_j)), 其中b_i \in G,i \ne j\\ N_M=Max(Nt, d_M), N_t为Greedy NMS中的阈值, d_M为密度值\\ s_i =\left\{ \begin{array}{rcl} s_i& & {iou(M,b_i)
因此,只要求到 d M d_M dM就可以了;
object density, d M d_M dM求法:
RetinaNet是2018年Facebook AI团队在目标检测领域新的贡献。
将原先训练 回归任务 惯用的 交叉熵误差 C E ( p t ) = − y t l o g ( p t ) CE(p_t)=−y_tlog(p_t) CE(pt)=−ytlog(pt)改为 FL (focal loss) 即可: F L ( p t ) = − α ∗ ( 1 − p t ) r ∗ l o g ( p t ) FL(p_t)=−\alpha*(1-p_t)^r* log(p_t) FL(pt)=−α∗(1−pt)r∗log(pt)
obj_loss = alpha * pow((torch.ones_like(pre_obj) - pre_obj), 2) * self.bceloss(pre_obj * obj_mask,lab_obj * obj_mask)
noobj_loss = (1 - alpha) * pow(pre_obj, 2) * self.bceloss(pre_obj * ignore_mask, lab_obj * ignore_mask)
上面代码是我的实际应用。
[完结]
论文中心思想:作者采用了two stage的思想先用一个ARM网络结构对ancor 进行处理,ARM就像RPN网络,其作用如下:1)用于修正anchor,去掉多余的负样本,减少负本数量;2)对anchor的进行修正,使ODM网络更容易分类和回归。ODM网络是由ARM网络通过TCB网络处理得到。TCP就像FPN中的上采样那样,将高层的语义信息与低层的信息相融合。TCB网络如下图,直接对上采样的网络进行相加等到。
这样在各个feature map 上,每个anchor产生c个类别以及4个坐标。与SSD不一样的是,SSD使用的是default box去预测,而refineDet使用的是ARM网络产生的refined anchor去预测。这使RefineDet具备的one&tow stage的优点。
可参考我的另一篇博客RefineDet
[完结]
可参考我的另一篇博客PFP Net
作者认为像金字塔形式的Feature map的网络,限制了网络的表现,尤其对于小目标的检测。对此,作者提出PFPNET。如图d所示。
Related Works:
先直接上PFPNET网络结构图:
base network:预训练去掉全连接层的VGG16。
Bottleneck layer: conv1x1+batch norm +relu
FP pool: 就一般的池化
MSCA: 将 F H 与 F L F_H与F_L FH与FL的特征图组合在一起,并再将大特征图downsamping, 小特征图upsamping,到同一尺度,再concatenate.其中, F H F_H FH有D个channels, F L 有 ( N − 1 ) × D / ( N − 1 ) = D F_L有(N-1)×D/(N-1)=D FL有(N−1)×D/(N−1)=D(作者的目的就是凑成D)个channels,各占一半。此外,作者也做过去掉 F H F_H FH,全由 F L F_L FL组成Feature map的实验,但表现与预期一样不好。
details: 采用RfineDet的ARM方式来做Anchors.
PFPNET:
1)图像经过VGG16的base network后,产生WXHXD的Feature map
2) 再经SPP池化成N(图中为3)个high dimensional 的特征图 ( F H ) s i z e = W 2 n × H 2 n (F_H) size =\frac{W}{2^n} × \frac{H}{2^n} (FH)size=2nW×2nHN:pyramid levels.
3)经过Bottleneck layer ( H L n ) (H_L^n) (HLn),得到 ( F L ) c h a n n e l = D / ( N − 1 ) (F_L)channel=D/(N-1) (FL)channel=D/(N−1)
4)经MSCA,得到 P L P_L PL;
5)最后采用RefineDet的方法进行训练(可以参考我的別一篇博客RefineDet)。
[完结]
作者提出anchor-free的在线式的选择特征层的方法,尤其是对FPN的多个特征层选择,并且在这个训练的同时也可以采用anchor-based的方法并行训练。大致可描述为下图:
可参考我的另一篇博客FSAF
[完结]
论文中心思想:更改了以目标分类的backbone,得到目标检测的backbone:M2Det.
请参考我的另一篇博客M2Det
[完结]
[完结]
Motivation:
作者认为检测效果好的网络,模型都比较大,而且速度大都比较慢。检测速度快的网络,大都检测效果差,因此,提出EfficientDet,在兼容效果的同时保证了速度。
Related Works:
BiFPN:
BiFPN是作者构建的创新网络:上一副网络演变对比图
Weighted Feature Fusion:
以P6为例说明了计算过程
其中 ω \omega ω是融合系数。并用softmax使所有 ω \omega ω相加为1.为使稳定加入了一个很小的系数: ϵ = 0.0001 \epsilon= 0.0001 ϵ=0.0001
Networks:
于是构建出整个网络模型:
Compound Scaling:
作者参考了EfficientNet中的方法:
干脆直接用了EfficientNet的backboneB0-B7,这样还直接用了它的预训练权重。
形成了一系列的Scaling:
具体请参考我的另一篇博客Gaussian Yolov3
[完结]