微信公众号:AI那点小事 作者:戴璞微 知乎专栏:AI那点小事 CSDN博客:https://daipuweiai.blog.csdn.net/ 原文链接:https://zhuanlan.zhihu.com/p/76597921 https://daipuweiai.blog.csdn.net/article/details/96134725
在刚刚过去的一个学期里,基本水逆了一整个学期,这学期基本没干什么活,就跟RCNN杠上了。首先是看论文,然后是网上找tensorflow写好的源码。但是,可惜的是网上给出的源码基本上是RCNN的主要作者Ross Girshick大神的代码,不同数据集换了下。因此为了理解源码,RCNN的处理过程,费劲去装了个ubuntu和win10的双系统并在Ubuntu上安装caffe,这就花费了近2周的时间。快速研究完RCNN的caffe源码之后,才转过来手写Fast RCNN的tensorflow版本的代码,这也花费了大量的时间,从踩坑到填坑再到踩坑。RCNN不是很好实现,SVM至今还没怎么看懂。接下来将会陆续更新RCNN->Fast RCNN->Faster RCNN系列的文章。在这篇文章中,主要讲解RCNN与Fast RCNN中获取图片中物体真实目标检测框的算法——选择性搜索算法。
在R-CNN中架构的第一步是要寻找推荐区域(Region Proposal),也就是找出可能的感兴趣区域(Region Of Interest, ROI)。获取推荐区域的方法有下三种,分为:滑动窗口、规则块和选择性搜索。
第一种就是滑动窗口。滑动窗口本质上就是穷举法,利用不同的尺度和长宽比把所有可能的大大小小的块都穷举出来,然后送去识别,识别出来概率大的就留下来。很明显,这样的方法复杂度太高,产生了很多的冗余候选区域,在现实当中不可行。
第二种是规则块。在穷举法的基础上进行了一些剪枝,只选用固定的大小和长宽比。但是对于普通的目标检测来说,规则块依然需要访问很多的位置,复杂度高。
第三种是选择性搜索。从机器学习的角度来说,前面的方法召回是不错了,但是精度差强人意,所以问题的核心在于如何有效地去除冗余候选区域。其实冗余候选区域大多是发生了重叠,选择性搜索利用这一点,自底向上合并相邻的重叠区域,从而减少冗余。
选择性搜索相关论文早在2012年发表于IJCV会议,论文名为:Selective Search for Object Recognition,下载地址为:https://ivi.fnwi.uva.nl/isis/publications/2013/UijlingsIJCV2013/UijlingsIJCV2013.pdf。由于这篇论文不单单讲解了选择性搜索,因此,我对论文中选择性搜索相关内容进行总结。选择性搜索的算法流程如下:
从图中可以看出,选择性搜索输入的是彩色图像,输出为候选的目标边界框集合。选择性搜索主要流程主要分成以下几个步骤:
,并初始化相似性度量集合
。
集合。
集合,计算区域
和区域
相似性度量,并把这个相似性度量加入
。
为空的情况下,进行循环处理。在循环中首先找到相似性最大的对应的区域对
。然后将区域
和区域
合成记作
。之后从
删除与区域
相邻的其他区域的相似性度量、与区域
邻的区域的相似性度量。接着计算区域 与其相邻的区域之间的相似性度量并加入
。最后也把区域
加入
。
在论文中,相似性度量主要使用了颜色相似度、纹理相似度、大小相似度和吻合相似度。下面我们一一进行介绍。
计算每个图像每个颜色通道的25 bins的直方图并将其进行L1-norm归一化,这样每个区域都可以得到一个75维的向量
。两个区域之间的每个通道的颜色相似度计算如下所示:
由于
是归一化后值,每一个颜色通道的直方图累加和为1.0,三个通道的累加和就为3.0,如果区域
和区域直方图完全一样,则此时颜色相似度最大为3.0;如果不一样,由于累加取两个区域bin的最小值进行累加,当直方图差距越大,累加的和就会越小,即颜色相似度越小。
在区域合并过程中使用需要对新区域
颜色直方图
的计算公式如下:
其中,
代表区域
内像素大小。
纹理相似度采用的是SIFT-Like特征。具体做法是计算每个颜色通道的8个不同方向的方差
的高斯微分(Gaussian Derivative),使用L1-norm归一化获取图像每个颜色通道的每个方向的10 bins的直方图,这样就可以获取到一个
维的向量
,区域之间纹理相似度计算方式和颜色相似度计算方式类似,计算公式如下:
合并之后新区域
纹理直方图
计算公式和颜色直方图计算公式比较类似,计算公式如下所示:
加入仅仅是使用颜色和纹理特征进行合并的话,这就会很容易造成合并后的大区域不断吞并周围的小区域。这样做的后果就是多尺度只应用于局部,而不是全局的多尺度。因此比较合理的思路就是优先进行小区域之间的合并,即赋予小区域更大的权重,这就是大小相似度。大小相似度的计算公式如下:
其中
为原始图像的像素个数。显然,可以从上式看出,两个区域越小,其相似度越大且越接近于1。即该大小相似度保证合并操作的尺度较为均匀,避免一个大区域陆续“吃掉”其他小区域。
下面介绍最后一个相似度——吻合相似度。如果区域
含在区域
,我们首先应该合并;另一方面,如果区域
难与区域
相接,他们之间会形成断崖,不应该合并在一块。这里定义区域的吻合相似度主要是为了衡量两个区域是否更加“吻合”,其指标是合并后的区域的边界框(Bounding Box)越小,其吻合度越高,即相似度越接近1。其计算方式如下:
其中,
图像未被区域
和区域
覆盖区域的像素大小。那么选择性搜索的相似性度量计算公式如下所示:
其中
。在实际计算时我们将
都取1。
上面介绍了选择性搜索算法流程以及相关细节,由于选择性搜索算法已经有人利用python实现,并且已经开源。那么,我们要做的就是利用Anaconda安装相关源代码后利用即可。在Anaconda的Prompt中输入以下命令即可安装选择性搜索的python库文件:
pip install selectivesearch
接下来我们,我们利用安装好的选择行搜索(selectivesearch)库对图片进行分割目标框。具体代码如下:
# -*- coding: utf-8 -*-
from __future__ import (
division,
print_function,
)
import skimage.data
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
import selectivesearch
def main():
# loading astronaut image
img = skimage.data.astronaut()
# perform selective search
img_lbl, regions = selectivesearch.selective_search(
img, scale=500, sigma=0.9, min_size=10)
candidates = set()
for r in regions:
# excluding same rectangle (with different segments)
if r['rect'] in candidates:
continue
# excluding regions smaller than 2000 pixels
if r['size'] < 2000:
continue
# distorted rects
x, y, w, h = r['rect']
if w / h > 1.2 or h / w > 1.2:
continue
candidates.add(r['rect'])
# draw rectangles on the original image
fig, ax = plt.subplots(ncols=1, nrows=1, figsize=(6, 6))
ax.imshow(img)
for x, y, w, h in candidates:
print(x, y, w, h)
rect = mpatches.Rectangle(
(x, y), w, h, fill=False, edgecolor='red', linewidth=1)
ax.add_patch(rect)
plt.show()
if __name__ == "__main__":
main()
结果如下所示:
接下来对 selectivesearch.selective_search(im_orig, scale=1.0, sigma=0.8, min_size=50)函数进行解析。首先是函数参数说明:
接下来是selectivesearch.selective_search函数的返回值为[r,g,b,(region)],实际操作时,我们通常得到的是[r,g,b]即RGB三个通道组成的原始图像,以及区域字典数组。格式如下:
[ { 'rect': (left, top, width, height), 'labels': […], 'size': component_size }, … ]
也就是说,"rect"返回的区域在原始图像中左上顶点的x坐标、右下顶点的y坐标、和区域的宽度和高度。
为了更加深刻地理解RCNN算法,在下一篇文章的将会主要讲解RCNN模型中另一个重要模块——用于微调候选目标框的边界框回归(Bounding-Box Regression)算法。