1.1什麼是輪廓
輪廓能夠簡單認爲成連續的點(連着邊界)連在一塊兒的曲線,具備相同的顏色或者灰度。輪廓在形狀分析和物體的檢測和識別中頗有用。python

  • 爲了準確,要使用二值化圖像。須要進行閥值化處理或者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) 

根據這些矩的值,咱們能夠計算出對象的重心:app

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),仍是打開的(一條曲線)。ui

perimeter = cv2.arcLength(cnt,True) 

2.4輪廓近似
將輪廓形狀近似到另一種由更少點組成的輪廓形狀,新輪廓的點的數目由咱們設定的準確度來決定,使用的Douglas-Peucker算法,能夠本身Google。
假設咱們要在一幅圖像中查找一個矩形,可是因爲圖像的種種緣由咱們不能獲得一個完美的矩形,而是一個「壞形狀」,如今就可使用這個函數來近似這個形狀,第二個參數是epsilon,它是從原始輪廓到近似輪廓的最大距離,它是一個準確度參數。spa

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

2.5凸包
凸包與輪廓近似類似,但不一樣,雖然有些狀況下它們給出的結果是同樣的。函數cv2.convexHull()能夠用來檢測一個曲線是否具備凸性缺陷,並能糾正缺陷。通常來講,凸性曲線老是凸出來的,至少是平的。若是有地方凹進去了就被叫作凸性缺陷。例以下圖中的手,紅色曲線顯示了手的凸包,凸性缺陷被雙箭頭標出來了。
3d

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

參數:code

  • 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)