1. 程式人生 > >Python OpenCV 輪廓特徵2

Python OpenCV 輪廓特徵2

                          Python  OpenCV  輪廓特徵2

 

1.1什麼是輪廓

   輪廓可以簡單認為成連續的點(連著邊界)連在一起的曲線,具有相同的顏色或者灰度。輪廓在形狀分析和物體的檢測和識別中很有用

  • 為了準確,要使用二值化影象。需要進行閥值化處理或者Canny邊界檢測。
  •  
  • 查詢輪廓的函式會修改原始影象。如果之後想繼續使用原始影象,應該將原始影象儲存到其他變數中。
  •  
  • 在OpenCV中,查詢輪廓就像在黑色背景中超白色物體。你應該記住,要找的物體應該是白色而背景應該是黑色
     

如何在一個二值影象中查詢輪廓 ?

函式 cv2.findContours()  有三個引數,

第一個是輸入影象,

第二個是輪廓檢索模式,

第三個是輪廓近似方法。

   返回值有三個,第一個是影象,第二個是輪廓,第三個是(輪廓的)層析結構。輪廓(第二個返回值)是一個Python列表,其中儲存這影象中所有輪廓。每一個輪廓都是一個Numpy陣列,包含物件邊界點(x,y)的座標

 

  •  
  • 1.2怎樣繪製輪廓
  • 函式cv2.drawContours()可以被用來繪製輪廓。 它可以根據你提供的邊界點繪製任何形狀。它的第一個引數是原始影象,第二個引數是輪廓,一個python列表,第三個引數是輪廓的索引(在繪製獨立輪廓是很有用,當設定為-1時繪製所有輪廓)。
  • 接下來的引數是輪廓的顏色和厚度。
    在一幅影象上繪製所有的輪廓:
import numpy as np
import cv2

img = cv2.imread('1024.jpg')
imgray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(imgray,127,255,0)
image ,contours,hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
#繪製獨立輪廓,如第四個輪廓
#imag = cv2.drawContour(img,contours,-1,(0,255,0),3)
#但是大多數時候,下面方法更有用
imag = cv2.drawContours(img,contours,3,(0,255,0),3)

while(1):
    cv2.imshow('img',img)
    cv2.imshow('imgray',imgray)
    cv2.imshow('image',image)
    cv2.imshow('imag',imag)
    if cv2.waitKey(1) == ord('q'):
        break
cv2.destroyAllWindows()

1.3輪廓的近似方法
   之前提到輪廓是一個形狀具有相同灰度值的邊界,它會儲存形狀邊界上所有的(x,y)座標。實際上我們不需要所有的點,當需要直線時,找到兩個端點即可。cv2.CHAIN_APPROX_SIMPLE可以實現。它會將輪廓上的冗餘點去掉,壓縮輪廓,從而節省記憶體開支。


  下面用矩陣來演示,在輪廓列表中的每一個座標上畫一個藍色圓圈。第一個顯示使用cv2.CHAIN_APPROX_NONE的效果,一共734個點,第二個圖是使用cv2.CHAIN_APPROX_SIMPLE的結果,只有4個點。


 

 

2.輪廓特徵
2.1矩

影象的矩可以幫助我們計算影象的質心,面積等。
函式cv2.moments()會將計算得到的矩以一個字典的形式返回。

import numpy as np
import cv2

img = cv2.imread('1024.jpg',0)
ret,thresh = cv2.threshold(img,127,255,0)
image,contours,hierarchy=cv2.findContours(thresh,1,2)
cnt=contours[0]
M=cv2.moments(cnt)
print(M)

 

根據這些矩的值,我們可以計算出物件的重心:

 

cx=int(M['m10']/M['m00'])
cy=int(M['m01']/M['m00'])

 

2.2輪廓面積
可以使用函式cv2.contourArea()計算得到,也可以用矩(0階矩),M['m00']。

area=cv2.contourArea(cnt)

2.3輪廓周長
也被稱為弧長。可以使用函式cv2.arcLength()計算得到。這個函式的第二引數可以用來指定物件的形狀是閉合的(True),還是開啟的(一條曲線)。

perimeter = cv2.arcLength(cnt,True)

2.4輪廓近似
將輪廓形狀近似到另外一種由更少點組成的輪廓形狀,新輪廓的點的數目由我們設定的準確度來決定,使用的Douglas-Peucker演算法,可以自己Google。
假設我們要在一幅影象中查詢一個矩形,但是由於影象的種種原因我們不能得到一個完美的矩形,而是一個“壞形狀”,現在就可以使用這個函式來近似這個形狀,第二個引數是epsilon,它是從原始輪廓到近似輪廓的最大距離,它是一個準確度引數。

epsilon=0.1*cv2.arcLength(cnt,True)
approx = cv2.approxPolyDP(cnt,epsilon,True)

 

2.5凸包
凸包與輪廓近似相似,但不同,雖然有些情況下它們給出的結果是一樣的。函式cv2.convexHull()可以用來檢測一個曲線是否具有凸性缺陷,並能糾正缺陷。一般來說,凸性曲線總是凸出來的,至少是平的。如果有地方凹進去了就被叫做凸性缺陷。例如下圖中的手,紅色曲線顯示了手的凸包,凸性缺陷被雙箭頭標出來了。

hull = cv2.convexHull(points,hull,clockwise,returnPoints)

引數:

  • points我們要傳入的輪廓
  • hull輸出,通常不需要
  • clockwise方向標誌,如果設定為True,輸出的凸包是順時針方向的,否則為逆時針方向。
  • returnPoints預設值為True。它會返回凸包上點的座標,如果設定為False,就會返回與凸包點對應的輪廓上的點。
    要獲得上圖的凸包,可以用下面命令:
hull=cv2.convexHull(cnt)

但是如果你想獲得凸性缺陷,需要把returnPoints設定為False。以上面矩形為例,首先我們找到他的輪廓從cnt。現在把returnPoints設定為True查詢凸包,得到的就是矩形的四個角點。把returnPoints設定為False,得到的是輪廓點的索引。
 

2.6凸性檢測
函式cv2.isContourConvex()可以檢測一個曲線是不是凸的。它只能返回True或者False。

k=cv2.isContourConvex(cnt)

 

2.7邊界矩形
直邊界矩形,一個直矩形,沒有旋轉。不會考慮物件是否旋轉。所以邊界矩形的面積不是最小的。可以使用函式cv2.boundingRect()查詢得到

#(x,y)為矩形左上角的座標,(w,h)是矩形的寬和高
x,y,w,h=cv2.boundingRect(cnt)
img=cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2)

  旋轉的邊界矩形,這個邊界矩形是面積最小的,因為它考慮了物件的旋轉。用函式cv2.minAreaRect()。返回的是一個Box2D結構,其中包含矩形最上角角點座標(x,y)矩形的寬和高(w,h)以及旋轉角度。但是要繪製這個矩形需要矩形的4個角點,可以通過函式cv2.boxPoints()獲得。


其中綠色的為直矩形,紅色為旋轉矩形。


 

2.8最小外接圓
函式cv2.minEnclosingCircle()可以幫我們找到一個物件的外接圓。它是所有能夠包括物件的圓中面積最小的一個。

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

 

2.9橢圓擬合
使用函式cv2.ellipse(),返回值其實就是旋轉邊界矩形的內切圓。

ellipse = cv2.fitEllipse(cnt)
img = cv2.ellipse(img,ellipse,(0,255,0),2)

 

2.10直線擬合
可以根據一組點擬合出一條直線,同樣我們也可以為影象中的白色點擬合出一條直線。

rows,cols = img.shape[:2]
[vx,vy,x,y]=cv2.fitLine(cnt,cv2.DIST_L2,0,0.01,0.01)
lefty=int((x*vy/vx)+y)
righty=int(((cols-x)*vy/vx)+y)
img = cv2.line(img,(cols-1,righty),(0,lefty),(0,255,0),2)

 希望對你有幫助。