【原创】R-CNN及Selective Search原理详解


R-CNN论文链接: R-CNN
R-CNN将CNN引入了目标检测领域,可以说是CNN在目标检测领域的开山之作,改变了目标检测领域的研究思路,紧随其后的是Fast R-CNN、Faster R-CNN、Mask R-CNN等一系列模型。

在这里插入图片描述
R-CNN分为三个部分:
1.候选区域生成:对输入图像采用Selective Search的方法生成2K个较为可能是目标的候选区域
2.特征提取: 对每个候选区域用卷积网络提取特征
3.类别判定: 将从卷积网络中读取的特征送入SVM模型中分类
4.位置调整: 使用回归器调整候选区域的位置

候选区域生成

R-CNN使用了Selective Search方法来生成候选区域,相对于传统的滑动窗口方法,Selective Search方法预先生成了较为可能是物体的候选区域。

Selective Search方法

在这里插入图片描述
这篇文章的描述我觉得写得非常好:目标检测(1)-Selective Search

由于我们事先不知道需要检测哪个类别,因此第一张图的桌子、瓶子、餐具都是一个个候选目标,而餐具包含在桌子这个目标内,勺子又包含在碗内。这张图展示了目标检测的层级关系以及尺度关系,那我们如何去获得这些可能目标的位置呢。常规方法是通过穷举法,就是在原始图片上进行不同尺度不同大小的滑窗,获取每个可能的位置。而这样做的缺点也显而易见,就是计算量实在是太大了,而且由于不可能每个尺度都兼顾到,因此得到的目标位置也不可能那么准。那么我们能不能通过视觉特征去减少这种分类的可能性并提高精确度呢。这就是本文想做的事情。
可用的特征有很多,到底什么特征是有用的呢?我们看第二副图片的两只猫咪,他们的纹理是一样的,因此纹理特征肯定不行了。而如果通过颜色则能很好区分。但是第三幅图变色龙可就不行了,这时候边缘特征、纹理特征又显得比较有用。而在最后一幅图中,我们很容易把车和轮胎看作是一个整体,但是其实这两者的特征差距真的很明显啊,无论是颜色还是纹理或是边缘都差的太远了。而这这是几种情况,自然图像辣么多,我们通过什么特征去区分?应该区分到什么尺度?

我们无法通过单一的特征去判断一幅图片里的物体类别,selective search的策略是,我们可以先得到小尺度的区域,然后一次次合并得到大的尺寸就好了,并用上我们所知的全部特征。

Selective Search方法希望实现一下三点目标:
1.捕获所有尺寸: 需要考虑到所有对象的比例(使用分层算法)
2.多样性: 采用多种策略去生成候选区域,如前图所示,不用单一的特征去处理
3.速度快: Selective Search方法希望生成一组可能的目标位置,用于实际的目标识别,所以算法应该相对较快。

算法流程

算法的流程如下所示:
在这里插入图片描述
Selective Search方法采用了自下而上的方法生成候选区域,首先将输入图像分割成许多小块的图像,采集每个小图像的区域特征,将最相似的区域组合在一起,再迭代的计算该区域与其相邻区域的新相似性,直到整一个图像成为一个单一的区域,其中每次产生的图像和合并后的图像我们都保存下来,这里需要注意,一种更好的组合方式是:以(a-b-c-d-e-f-g)为例,图像应该较为均匀的发生组合,即(ab-cd-ef-g —> abcd-efg),而不是变成一大块后不断组合小的图像块,如(abcde-f-g)。

计算相似度

为了尽量分割所有场景的图像,我们需要保持算法的多样性,即采用不同的特征去计算相似度,这边文章首先将RGB转换到8个种类的色彩空间(1)RGB,(2)灰度I,(3)Lab,(4)rgI(归一化的rg通道加上灰度),(5)HSV,(6)rgb(归一化的RGB),(7)C,(8)H(HSV的H通道)。

在这里插入图片描述
这里的 +/-表示部分不变性。分数1/3意味着三个颜色通道中有一个是不变的。

计算颜色的距离:
使用L1-norm归一化获取图像每个颜色通道的25 bins的直方图。这样做的话两个区域合并后的直方图也很好计算,直接通过直方图大小加权区域大小然后除以总区域大小就好了。
在这里插入图片描述
计算纹理的距离:
文章使用快速的类似于SIFT的测量方法来表示纹理,具体做法是对每个颜色通道的8个不同方向计算方差σ=1的高斯微分(Gaussian Derivative),使用L1-norm归一化获取图像每个颜色通道的每个方向的10 bins的直方图。

有限组合较小的区域:
在这里插入图片描述
鼓励小区域尽早合并。防止一块大的图像不断组合小图像,那么多尺度仅仅运用在了局部而不是全局,这样保证了整个图像的多样性。

区域的适合度距离:
在这里插入图片描述
衡量区域ri和rj如何适应彼此,合并后的区域要尽量规范,不能合并后出现断崖的区域,如果区域ri包含在rj内,我们首先应该合并,另一方面,如果ri很难与rj相接,他们之间会形成断崖,不应该合并在一块。

最终度量:
在这里插入图片描述
最终度量是将这四种方法组合起来,最简单的方法就是加权相加了。

给区域打分

通过上述的步骤我们能够得到很多很多的区域,但是显然不是每个区域作为目标的可能性都是相同的,因此我们需要衡量这个可能性,这样就可以根据我们的需要筛选区域建议个数啦。

这篇文章做法是,给予最先合并的图片块较大的权重,比如最后一块完整图像权重为1,倒数第二次合并的区域权重为2以此类推。但是当我们策略很多,多样性很多的时候呢,这个权重就会有太多的重合了,排序不好搞啊。文章做法是给他们乘以一个随机数,毕竟3分看运气嘛,然后对于相同的区域多次出现的也叠加下权重,毕竟多个方法都说你是目标,也是有理由的嘛。这样我就得到了所有区域的目标分数,也就可以根据自己的需要选择需要多少个区域了。

特征提取

R-CNN 抽取了一个 4096 维的特征向量,采用的是 Alexnet,我们将生成的候选区域缩放为227227大小后放入Alexnet进行特征提取。(这边R-CNN采用了非常暴力的手段将候选区域缩放为227227大小)

缩放分为两大类(该部分在原文附录A):

1)各向同性缩放,长宽放缩相同的倍数

tightest square with context:
把region proposal的边界进行扩展延伸成正方形,灰色部分用原始图片中的相应像素填补,如下图(B)所示
tightest square without context:
把region proposal的边界进行扩展延伸成正方形,灰色部分不填补,如下图©所示
2)各向异性缩放, 长宽放缩的倍数不同
不管图片是否扭曲,长宽缩放的比例可能不一样,直接将长宽缩放到227*227,如下图(D)所示

在这里插入图片描述

Alexnet结构如图所示:
在这里插入图片描述
Alexnet特征提取部分包含了5个卷积层、2个全连接层,在Alexnet中p5层神经元个数为9216、 f6、f7的神经元个数都是4096,通过这个网络训练完毕后,最后提取特征每个输入候选框图片都能得到一个4096维的特征向量。

这边使用了迁移学习,将预训练后的Alexnet模型去掉全连接层后的输出当做各个候选区域提取出的特征,进行fine-tuning训练时,网络优化求解时采用随机梯度下降法,学习率大小为0.001。通过候选区域对预训练的CNN模型进行fine-tuning训练,将输出层替换为N+1层(N为需要的分类数,最后加一层背景就是N+1),在每次训练的时候,我们batch size大小选择128,其中32个为正样本、96个为负样本。

此处还需要讨论一个问题,就是怎么判断候选区域是将对象的一部分包括在内还是完全包括了对象,这边作者作者测试了IOU阈值各种方案数值0,0.1,0.2,0.3,0.4,0.5。最后通过训练发现,如果选择IOU阈值为0.3效果最好,通过IOU将候选区域与ground true进行比较,当其重叠区域IOU小于0.3时,将其标注成负样本,IOU大于0.7标注为正样本,这里可能会出现正负样本数量差距过大的问题。

类别判定

由于设置了IOU阈值不同,数据就不够准确导致softmax效果并不好,所以作者使用了SVM方法来分类,我们为每个类别训练一个二分类的SVM分类器,如判断是汽车还是背景,提取出的2000个候选区域就能得到2000 * 4096大小的特征矩阵,我们将SVM的矩阵大小设置为4096 * N(N为分类数量或者是SVM数量),就能得到所有region proposals的对于这N类的分数。再对这些region proposals进行NMS(非极大值抑制)去除多余的region proposals。

这里是c++代码写的NMS:

struct Nms_Boxs
{
   
	Rect box;
	int confident;
	int index;
};

float iou_cal(Rect box1, Rect box2) {
   
	float x1 = max(box1.x, box2.x);
	float y1 = max(box1.y, box2.y);
	float x2 = min(box1.x + box1.width - 1, box2.x + box2.width - 1);
	float y2 = min(box1.y + box1.height - 1, box2.y + box2.height - 1);
	
	float inter_width, inter_height;
	inter_width = max(0, x2 - x1 + 1);
	inter_height = max(0, y2 - y1 + 1);

	float inter_area, union_area;
	inter_area = inter_width * inter_height;
	union_area = box1.height*box1.width + box2.height*box2.width - inter_area;

	return inter_area / union_area;
}

void NMS(vector<Rect> boxs, vector<float> confidents, int thre_confident, int thre_iou, vector<
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员毛师傅

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值