目錄
1.什么是輪廓?為什么要進行輪廓檢測?
2.輪廓檢測原理
2.1尋找第一個邊界點
2.2尋找下一個邊界點
3.程式實作(Python OpenCv)
3.1尋找輪廓
3.1.1輪廓的輪廓串列與層次關系
3.1.2輪廓檢索模式
3.1.3輪廓近似方法
3.2繪制輪廓
4.OpenCv中的輪廓相關屬性方法

1.什么是輪廓?為什么要進行輪廓檢測?
輪廓是什么?
1.對于人眼來說,是圖片中某一物體的邊緣,
2.對于機器來說,是矩陣中沿著邊緣的相同顏色即相同像素點強度的所有連續點的曲線,(我們在前篇中已經詳細講過圖片在計算機中其實是一個矩陣:影像與矩陣)
3.輪廓與邊緣的區別:輪廓是一圈包住物體,邊緣可以使零零散散的一條線,
為什么要對輪廓進行檢測?
輪廓是后續用于對圖中物體進行形狀分析或者物件識別的有效媒介,
2.輪廓檢測原理
輪廓檢測的原理是輪廓跟蹤,即通過順序逐點跟蹤目標邊界,最終找出的所有點構成的就是邊界,
注意:在開始講述之前,最好確保影像已經二值化(即只存在黑白二色),這不僅是理論的前提還是后面程式實作的前提,另外,影像二值化可通過設定閾值使用掩膜卷積過濾或者Canny邊緣檢測來實作:制作掩膜3.1.3②、Canny邊緣檢測,
2.1尋找第一個邊界點
從上到下,從左到右地在圖片中找到第一個邊界點E0,
2.2尋找下一個邊界點
怎么找?可通過搜尋4連通域(即像素點的上、下、左、右)或者8連通域(不僅包括上、下、左、右還包括的左上、右上、左下、右下)來找,
找什么?找與本像素點值相同的連著的另一個像素點,此像素點即下一個邊界點,
具體方法:
- 設定一個dir數值,表示上一個像素點是如何找到本像素點的,
- 利用dir計算(dir + 3) mod 4(4連通域算式,若是8連通域則為(dir + 7) mod 8)表示本像素點開始搜索的方向,
- 這樣順時針搜索(根據0,1,2,3代表的指向的不同也可以設定成逆時針)到另一個值相同的像素點后,使該像素點為新像素點并且該像素點的dir為上一步除余的值,
3.程式實作(Python OpenCv)
3.1尋找輪廓
contours, hierarchy = cv.findContours(image, mode, method[, contours[, hierarchy[, offset]]])
- contours:提取到的n個輪廓,是一個Python串列,可通過索引訪問其中的具體某個輪廓,
- hierarchy:輪廓的層次關系,見3.1.1,
- image:源影像,一般要求是個二進制影像,若mode為RETR_CCOMP和RETR_FLOODFILL時可以是32位整數影像,
- mode:輪廓檢索模式,見3.1.2,
- method:輪廓近似方法,見3.1.3,
- offset:可選偏移量,每個輪廓點偏移量,如果從影像ROI中提取輪廓,然后在整個影像背景關系中對其進行分析,這將非常有用,
- 值得一提的是,這個函式不使用輪廓追蹤,而是使用鈴木佐藤等人的《基于邊界跟蹤的數字化二值影像拓撲結構分析》提到的演算法,
3.1.1輪廓的輪廓串列與層次關系
通過例子來掌握輪廓的輪廓串列與層次關系,給出一張二值影像:

先來說說為什么2有2a,3有3a,而0,1,4,5卻沒有呢?
答:2,3所在輪廓是一個內空心的閉合圖形,所以2是所在輪廓的外輪廓,2a是所在輪廓的內輪廓,相應的,3是所在輪廓的外輪廓,3a是所在輪廓的內輪廓,而0,1是線段、4,5是實心圖形,沒有內外之分,只有簡單的輪廓之稱,
輪廓串列:
很顯然,輪廓串列contours = [0,1,2,2a,3,3a,4,5],
層次關系:
在邏輯層面,可以很輕松地從圖中看出0,1,2是同一層次的輪廓,而2有個子輪廓2a,2a又有個子輪廓3,3又又有個子輪廓3a,3a又又又有兩個子輪廓4,5,并且4,5處于同一層次,(2的子輪廓是2a,那么2a的父輪廓就是2,這種簡單的理論自己想一下就不說了...)
而在opencv中將每個輪廓的層次資訊(同層次下一個,同層次上一個,子輪廓,父輪廓)包含在這樣一個4值陣列中:[Next, Previous, First_Child, Parent],
因此圖中我們可得到的層次關系資訊為:
0->[1,-1,-1,-1]
1->[0,2,-1,-1]
2->[1,-1,2a,-1]
2a->[-1,-1,3,2]
......
注意:
1.不存在的層次關系用-1表示,
2.實際的程式中并沒有2a,3a這種說法,這里只是為了方便表示,實際程式中2a應該變3,3應該便4,3a應該變5,依次往后挪......
3.實際程式hierarchy輸出案例(與上圖無關):

3.1.2輪廓檢索模式
opencv中的輪廓檢索模式有4種:
| cv.RETR_EXTERNAL | 僅檢索最外層輪廓, |
| cv.RETR_LIST | 檢索所有輪廓,而不建立任何層次關系, |
| cv.RETR_TREE | 檢索所有輪廓并重建嵌套輪廓的完整層次結構, |
| cv.RETR_CCOMP | 把所有層次僅分為內外兩層, |
還是結合上面那個例子:

- cv.RETR_EXTERNAL:只記錄0,1,2這3個最外層級的輪廓,
- cv.RETR_LIST:記錄所有輪廓但是不分層次,比如把2與2a記錄在同一層次,
- cv.RETR_TREE:記錄所有完整層次,也就是上一節的那種,
- cv.RETR_CCOMP:0,1,2,3,4,5是外層,2a,3a是內層,內層的父輪廓、外層的子輪廓照舊,
似懂非懂的話可以再看看這個:輪廓檢索方式具體案例
3.1.3輪廓近似方法
opencv中的輪廓近似方法也有4種:
| cv.CHAIN_APPROX_NONE | 存盤所有邊界點, |
| cv.CHAIN_APPROX_SIMPLE | 只保存關鍵的點(如保存線段的兩頭便可畫出線段了),節省記憶體, |
| cv.CHAIN_APPROX_TC89_L1 | 采用一種Teh-Chin chain近似演算法, |
| cv.CHAIN_APPROX_TC89_KCOS | 采用一種Teh-Chin chain近似演算法, |
其實只要懂第一種跟第二種就好啦~后面兩種有興趣自己百度~
3.2繪制輪廓
cv.drawContours(image, contours, contourIdx, color[, thickness[, lineType[, hierarchy[, maxLevel[, offset]]]]])
contourIdx就是contours串列中的索引,如輸入3則繪制第3個輪廓,輸入-1則繪制所有輪廓,
其他的本專欄前面幾章都講過類似的這里就不講了,看看屬性名字應該都懂了,
注意:
1.輸入的應該是原始影像,
2.輸入影像直接在原圖上被修改,
使用案例:
import cv2
import numpy as np
src = cv2.imread("lyf.jpg")
# Canny處理得到二值化影像
src = cv2.GaussianBlur(src, (5, 5), 5)
canny = cv2.Canny(src, 0,30)
# 輪廓檢測
contours, hierarchy = cv2.findContours(canny, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# 注意這里第一個引數輸入的是原始影像
cv2.drawContours(src, contours, -1, (0,0,255), 1)
cv2.imshow("src", src)
cv2.imshow("canny", canny)
cv2.waitKey()
cv2.destroyAllWindows()
4.OpenCv中的輪廓相關屬性方法
首先得找一條輪廓吧:
cnt = contours[0]
1.特征矩
M = cv.moments(cnt)
2.輪廓面積
area = cv.contourArea(cnt)
3.輪廓周長
perimeter = cv.arcLength(cnt,True)
更多的,可以查看OpenCv官方中文檔案,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/290194.html
標籤:其他
上一篇:java-opencv剪輯圖片
下一篇:最新Pycharm安裝呼叫opencv-python步驟,以及遇到的問題: opencv已經安裝成功;cmd環境下python可以import cv2 ;但pycharm下會出錯
