目标检测之选择性搜索算法实现(符动图演示)

定义

选择性搜索是在对象检测中使用的区域提议算法。它的设计速度很快,召回率很高。它基于基于颜色,纹理,大小和形状兼容性的相似区域的分层分组计算。

操作步骤

  1. 首先使用 Felzenszwalb 和 Huttenlocher 基于图像的分割方法
  2. 对分割的图像进行超像素的合并,合并彼此相似的相邻区域 ,合并的规则包括颜色相似度、纹理相似度、尺寸相似度、形状相似性等

自下而上的方法创建了从较小细分到较大细分的区域建议 ,如下图所示

image

合并规则

  • 颜色相似度

计算图像每个通道的 25 个 bins 的颜色直方图,并将所有通道的直方图连接起来,得到 25×3 = 75 维的颜色描述符(归一化)。

image

其中
image

代表两块区域,
image
代表第 i 块区域直方图中第 k 个 bins 的颜色描述符,以上公式表示
image
两块区域的 n=75 维颜色描述符完全一致的话(就是两块区域的 75 维直方图一对一完全相同)那么说明这两块区域的颜色完全相同,可以进行合并
  • 纹理相似度

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

image

以上的公式与颜色相似度的计算公式指代的意义差不多,都是计算每块区域的纹理特征,再比较不同区域的纹理相似度

  • 尺寸相似度

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

image

上面的公式表示,两个区域越小,其相似度越大,越接近 1。 size(im) 计算的是图片的像素个数

  • 形状相容性
image

形状兼容性可衡量两个区域相互配合的程度,如果匹配则进行合并,如果它们接触都没有,则不合并

  • 最终相似度

最终相似度就是在上面四个相似度的基础上添加一个权重来计算最终相似度,公式如下:

image

代码实现

先上效果:

image

在 OpenCV 中,提供了一个选择性搜索的接口供我们使用,这个模块是在 OpenCV 扩展模块包opencv-contrib-python 里面

首先需要进行安装 pip install opencv-contrib-python

所有代码都进行了注释,这里就不在赘述

#!/usr/bin/env python
'''
安装依赖
!pip install opencv-python
!pip install opencv-contrib-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
    
    # speed-up using multithreads
    cv2.setUseOptimized(True);
    cv2.setNumThreads(4)  # 设置线程数
 
    # read image
    path = "F:/jupyter/Dive-into-DL-PyTorch/docs/img/cat1.jpg"
    im = cv2.imread(path)
    
    # resize image 重置大小
    newHeight = 2000
    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)
    
    
    model = "f"   # 快速模式 f 还是 高召回率模式 q
    # 三种模式,参考
    # https://docs.opencv.org/3.4/d6/d6d/classcv_1_1ximgproc_1_1segmentation_1_1SelectiveSearchSegmentation.html
    
    # Switch to fast but low recall Selective Search method
    # 快速模式,但是意味着低召回率
    if (model == 'f'):
        ss.switchToSelectiveSearchFast()
 
    # Switch to high recall but slow Selective Search method
    # 高召回率模式,但是速度较慢
    elif (model == 'q'):
        ss.switchToSelectiveSearchQuality()
    elif (model == "ToString"):
        ss.switchToSingleStrategy()
    # if argument is neither f nor q print help message
    else:
        print("plase set model!")
 
    # 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 = 10
    # increment to increase/decrease total number of reason proposals to be shown
    increment = 20
 
    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)
        cv2.imwrite("Output.jpg", imOut)

        # record key press 
        k = cv2.waitKey(0) & 0xFF
        # m is pressed  m  键增加要显示的矩形框数
        if k == 109:
            # increase total number of rectangles to show by increment
            numShowRects += increment
            
        # l is pressed  l 键减少要显示的矩形框数
        elif k == 108 and numShowRects > increment:
            # decrease total number of rectangles to show by increment
            numShowRects -= increment
            
        # q is pressed  q 键退出
        elif k == 113:
            break
            
    # close image show window
    cv2.destroyAllWindows() 

参考:

  • https://www.learnopencv.com/selective-search-for-object-detection-cpp-python/

  • http://cs.brown.edu/~pff/segment/

你可能感兴趣的:(目标检测之选择性搜索算法实现(符动图演示))