基于Python的OpenCV輪廓檢測聚類
點(diǎn)擊上方“小白學(xué)視覺”,選擇加"星標(biāo)"或“置頂”
重磅干貨,第一時(shí)間送達(dá)
OpenCV的“findContours”功能經(jīng)常被計(jì)算機(jī)視覺工程師用來檢測物體。OpenCV的存在,使得我們只需要編寫幾行代碼就可以檢測輪廓(對象)。然而,OpenCV檢測到的輪廓通常是分散的。例如,一個(gè)功能豐富的圖像可能有數(shù)百到數(shù)千個(gè)輪廓,但這并不意味著圖像中有那么多對象。一些屬于同一對象的輪廓是單獨(dú)檢測的,因此我們感興趣的是對它們進(jìn)行分組,使一個(gè)輪廓對應(yīng)一個(gè)對象。
當(dāng)我在項(xiàng)目中遇到這個(gè)問題時(shí),我花了很多時(shí)間嘗試使用不同的參數(shù)或不同的OpenCV函數(shù)來檢測輪廓,但沒有一個(gè)有效。然后,我做了更多的研究,在OpenCV的論壇上找到了一篇帖子,它提到了凝聚聚類。但是,沒有給出源代碼。我還發(fā)現(xiàn)sklearn支持聚合聚類,但我沒有使用它,原因有兩個(gè):
這個(gè)功能對我來說似乎很復(fù)雜。我不知道如何輸入正確的參數(shù),我懷疑輪廓檢測的數(shù)據(jù)類型是否適合該函數(shù)。 我需要使用python 2.7、OpenCV 3.3.1和Numpy 1.11.3。它們與sklearn的版本(0.20+)不兼容,后者支持聚類。
為了分享我編寫的函數(shù),我在Github中對其進(jìn)行了開源,并將其作為要點(diǎn)發(fā)布在下面。以下版本適用于Python3,若需要要在Python2.7中使用它,只需將“range”更改為“xrange”。
#!/usr/bin/env python3import osimport cv2import numpydef calculate_contour_distance(contour1, contour2):x1, y1, w1, h1 = cv2.boundingRect(contour1)c_x1 = x1 + w1/2c_y1 = y1 + h1/2x2, y2, w2, h2 = cv2.boundingRect(contour2)c_x2 = x2 + w2/2c_y2 = y2 + h2/2return max(abs(c_x1 - c_x2) - (w1 + w2)/2, abs(c_y1 - c_y2) - (h1 + h2)/2)def merge_contours(contour1, contour2):return numpy.concatenate((contour1, contour2), axis=0)def agglomerative_cluster(contours, threshold_distance=40.0):current_contours = contourswhile len(current_contours) > 1:min_distance = Nonemin_coordinate = Nonefor x in range(len(current_contours)-1):for y in range(x+1, len(current_contours)):distance = calculate_contour_distance(current_contours[x], current_contours[y])if min_distance is None:min_distance = distancemin_coordinate = (x, y)elif distance < min_distance:min_distance = distancemin_coordinate = (x, y)if min_distance < threshold_distance:index1, index2 = min_coordinatecurrent_contours[index1] = merge_contours(current_contours[index1], current_contours[index2])del current_contours[index2]else:breakreturn current_contours
注意:
“calculate_contour_distance”函數(shù)獲取輪廓的邊界框,并計(jì)算兩個(gè)矩形之間的距離。
“merge_contours”函數(shù),我們只需使用'numpy.concatenate'即可,因?yàn)槊總€(gè)輪廓只是一個(gè)點(diǎn)的numpy數(shù)組。
使用聚類算法,我們不需要事先知道有多少個(gè)聚類。相反,可以向函數(shù)提供閾值距離,例如40個(gè)像素,因此如果所有輪廓中最近的距離大于閾值,則函數(shù)將停止處理。
要可視化集群效果,請參見下面的兩幅圖像。第一幅圖像顯示最初檢測到12個(gè)輪廓,聚類后只剩下4個(gè)輪廓,如第二幅圖像所示。這兩個(gè)小對象是由于噪聲造成的,它們沒有合并,因?yàn)榕c閾值距離相比,它們離太遠(yuǎn)。


GITHUB代碼鏈接:
https://github.com/CullenSUN/fish_vision/blob/master/obstacle_detector_node/src/opencv_utils.py交流群
歡迎加入公眾號讀者群一起和同行交流,目前有SLAM、三維視覺、傳感器、自動駕駛、計(jì)算攝影、檢測、分割、識別、醫(yī)學(xué)影像、GAN、算法競賽等微信群(以后會逐漸細(xì)分),請掃描下面微信號加群,備注:”昵稱+學(xué)校/公司+研究方向“,例如:”張三?+?上海交大?+?視覺SLAM“。請按照格式備注,否則不予通過。添加成功后會根據(jù)研究方向邀請進(jìn)入相關(guān)微信群。請勿在群內(nèi)發(fā)送廣告,否則會請出群,謝謝理解~

