選擇性搜索算法 (Selective Search)

引言

計算機視覺領域有幾個基本的任務:

  • object recognition:物體識別,即在給定的圖片中辨認出其中的物體種類,例如貓,飛機,行人等。這里的輸入是整個圖片,輸出是類別標簽以及相應的概率(自信度)。
  • image classification = object recognition
from [https://github.com/apache/incubator-mxnet/tree/master/example/image-classification]
  • object detection: 物體檢測,不僅要識別圖片中的物體,還要定位 (localization),即用 bounding box 將物體圈出來。如果圖片中有多個物體,則每個物體都要有對應的 bounding box 和識別出的類型標簽。
from https://medium.com/synapse-blog/tech-deep-dive-object-detection-ensembles-as-graph-cliques-a7f7d33b5477

object detection 的基礎是 object recognition,只不過要先將圖片進行分割,對每個分割之后的子圖區域 region (也稱為 patch) 進行 object recognition.

由于事先并不知道物體在圖片的哪個位置,為了避免漏檢,我們應該對圖片中盡量多的 region 進行搜索。理論上來說,可以有無窮多個 region。這里就需要一種 region proposal 的算法,以比較高效的方式提出圖片劃分 region 的方式,從而加速整個 object detection 的過程并且提高準確率。

本文將要介紹的 selective search 算法,是比較經典的,也是 R-CNN 中使用的 region proposal 算法。

參考文獻:

  1. original paper by Uijlings et al
  2. https://www.learnopencv.com/selective-search-for-object-detection-cpp-python/

基本思想

為了避免蠻力搜索,selective search 算法首先需要一個基于像素的圖像分割。這里用的是 Felzenszwalb and Huttenlocher 算法 (因為是當時速度最快的算法,而且是公開的),得到一個 oversegmented 的圖像分割。例如:

oversegmented.png

這里之所以用 oversegmented 圖像,是為了得到盡可能細分的區域,再以此為基礎逐步合并,形成更大的區域。

image segmentation 可以用作 region proposal 的基礎,每個分割的區域都可以看作一個潛在的 region,但是一個 object 往往包含了多個分割的區域,例如盛有咖啡的杯子,咖啡和杯子應該作為一個整體來看待。因此,還要根據某種相似性原則進行分割區域的合并,得到更大范圍的 region。

Selective search 算法考慮了 4 種相似性度量,取值都在 [0,1] 之間,越大越相似。

  • 顏色相似性 s_{colour}(r_i, r_j)
  • 紋理相似性 s_{texture}(r_i, r_j)
  • size 相似性 s_{size}(r_i, r_j),促使小的區域之間優先合并
  • shape 相似性 s_{fill}(r_i, r_j),合并只能在緊鄰的兩個區域間進行,遠離的兩個區域不能合并

最終的相似性度量是上述四個度量的組合:
s(r_i, r_j) = a_1\times s_{colour}(r_i, r_j) + a_2\times s_{texture}(r_i, r_j) + a_3 \times s_{size}(r_i, r_j) + a_4 \times s_{fill}(r_i, r_j)
其中 a_k 取 0 或 1.

總結起來,selective search 的算法步驟非常簡單:

  1. 基于 oversegmented 得到細分的區域,作為初始的 region 集合。
  2. 計算 region 兩兩之間的相似性,合并具有最大相似性的兩個 region,得到新的更大的 region,加入 region 集合中。
  3. 重復 step 2,直到整幅圖只剩一個 region。至此,得到的 region 集合就是算法的輸出。
hierarchical-segmentation-1.jpg

實例程序

環境配置:

  • opencv >= 3.3,本機用的 4.1.0 版本
  • 安裝 opencv-contrib-python package
    pip install opencv-contrib-python --user
    
  • 測試用的圖片如下:


    from https://people.com/pets/dog-breeds-diversity-verses-cats-breeds-explainer/

具體程序:

import sys
import cv2
 
# 讀取照片,這里要根據具體情況設置路徑
im = cv2.imread("./pic/cats-dogs.jpg")

# 重置圖片大小,高設置為 400,保持高、寬比例
newHeight = 400
newWidth = int(im.shape[1]*400/im.shape[0])
im = cv2.resize(im, (newWidth, newHeight))    

# 創建 Selective Search Segmentation 對象
ss = cv2.ximgproc.segmentation.createSelectiveSearchSegmentation()

# 添加待處理的圖片
ss.setBaseImage(im)

# 可以選擇快速但是低 recall 的方式 
# 這里的 recall 指的是選擇出來的 region 是否包含了所有應該包含的區域。recall 越高越好
#ss.switchToSelectiveSearchFast()

# 也可以選擇慢速但是高 recall 的方式
ss.switchToSelectiveSearchQuality()


# 進行 region 劃分,輸出得到的 region 數目
rects = ss.process()
print('Total Number of Region Proposals: {}'.format(len(rects)))

# 設定要顯示的 region 數目
numShowRects = 100

# 可以通過按鍵逐步增加或者減少顯示的 region 數目
increment = 50

while True:
    # 不要在原圖上畫 bounding box,而是復制一個新圖
    imOut = im.copy()

    # 遍歷 regions
    for i, rect in enumerate(rects):
        # 通過 bounding box 顯示出指定數量的 region
        if (i < numShowRects):
            x, y, w, h = rect  # bounding box 左上角坐標 x,y, 以及 box 的寬和高
            cv2.rectangle(imOut, (x, y), (x+w, y+h), (0, 255, 0), 1) # 綠色 box,線寬為 1
        else:
            break

    # 顯示圖片+bbox
    cv2.imshow("Output", imOut)

    # 接收按鍵輸入
    k = cv2.waitKey(0) & 0xFF

    # “m” 鍵 is pressed
    if k == 109:
        # 增加顯示的 bbox 數目
        numShowRects += increment
    # “l” 鍵 is pressed
    elif k == 108 and numShowRects > increment:
        # 減少顯示的 bbox 數目
        numShowRects -= increment
    # “q” 鍵 is pressed
    elif k == 113:  
        break
# close image show window
cv2.destroyAllWindows()

最后效果如下:


regions.png

顯示的 100 個 region 已經包含了我們感興趣的待檢測區域,說明了 selective search 算法的高效。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。