目标检测之R-CNN

前言

R-CNN是基于深度学习目标检测的开创之作,是带有CNN特征的区域(Region with CNN features)的缩写,它较之前传统目标检测方法在平均精度上(mAP)提高了30%以上。从本文开始将逐渐介绍R-CNN。

一、R-CNN结构

如图,R-CNN分为三步 :

1、生成候选区域(2000左右)

2、利用CNN对每个候选区域进行特征提取

3、利用SVM分类

二、生成候选区域

R-CNN生成候选区域的方法是使用Selective Search算法。论文地址如下:

http://www.huppelen.nl/publications/selectiveSearchDraft.pdf

在这对该算法进行简单介绍,

生成候选区域大致分为两种方法:

1)穷举搜索

自然而然,我们想到利用大小不同的滑窗遍历整张图片,寻找目标在图片上的位置。但显然这样计算量会很大,而且不会很准确的得到目标位置

2)分割

那能不能考虑目标自身特征呢?图像分割应运而生,它根据灰度、颜色、纹理和形状等图像特征把图像划分成若干互不交迭的区域,并使这些特征在同一区域内呈现出相似性,而在不同区域间呈现出明显的差异性。但是分割常常依赖于一种单一的强算法来识别区域。

而Selective Search结合两者优点生成候选区域。受分割启发,利用图像特征来生成目标位置。受穷举搜索启发,捕捉尽可能多的对象位置。同样,不是使用单一的采样特征,而是使采样特征多样化,以尽可能多地考虑各种图像情况。

结合图具体说明一下:

对于图(a)若使用穷举搜索,目标位置不会很准确,因为目标之间是分层级的,沙拉和勺子在碗中,碗又在桌上。最自然的解决方法是使用分层分区进行分割,但使用一种单一的强算法是行不通的。如在图(b)中两只猫纹理相同,颜色不同。而在图(c)中变色龙和周围颜色相同,而纹理不同。最后在图(d)中,车身和轮胎颜色、纹理都不同,但显然都属于车。而Selective Search算法结合两者优点,先利用分层分区形成初始化很多分割区域,再利用贪心算法,根据多种特征计算区域间相似性,过程不断重复,直至形成一个区域。

文章通过互补的色彩空间转换、互补的相似性计算方式,互补的初始化区域来保证特征的多样性。

互补的相似性计算公式如下:

  1. 颜色距离

根据色彩空间,计算颜色的距离。

距离的计算方式很简单,就是对各个通道计算颜色直方图,然后取各个对应bins的直方图最小值。这样做的话两个区域合并后的直方图也很好计算,直接通过直方图大小加权区域大小然后除以总区域大小就好了。

2.纹理距离

纹理距离计算方式和颜色距离几乎一样,我们计算每个区域的快速sift特征,其中方向个数为8,3个通道,每个通道bins为10,对于每幅图像得到240维的纹理直方图,然后通过上式计算距离。

3.优先合并小的区域

如果仅仅是通过颜色和纹理特征合并的话,很容易使得合并后的区域不断吞并周围的区域,后果就是多尺度只应用在了那个局部,而不是全局的多尺度。因此我们给小的区域更多的权重,这样保证在图像每个位置都是多尺度的在合并。

4.区域的合适度距离

不仅要考虑每个区域特征的吻合程度,区域的吻合度也是重要的,吻合度的意思是合并后的区域要尽量规范,不能合并后出现断崖的区域,这样明显不符合常识,体现出来就是区域的外接矩形的重合面积要大。因此区域的合适度距离定义为:

5.综合各种距离

现在各种距离都计算出来,我们要做的就是整合这些距离,通过多种策略去得到区域建议,最简单的方法当然是加权:

整体算法如下:

 OpenCV实现:

import cv2

if __name__ == '__main__':
    # 读取照片
    filename = 'longmao.png'
    im = cv2.imread(filename)
    # 重塑照片大小
    newHeight = 200
    newWidth = int( im.shape[1] * 200 / im.shape[0] )
    im = cv2.resize( im, (newWidth, newHeight) )
    # 使用Selective Search算法
    ss = cv2.ximgproc.segmentation.createSelectiveSearchSegmentation()
    ss.setBaseImage(im)
    ss.switchToSelectiveSearchFast()

    rects = ss.process()
    #总共的候选区域
    print( 'Total Number of Region Proposals: {}'.format( len( rects ) ) )
    #设定指定边界框数
    numShowRects = 100
    #增加或减少额定的边界框数
    increment = 50

    while True:
        imOut = im.copy()
        # 迭代边界框
        for i, rect in enumerate( rects ):
            #画出numShowRects数量的边界框
            if (i < numShowRects):
                x, y, w, h = rect
                cv2.rectangle(imOut, (x, y), (x + w, y + h), (0, 255, 0), 1, cv2.LINE_AA )
            else:
                break

        cv2.imshow('Output',imOut)
        k = cv2.waitKey(0)
        # m键增加边框数
        if k == 109:
            numShowRects += increment
        # l键减少边框数
        elif k == 108 and numShowRects > increment:
            numShowRects -= increment
        # q键退出
        elif k == 113:
            break
    cv2.destroyAllWindows()

效果如下:

特征提取

R-CNN利用Alexnet网络对候选区域进行特征提取,注意到Alexnet的输入图像大小为227*227,如上图所示,我们生成的候选区域大小是不一样的。在论文中,采用简单粗暴的方法,将所有候选区域统一重塑为227*227。当然这样做肯定会丢失很多图像信息,论文中有这样一个小技巧:区域进行裁剪前,首先对这些区域进行膨胀处理,在其周围附加了 p 个像素,也就是人为添加了边框,在这里 p=16。还有一个问题是,目标标签训练数据少,如果要直接采用随机初始化CNN参数的方法,那么目前的训练数据量是远远不够的,所以会直接采用训练好的网络参数作为初始化参数,再用我们的数据集进行fine-tuning。fine-tuning时只需去掉最后的softmax层,会生成4096维的特征向量

SVM训练

得到特征向量后,我们需要训练SVM。为何要训练SVM呢?直接用CNN的softmax不好吗?因为cnn在训练的时候,对训练数据做了比较宽松的标注,比如一个bounding box可能只包含物体的一部分,那么就把它标注为正样本,用于训练cnn;采用这个方法的主要原因在于因为CNN容易过拟合,所以需要大量的训练数据,所以在CNN训练阶段我们是对Bounding box的位置限制条件限制的比较松(比如IOU只要大于0.5都被标注为正样本了);然而svm训练的时候,因为svm适用于少样本训练,所以对于训练样本数据的IOU要求比较严格,我们只有当bounding box把整个物体都包含进去了,我们才把它标注为物体类别,然后训练svm
假设我们要检测车辆。我们知道只有当bounding box把整量车都包含在内,那才叫正样本;如果bounding box 没有包含到车辆,那么我们就可以把它当做负样本。但问题是当我们的检测窗口只有部分包好物体,那该怎么定义正负样本呢?作者测试了IOU阈值各种方案数值0,0.1,0.2,0.3,0.4,0.5。最后通过训练发现,如果选择IOU阈值为0.3效果最好(选择为0精度下降了4个百分点,选择0.5精度下降了5个百分点),即当重叠度小于0.3的时候,我们就把它标注为负样本。一旦CNN f7层特征被提取出来,那么我们将为每个物体训练一个svm分类器。当我们用CNN提取2000个候选框,可以得到2000*4096这样的特征向量矩阵,然后我们只需要把这样的一个矩阵与svm权值矩阵4096*N点乘(N为分类类别数目,因为我们训练的N个svm,每个svm包好了4096个W),就可以得到结果了。
 

具体代码实现可以参考:

https://github.com/yangxue0827/RCNN

总结

利用Selective Search提取候选框,然后利用CNN进行特征提取,最后训练SVM得出结果。可见R-CNN过程繁琐,而且非常耗时。下节将要介绍对R-CNN的改进算法,spp-net.

参考:

https://blog.csdn.net/hjimce/article/details/50187029

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值