候選區域(Region Proposal)算法
滑窗法的問題可以使用候選區域產生算法解決。這些算法輸入整張圖片,然後輸出可能有物體的候選區域位置,這些候選區域可以有噪聲或者重疊,或者和物體的重合度不是很好,這都不要緊,只要這些區域裏有一個和實際物體的位置足夠接近就行。因爲不好的候選區域會被物體識別算法過濾掉。
候選區域算法用分割不同區域的辦法來識別潛在的物體。在分割的時候,我們要合併那些在某些方面(如顏色、紋理)類似的小區域。相比滑窗法在不同位置和大小的窮舉,候選區域算法將像素分配到少數的分割區域中。所以最終候選區域算法產生的數量比滑窗法少的多,從而大大減少運行物體識別算法的次數。同時候選區域算法所選定的範圍天然兼顧了不同的大小和長寬比。
候選區域算法比較重要的特徵就是要有較高的召回率。我們要通過這種方法保證擁有物體的區域就在候選區域列表裏。所以我們不介意有很多區域什麼都有,這都沒關係,物體檢測算法會過濾掉他們,雖然會浪費一點時間。
物體檢測之選擇性搜索(Selective Search)
選擇性搜索算法用於爲物體檢測算法提供候選區域,它速度快,召回率高。
選擇性搜索算法需要先使用《Efficient Graph-Based Image Segmentation》論文裏的方法產生初始的分割區域,然後使用相似度計算方法合併一些小的區域。
下列兩張圖分別是原圖和原始分割圖:
我們不能使用原始分割圖的區域作爲候選區域,原因如下:
- 大部分物體在原始分割圖裏都被分爲多個區域
- 原始分割圖無法體現物體之間的遮擋和包含。
如果我們試圖通過進一步合併相鄰的區域來解決第一個問題,我們最終會得到一個包含兩個對象的分段區域。
我們不要需要完美的的分割區域,我們只想要和實際物體高度重合的區域就行了。
選擇性搜索算法使用《Efficient Graph-Based Image Segmentation》論文裏的方法產生初始的分割區域作爲輸入,通過下面的步驟進行合併:
- 首先將所有分割區域的外框加到候選區域列表中
- 基於相似度合併一些區域
- 將合併後的分割區域作爲一個整體,跳到步驟1
通過不停的迭代,候選區域列表中的區域越來越大。可以說,我們通過自底向下的方法創建了越來越大的候選區域。表示效果如下:
相似度
選擇性搜索算法如何計算兩個區域的像素度的呢?
主要是通過以下四個方面:顏色、紋理、大小和形狀交疊
最終的相似度是這四個值取不同的權重相加
效果
opencv實現了選擇性搜索算法,可以給出上千個根據有物體的可能性降序排列的候選區域。
下圖是畫出了前面250個候選區域的效果。一般來說。1200個候選區域基本能勝任物體檢測的任務了。
opencv中的實現-python版本
代碼主要參考《Selective Search for Object Detection (C++ / Python)》
#!/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__':
# speed-up using multithreads
cv2.setUseOptimized( True );
cv2.setNumThreads( 4 );
# read image
im = cv2.imread( './test.jpg' )
# 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 )
if 1:
# Switch to fast but low recall Selective Search method
ss.switchToSelectiveSearchFast()
else:
# Switch to high recall but slow Selective Search method
ss.switchToSelectiveSearchQuality()
# 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()