R-CNN目标检测模型被称为将卷积神经网络引入目标检测的开山之作,尽管现在看来其性能早已达不到应用的标准,但是它的一些设计思想至今仍具有学习的意义。
〇、 相关博客
- 选择搜索算法:选择搜索(Selective Search)算法介绍与Python实现解释
- 边框回归:边框回归(Bounding Box Regression)算法解释
IoU与非极大抑制:非极大抑制(NMS)算法原理与Python实现
一、R-CNN
R-CNN,全称Region CNN,即区域卷积神经网络。其进行目标检测的主要思想就是生成可能存在目标的候选区域region proposal,然后通过CNN、分类器等手段判断区域中是否存在检测目标,并进行分类。最后再对识别出目标的区域范围进行精细的调整即可。
R-CNN进行目标识别主要分为四个步骤:
- 生成候选区域:生成大约
1000~2000个候选区域以进行识别 - 提取特征:使用
CNN提取每个候选区域的特征向量 - 区域分类:使用
SVM根据特征向量对区域进行分类 - 边框修正:使用边框回归
Bounding Box Regression对检测框进行调整

二、生成候选区域
R-CNN在生成候选区域时选择了比传统的滑动窗口性能更好的选择搜索算法Selective Search。
选择搜索算法的主要思想和python实现我已经在另一篇博客"选择搜索(Selective Search)算法介绍与Python实现解释"中进行了详细的介绍,此处不再赘述。
通过选择搜索算法,模型能够在原图上提取出1000~2000个可能包含检测目标的候选区域,这些区域的位置信息和大小信息以如下形式返回:
regions = [[x, y, w, h], ...]
# x: 候选区域中心点横坐标
# y: 候选区域中心点纵坐标
# w: 候选区域宽度
# h: 候选区域高度
三、特征提取
将每个候选区域输入卷积神经网络便可以提取出这个区域的特征向量。R-CNN论文发表时所采用的网络为AlexNet,初始权重也直接采用了当时AlexNet的训练结果,其结构如下:

AlexNet输入图像的尺度都是固定的,然而候选区域的大小形状缺并不唯一,为了能够将不同的候选区域输入同一个CNN,一般可以采取以下两种做法:
- 各向异性缩放:所谓各向异性缩放就是直接通过
resize函数将图像缩放到指定的大小。这种做法十分简单,缺点时可能导致图像的形状特征被破坏 - 各向同性缩放:考虑到各向异性缩放的缺点,各向同性缩放采用裁剪于扩充两种方式将图像缩放到指定的大小。裁剪就是剪切掉图像的部分区域来缩小图像,扩充则是用固定颜色的背景对图像进行填充以增大图像
除了缩放,R-CNN论文中还为图像增加了padding(这个概念和CNN中的padding一样),通过实验,对候选区域采用各向异性缩放并且padding为16时,模型效果最优。
四、区域分类
区域分类的样本是CNN提取出的区域特征向量,采用的分类模型是SVM,那么每个样本的标签从何而来呢?
候选区域生成算法生成的候选区域有1000~2000个,并且每张图像生成的候选区域都不一样,所以肯定无法人为进行标注。R-CNN最终采取的策略是,如果候选区域与人工标注的少量检测框的交并比Intersection over Union, IoU大于某个阙值,就将其判为正例,否则判定为反例。这个阙值的取值通过论文作者的实验,最终建议取值为0.3。(关于交并比的解释详见博客"非极大抑制(NMS)算法原理与Python实现")
准备好训练数据后,便可以针对每一个类别训练一个二分类SVM,通过多个SVM的输出结果便可以知道输入特征向量对应的候选区域中是否存在某种物体。
五、边框修正
通过SVM分类得到的预测框虽然能够正确判定框中的检测物体,但是其预测框与真实框的IoU却可能很低,例如:

为了提高模型识别目标的准确率,此时就需要对检测框进行一定程度上的修正,即使用边框回归Bounding Box Regression对检测框进行微调。关于边框回归算法的解释详见我的另一片博客"边框回归(Bounding Box Regression)算法解释"。简而言之,边框回归算法通过学习对预测框的平移参数和缩放参数,可以尽可能让预测框更加接近于真实框。
六、简化输出:非极大抑制
通过上述的四个步骤,R-CNN的目标检测任务就基本完成了,此时模型已经能够输出一些较为精准的检测框,例如:

但是,不难发现,此时R-CNN的输出似乎总是会产生一些冗余。在上图的示例输出中,就出现了多个检测框检测同一个目标的情况。这种情况可以通过对输出进行非极大抑制Non-Maximum Suppression, NMS解决。
所谓非极大抑制,顾名思义,就是对检测准确率不高的检测框的输出进行抑制,从而达到缩减输出检测框数量并清除冗余的目的。关于非极大抑制算法的详细说明和python实现详见博客"非极大抑制(NMS)算法原理与Python实现"。
进行NMS后,模型的输出如下:
