Selective Search

在目标检测学习系列的文章中,很多检测算法都会涉及到Selective Search的使用,比如R-CNN。本文介绍Selective Search
参考:

简介

Selective Search是一种用于目标检测的区域建议算法。它的设计速度快,召回率高。它基于颜色、纹理、大小和形状相容性计算相似区域的层次分组。

Selective Search首先使用Felzenszwalb和Huttenlocher的基于图的分割方法,根据像素的强度对图像进行过分割。算法输出如下图所示。右边的图像包含用纯色表示的分割区域。
image

Selective Search方法主要有三个优势: 捕捉不同尺度(Capture All Scales)、多样化(Diversification)、快速计算(Fast to Compute)总结为:选择性搜索是用于目标检测的区域提议算法,它计算速度快,具有很高的召回率,基于颜色,纹理,大小和形状兼容计算相似区域的分层分组。Selective Search算法主要包含两个内容:Hierarchical Grouping Algorithm、Diversification Strategies。

Hierarchical Grouping Algorithm

图像中区域特征比像素更具代表性,HGA产生图像初始区域,使用贪心算法对区域进行迭代分组:

  1. 计算所有邻近区域之间的相似性;
  2. 两个最相似的区域被组合在一起;
  3. 计算合并区域和相邻区域的相似度;
  4. 重复2、3过程,直到整个图像变为一个地区。

在每次迭代中,形成更大的区域并将其添加到区域提议列表中。以自下而上的方式创建从较小的细分segments到较大细分segments的区域提案,如下图。
image

Diversification Strategies

这个部分讲述作者提到的多样性的一些策略,使得抽样多样化,主要有下面三个不同方面:

  1. 利用各种不同不变性的色彩空间;
  2. 采用不同的相似性度量;
  3. 改变起始区域

相似性的度量指标:

1. 颜色相似度

这里用25个bin的颜色直方图,对于3通道的图片,就是\(25*3=75\)个bin

\(s_{color}(r_i, r_j) = \sum_{k=1}^n min(c^k_i, c^k_j)\)

这里\(c_i^k\)是第k个bin的直方图描述子

2. 纹理相似度

纹理特征通过提取每个通道在8个方向上的高斯导数来计算。对于每个方向和每个颜色通道,一个10-bin直方图被计算成一个10x8x3 = 240维特征描述符。

利用直方图相交计算两个区域的纹理相似度。

\(s_{texture}(r_i, r_j) = \sum_{k=1}^n min(t^k_i, t^k_j)\)

\(t^k_i\)是纹理描述符中\(k^{th}\) bin的直方图值

3. 尺寸相似度

大小相似性鼓励较小的区域尽早合并。它确保在图像的所有部分形成所有尺度的区域建议。如果不考虑这种相似性度量,单个区域将会一个接一个地吞噬所有较小的相邻区域,因此只会在这个位置产生多个尺度的区域建议。大小相似度定义为:

\(s_{size}(r_i, r_j) = 1 - \frac{size(r_i) + size(r_j)}{size(im)}\)

其中size(im)为图像像素大小。

4. 形状重合度

形状相容性衡量两个区域(\(r_i\)\(r_j\))相互适应的程度。如果\(r_i\)适合\(r_j\),我们想要合并它们以填补空白,如果它们甚至没有相互接触,它们就不应该被合并。

形状相容性定义为:
\(s_{fill}(r_i, r_j) = 1 - \frac{size(BB_{ij}) - size(r_i) - size(r_j)}{size(im)}\)

其中\(size(BB{ij})\)是一个围绕\(r_i\)\(r_j\)的边界框。

5. 最终重合度

最终重合度是上述4个重合度加权的结果:

\((r_i, r_j) = a_1s_{color}(r_i, r_j) + a_2s_{texture}(r_i, r_j) + a_3s_{size}(r_i, r_j)+ a_4s_{fill}(r_i, r_j)\)

python-opencv中的应用

opencv自从3.3.0集成了Selective Search,代码:

#!/usr/bin/env python
'''
Usage:
    ./ssearch.py input_image (f|q)
    f=fast, q=quality
Use "l" to display less rects, 'm' to display more rects, "q" to quit.
'''

import sys
import cv2

if __name__ == '__main__':
    # If image path and f/q is not passed as command
    # line arguments, quit and display help message
    if len(sys.argv) < 3:
        print(__doc__)
        sys.exit(1)

    # speed-up using multithreads
    cv2.setUseOptimized(True);
    cv2.setNumThreads(4);

    # read image
    im = cv2.imread(sys.argv[1])
    # resize image
    newHeight = 200
    newWidth = int(im.shape[1]*200/im.shape[0])
    im = cv2.resize(im, (newWidth, newHeight))    

    # create Selective Search Segmentation Object using default parameters
    ss = cv2.ximgproc.segmentation.createSelectiveSearchSegmentation()

    # set input image on which we will run segmentation
    ss.setBaseImage(im)

    # Switch to fast but low recall Selective Search method
    if (sys.argv[2] == 'f'):
        ss.switchToSelectiveSearchFast()

    # Switch to high recall but slow Selective Search method
    elif (sys.argv[2] == 'q'):
        ss.switchToSelectiveSearchQuality()
    # if argument is neither f nor q print help message
    else:
        print(__doc__)
        sys.exit(1)

    # run selective search segmentation on input image
    rects = ss.process()
    print('Total Number of Region Proposals: {}'.format(len(rects)))

    # number of region proposals to show
    numShowRects = 100
    # increment to increase/decrease total number
    # of reason proposals to be shown
    increment = 50

    while True:
        # create a copy of original image
        imOut = im.copy()

        # itereate over all the region proposals
        for i, rect in enumerate(rects):
            # draw rectangle for region proposal till 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

        # show output
        cv2.imshow("Output", imOut)

        # record key press
        k = cv2.waitKey(0) & 0xFF

        # m is pressed
        if k == 109:
            # increase total number of rectangles to show by increment
            numShowRects += increment
        # l is pressed
        elif k == 108 and numShowRects > increment:
            # decrease total number of rectangles to show by increment
            numShowRects -= increment
        # q is pressed
        elif k == 113:
            break
    # close image show window
    cv2.destroyAllWindows()

效果:
image

posted @ 2022-08-31 21:13  Asp1rant  阅读(161)  评论(0编辑  收藏  举报