opencv-python 學習 |圖像輪廓

圖像輪廓

import cv2
def cv_show(name,img):
    cv2.imshow(name,img)
    while cv2.waitKey(100) != 27:# loop if not get ESC
        if cv2.getWindowProperty(name,cv2.WND_PROP_VISIBLE) <= 0:
            break
    cv2.destroyWindow(name)

cv2.findContours(img,mode,method)

mode:輪廓檢索模式

  • RETR_EXTERNAL :只檢索最外面的輪廓;
  • RETR_LIST:檢索所有的輪廓,並將其保存到一條鏈表當中;
  • RETR_CCOMP:檢索所有的輪廓,並將他們組織爲兩層:頂層是各部分的外部邊界,第二層是空洞的邊界;
  • RETR_TREE:檢索所有的輪廓,並重構嵌套輪廓的整個層次;

method:輪廓逼近方法

  • CHAIN_APPROX_NONE:以Freeman鏈碼的方式輸出輪廓,所有其他方法輸出多邊形(頂點的序列)。
  • CHAIN_APPROX_SIMPLE:壓縮水平的、垂直的和斜的部分,也就是,函數只保留他們的終點部分。

什麼是輪廓?輪廓是一系列相連的點組成的曲線,代表了物體的基本外形,相對於邊緣,輪廓是連續的,邊緣並不全部連續。

如何尋找輪廓?尋找輪廓的操作一般用於二值化圖,所以通常會使用閾值分割或Canny邊緣檢測先得到二值圖

PS:尋找輪廓是針對白色物體的,一定要保證物體是白色,而背景是黑色,不然很多人在尋找輪廓時會找到圖片最外面的一個框

img = cv2.imread('map.jpeg')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray,127,255,cv2.THRESH_BINARY)#大於127取255,小於取0
cv_show('thresh',thresh)

參數1:二值化原圖
參數2:輪廓的查找方式,一般使用cv2.RETR_TREE,表示提取所有的輪廓並建立輪廓間的層級。
參數3:輪廓的近似方法。比如對於一條直線,我們可以存儲該直線的所有像素點(cv2.CHAIN_APPOX_NONE),也可以只存儲起點和終點。使用 cv2.CHAIN_APPROX_SIMPLE 就表示用儘可能少的像素點表示輪廓.

contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE) #新版的opencv調用只返回兩個參數,此時本人用的版本是4.1.2

contours即爲輪廓的像素集合(可能有多個輪廓,需要找到自己要提取的輪廓)

繪製輪廓

#傳入繪製圖像,輪廓,輪廓索引,顏色模式,線條厚度
# 注意需要copy,要不原圖會變。。。
draw_img = img.copy()
#cv2.drawContours參數:圖片,輪廓集合,第幾個輪廓(-1表示繪製所有輪廓) ,畫筆顏色((0,0,255)表示紅色),畫筆寬度,
res = cv2.drawContours(draw_img,contours,110,(0,0,255),2)     
cv_show('res',res)
print(len(contours))
610

輪廓特徵

計算物體的周長、面積、質心、最小外接矩形等
OpenCV函數:cv2.contourArea(), cv2.arcLength(), cv2.approxPolyDP()等

#面積
cv2.contourArea(cont)
365715.0
#查看每個較大點的輪廓
for index,area in enumerate(contours,0) :
    if cv2.contourArea(area)>100:
        print(cv2.contourArea(area),index)
365715.0 0
530.0 61
200.0 64
139.5 88
627.0 110
161.0 119
102.0 124
109.0 136
695.0 164
110.5 205
524.5 224
380.5 242
316.5 243
227.0 253
106.5 273
108.0 286
106.0 315
5552.0 333
1726.5 339
122.0 344
129.5 348
135.0 370
155.0 377
101.0 384
302.5 395
163.0 398
359.0 407
113.0 412
100.5 420
123.5 423
261.5 431
520.5 441
100.5 442
297.0 446
119.0 457
216.0 470
268.0 484
116.0 490
106.5 510
637.5 519
113.5 557
100.5 560
155.5 579
285.0 585
144.0 586
2087.0 595
314.0 597
114.5 599
113.0 608
cont = contours[0]
#周長
cv2.arcLength(cont,True)    #True表示閉合
2424.0

當輪廓有毛刺的時候,我們希望能夠做輪廓近似,將毛刺去掉,大體思想是將曲線用直線代替,但是有個長度的閾值需要自己設定。

輪廓近似

將輪廓形狀近似到另外一種由更少點組成的輪廓形狀,新輪廓的點的數目由我們設定的準確度來決定,用的Douglas-Peucker算法。

#先找到輪廓
img_contours = cv2.imread('contours2.png')
gray = cv2.cvtColor(img_contours,cv2.COLOR_BGR2GRAY)    #灰度處理
ret,thresh = cv2.threshold(gray,127,255,cv2.THRESH_BINARY) #二值化
#找輪廓
contours2, hierarchy2 = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
#第一個輪廓
cnt = contours2[0]

draw_img = img_contours.copy()
res = cv2.drawContours(draw_img,[cnt],-1,(0,0,255),2)
cv_show('res',res)
#行多邊形逼近,得到多邊形的角點
epsilon = 0.15 * cv2.arcLength(cnt,True)
approx = cv2.approxPolyDP(cnt,epsilon,True)

draw_img = img_contours.copy()
res = cv2.drawContours(draw_img,[approx],-1,(0,0,255),2)
cv_show('res',res)

其中cv2.approxPolyDP() 的參數2(epsilonepsilon)是一個距離值,表示多邊形的輪廓接近實際輪廓的程度,值越小,越精確;參數3表示是否閉合。

對於輪廓我們還可以做一些額外的操作,比如外接矩形,外接圓,外界橢圓等等。

邊界矩形

img_contours = cv2.imread('contours2.png')
gray = cv2.cvtColor(img_contours,cv2.COLOR_BGR2GRAY)    #灰度處理
ret,thresh = cv2.threshold(gray,127,255,cv2.THRESH_BINARY) #二值化
#找輪廓
contours2, hierarchy2 = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
#第一個輪廓
cnt = contours2[0]

img = img_contours.copy()
x,y,w,h = cv2.boundingRect(cnt)
img = cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2)
cv_show('img',img)
plt.imshow(img)
<matplotlib.image.AxesImage at 0x133ae3048>

在這裏插入圖片描述

area = cv2.contourArea(cnt)
x, y, w, h = cv2.boundingRect(cnt)
rect_area = w * h
extent = float(area) / rect_area
print ('輪廓面積與邊界矩形比',extent)
輪廓面積與邊界矩形比 0.7800798598378357

外接圓

(x,y),radius = cv2.minEnclosingCircle(cnt)
center = (int(x), int(y))
radius = int(radius)
img = img_contours.copy()
img = cv2.circle(img,center,radius,(0,255,0),2)
cv_show('img',img)

plt.imshow(img)
<matplotlib.image.AxesImage at 0x127cc22b0>

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章