OpenCV入门之寻找图像的凸包(convex hull)
介紹
??凸包(Convex Hull)是一個(gè)計(jì)算幾何(圖形學(xué))中的概念,它的嚴(yán)格的數(shù)學(xué)定義為:在一個(gè)向量空間V中,對(duì)于給定集合X,所有包含X的凸集的交集S被稱(chēng)為X的凸包。
??在圖像處理過(guò)程中,我們常常需要尋找圖像中包圍某個(gè)物體的凸包。凸包跟多邊形逼近很像,只不過(guò)它是包圍物體最外層的一個(gè)凸集,這個(gè)凸集是所有能包圍這個(gè)物體的凸集的交集。如下圖所示:
在上圖中,綠色線條所包圍的凸集即為白色圖形的凸包。
??在opencv中,通過(guò)函數(shù)convexHulll能很容易的得到一系列點(diǎn)的凸包,比如由點(diǎn)組成的輪廓,通過(guò)convexHull函數(shù),我們就能得到輪廓的凸包。尋找圖像的凸包,能夠讓我們做一些有意思的事情,比如手勢(shì)識(shí)別等。
??下面筆者將會(huì)通過(guò)兩個(gè)簡(jiǎn)單例子來(lái)展示如何用OpenCV來(lái)尋找圖像的凸包。
簡(jiǎn)單例子1 幾何圖形
??首先,我們用以下的Python代碼來(lái)自己繪制一張簡(jiǎn)單的多邊形的圖片(polygon.png),代碼如下:
import cv2
import numpy as np
# 新建512*512的空白圖片
img = np.zeros((512,512,3), np.uint8)
# 平面點(diǎn)集
pts = np.array([[200,250], [250,300], [300, 270], [270,200], [120, 240]], np.int32)
pts = pts.reshape((-1,1,2))
# 繪制填充的多邊形
cv2.fillPoly(img, [pts], (255,255,255))
# 保存圖片
cv2.imwrite('F://polygon.png', img)
繪制的圖片如下:
??接著我們需要尋找這個(gè)多邊形的凸包,利用OpenCV的convexHull函數(shù),然后再將這個(gè)凸包繪制出來(lái),得到直觀的展示結(jié)果。處理的Python代碼如下:
import cv2
# 讀取圖片并轉(zhuǎn)至灰度模式
imagepath = 'F://convex.png'
img = cv2.imread(imagepath, 1)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 二值化
ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
# 圖片輪廓
image, contours, hierarchy = cv2.findContours(thresh, 2, 1)
cnt = contours[0]
# 尋找凸包并繪制凸包(輪廓)
hull = cv2.convexHull(cnt)
print(hull)
length = len(hull)
for i in range(len(hull)):
cv2.line(img, tuple(hull[i][0]), tuple(hull[(i+1)%length][0]), (0,255,0), 2)
# 顯示圖片
cv2.imshow('line', img)
cv2.waitKey()
輸出的結(jié)果如下:
[[[300 270]]
[[299 271]]
[[254 298]]
[[250 300]]
[[120 240]]
[[122 239]]
[[257 203]]
[[269 200]]
[[270 200]]
[[273 206]]
[[300 269]]]
這是凸包所在的輪廓的點(diǎn)集集合,有了它,我們就能繪制出凸包的輪廓了,如下:
簡(jiǎn)單例子2 手勢(shì)圖片
??接下來(lái),我們將介紹一張稍微難一點(diǎn)的圖片——手勢(shì)圖片(finger.jpg),如下所示:
我們將會(huì)來(lái)尋找這個(gè)手勢(shì)的凸包。基本的處理思路還是和之前的一致,只是要在二值化以及凸包點(diǎn)集集合的大小上做一些處理,取二值化的閾值為235,凸包點(diǎn)集中的點(diǎn)個(gè)數(shù)大于5,完整的Python代碼如下:
import cv2
# 讀取圖片并轉(zhuǎn)至灰度模式
imagepath = 'F://finger.jpg'
img = cv2.imread(imagepath, 1)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 二值化,取閾值為235
ret, thresh = cv2.threshold(gray, 235, 255, cv2.THRESH_BINARY)
# 尋找圖像中的輪廓
image, contours, hierarchy = cv2.findContours(thresh, 2, 1)
# 尋找物體的凸包并繪制凸包的輪廓
for cnt in contours:
hull = cv2.convexHull(cnt)
length = len(hull)
# 如果凸包點(diǎn)集中的點(diǎn)個(gè)數(shù)大于5
if length > 5:
# 繪制圖像凸包的輪廓
for i in range(length):
cv2.line(img, tuple(hull[i][0]), tuple(hull[(i+1)%length][0]), (0,0,255), 2)
cv2.imshow('finger', img)
cv2.waitKey()
檢測(cè)到的凸包如下圖所示:
可以發(fā)現(xiàn),一共檢測(cè)到2個(gè)凸包,一個(gè)是整個(gè)手勢(shì)外圍的凸包,正好包圍整個(gè)手,另一個(gè)是兩個(gè)手指形成的內(nèi)部的圖形,類(lèi)似于O的凸包,這符合我們的預(yù)期。
總結(jié)
??當(dāng)然,我們?cè)谶@里只是介紹了OpenCV檢測(cè)凸包的函數(shù)convexHull以及其應(yīng)用,并沒(méi)有講到如何檢測(cè)凸包的算法。如有機(jī)會(huì),筆者將會(huì)介紹該算法。歡迎大家交流,祝大家國(guó)慶快樂(lè)!
注意:本人現(xiàn)已開(kāi)通微信公眾號(hào): 輕松學(xué)會(huì)Python爬蟲(chóng)(微信號(hào)為:easy_web_scrape), 歡迎大家關(guān)注哦~~
總結(jié)
以上是生活随笔為你收集整理的OpenCV入门之寻找图像的凸包(convex hull)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: go语言快速刷《程序员面试金典》(3)
- 下一篇: leetcode570. 至少有5名直接