OpenCV計算機圖像處理 —— 凸性缺陷 + 點多邊形測試 + 形狀匹配 + 輪廓分層與cv.findContours()
OpenCV計算機圖像處理 —— 凸性缺陷 + 點多邊形測試 + 形狀匹配 + 輪廓分層與cv.findContours()
1. 凸性缺陷
一般來說凸曲線都是凸出或平坦的曲線,如果在內部凸出了(凹進去了)我們就稱其為凸性缺陷,OpenCV提供了一個方法cv.convexityDefects()
這個函數返回一個數組,其中每行包含這些值-【起點,終點,最遠點,到最遠點的近似距離】,我們可以用圖像把它形象化,我們畫一條連接起點和終點的線,然后在最遠處畫一個圓
import cv2 as cv import numpy as np img = cv.imread(r'E:\image\test14.png') img_gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY) ret, thresh = cv.threshold(img_gray, 127, 255, 0) contours, hierarchy = cv.findContours(thresh, 2, 1) cnt = contours[0] hull = cv.convexHull(cnt, returnPoints=False) defects = cv.convexityDefects(cnt, hull) for i in range(defects.shape[0]): s, e, f, d = defects[i, 0] start = tuple(cnt[s][0]) end = tuple(cnt[e][0]) far = tuple(cnt[f][0]) cv.line(img, start, end, [0, 255, 0], 2) cv.circle(img, far, 5, [0, 0, 255], -1) cv.imshow('img', img) cv.waitKey(0) cv.destroyAllWindows()
在以前輪廓的內容中我們提到了了一個函數cv.convexHull(),當這個函數的屬性returnPoints = False時,我們就可以找到凸性缺陷
代碼解釋:又到了激動人心的解析代碼的時間啦!第4-5行即是老生常談的讀取圖片并轉化為灰度圖,第6行通過threshold()函數設置閾值,第7行通過findContours()方法找到輪廓,將第一個輪廓拿出來后用convexHull()函數檢查輪廓的凸度缺陷,然后使用convexityDefects()函數得到這些凸度缺陷對應點的相關信息,包括起點終點等
2. 點多邊形測試
點多邊形測試中涉及了一個新的函數:cv.pointPolygonTest(),顧名思義它是一個測試函數,第一個參數是輪廓,第二個參數就是我們的測試點了,第三個參數指的是measureDist,如果其取值為True,這個函數會找到有符號的距離,反之它只會反映出這個點是在輪廓線內部、上面還是外部(分別返回1、-1和0)
import cv2 as cv import numpy as np img = cv.imread(r'E:\image\test12.png') img_gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY) ret, thresh = cv.threshold(img_gray, 127, 255, 0) contours, hierarchy = cv.findContours(thresh, 2, 1) cnt = contours[0] img02 = cv.drawContours(img, [cnt], 0, (0, 0,255), 3) dist = cv.pointPolygonTest(cnt, (20, 20), True) dist2 = cv.pointPolygonTest(cnt, (192.5, 156), True) print("point:(20,20) = " + str(dist)) print("point:(192.5,156) = " + str(dist2)) cv.imshow('test', img02) cv.waitKey(0) cv.destroyWindow()
3. 形狀匹配
OpenCV中的形狀匹配與一個函數有關:cv.matchShapes(),這個函數使我們能夠比較兩個形狀(或兩個輪廓),并返回一個顯示相似性的度量,這個值越低說明匹配越好,在實質上它是根據矩值計算出來的
值得注意的是,即使是圖像旋轉也不會對結果產生很大的影響
import cv2 as cv import numpy as np from matplotlib import pyplot as pyt img1 = cv.imread(r'E:/image/star01.png', 0) img2 = cv.imread(r'E:/image/star02.png', 0) img3 = cv.imread(r'E:/image/rectangle01.png', 0) ret, thresh = cv.threshold(img1, 127, 255, 0) ret, thresh2 = cv.threshold(img2, 127, 255, 0) ret, thresh3 = cv.threshold(img3, 127, 255, 0) contours, hierarchy = cv.findContours(thresh, 2, 1) cnt1 = contours[0] contours, hierarchy = cv.findContours(thresh2, 2, 1) cnt2 = contours[0] contours, hierarchy = cv.findContours(thresh3, 2, 1) cnt3 = contours[0] ret = cv.matchShapes(cnt1, cnt2, 1, 0.0) ret2 = cv.matchShapes(cnt1, cnt3, 1, 0.0) print("星圖1與星圖2的匹配度量 = " + str(ret)) print("星圖1與方圖1的匹配度量 = " + str(ret2)) pyt.subplot(1, 3, 1), pyt.imshow(img1, cmap="gray") pyt.title("star_img01"), pyt.xticks([]), pyt.yticks([]) pyt.subplot(1, 3, 2), pyt.imshow(img2, cmap="gray") pyt.title("star_img02"), pyt.xticks([]), pyt.yticks([]) pyt.subplot(1, 3, 3), pyt.imshow(img3, cmap="gray") pyt.title("rectangle_img01"), pyt.xticks([]), pyt.yticks([]) pyt.show()
4. 輪廓分層與cv.findContours()
4.1 輪廓分層與cv.findcontours()的關系
在前面的文章我們聊了怎么使用cv.findcontours()函數找到輪廓,并且提到了它的第三個參數輪廓檢索模式,對于這個參數我們通常使用cv.RETR_LIST或cv.RETR_TREE就能得到很好的效果,而且對應這個函數的三個輸出我們也很有必要了解一下,它的輸出包括三個數組,包括圖像(image)、輪廓(contours)和hierarchy,它其實就是我們在這一節要聊的”輪廓層次結構”
在某些情況下,某些形狀位于其他形狀中,就像嵌套的圖形一樣,在這種情況下,我們把外部的稱為父類,把內部的稱為子類,這樣,圖像中的輪廓就有了一定的相互關系。我們可以指定一個輪廓是如何相互連接的,比如,它是另一個輪廓的子輪廓,還是父輪廓等等。這種關系的表示稱為層次結構
所以每個輪廓都有它自己的信息關于它是什么層次,誰是它的孩子,誰是它的父母等等,OpenCV將它表示為一個包含四個值的數組: [Next, Previous, First_Child, Parent],這就是我們在findcontours()函數中得到的第三個參數
4.2 輪廓檢索模式(四種參數)
RETR_LIST
這是四個標志中最簡單的一個,它只是檢索所有的輪廓,但不創建任何親子關系,在這個規則下,父輪廓和子輪廓是平等的,他們只是輪廓,并且都屬于同一層級,如果我們在開發中沒有使用任何層次結構特性,它就是我們最佳的選擇
RETR_EXTERNAL
如果使用此標志,它只返回極端外部標志,所有孩子的輪廓都被留下了,更形象地來說,根據這項規則,每個家庭只有長子得到關注,它不關心家庭的其他成員,所以當我們只關心外部輪廓時可以使用它
RETR_CCOMP
此標志檢索所有輪廓并將其排列為2級層次結構,物體的外部輪廓(即物體的邊界)放在層次結構-1中,對象內部孔洞的輪廓(如果有)放在層次結構-2中,如果其中有任何對象,則其輪廓僅在層次結構1中重新放置,以及它在層級2中的漏洞等等
RETR_TREE
它就是最完美的一個家伙了,它檢索所有的輪廓并創建一個完整的家族層次結構列表,當我們需要檢索所有輪廓時會使用它
接下來通過代碼看看吧,實踐永遠是最好的老師
import cv2 as cv import numpy as np from matplotlib import pyplot as pyt img = cv.imread(r'E:/image/the_first.png') img_gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY) ret, thresh = cv.threshold(img_gray, 127, 255, 0) contours, hierarchy = cv.findContours(thresh, cv.RETR_LIST, cv.CHAIN_APPROX_NONE) cnt = contours[0] contours, hierarchy = cv.findContours(thresh, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_NONE) cnt2 = contours[0] contours, hierarchy = cv.findContours(thresh, cv.RETR_CCOMP, cv.CHAIN_APPROX_NONE) cnt3 = contours[0] contours, hierarchy = cv.findContours(thresh, cv.RETR_TREE, cv.CHAIN_APPROX_NONE) cnt4 = contours[0] img1 = cv.drawContours(thresh, [cnt], 0, (255, 0, 0), 2) img2 = cv.drawContours(thresh, [cnt2], 0, (0, 255, 0), 2) img3 = cv.drawContours(thresh, [cnt3], 0, (0, 0, 255), 2) img4 = cv.drawContours(thresh, [cnt4], 0, (0, 0, 0), 2) pyt.subplot(2, 2, 1), pyt.imshow(img1, cmap="gray") pyt.title("RETR_LIST"), pyt.xticks([]), pyt.yticks([]) pyt.subplot(2, 2, 2), pyt.imshow(img2, cmap="gray") pyt.title("RETR_EXTERNAL"), pyt.xticks([]), pyt.yticks([]) pyt.subplot(2, 2, 3), pyt.imshow(img3, cmap="gray") pyt.title("RETR_CCOMP"), pyt.xticks([]), pyt.yticks([]) pyt.subplot(2, 2, 4), pyt.imshow(img3, cmap="gray") pyt.title("RETR_TREE"), pyt.xticks([]), pyt.yticks([]) pyt.show()
(注:文章內容參考OpenCV4.1中文官方文檔)
如果文章對您有所幫助,記得一鍵三連支持一下哦
AI OpenCV 圖像處理 機器學習 機器視覺
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。