OpenCV學習筆記(13)——輪廓特征


  • 查找輪廓的不同特征,例如面積,周長,重心,邊界等

1.矩

  圖像的矩可以幫助我們計算圖像的質心,面積等。

  函數cv2.momen()會將計算得到的矩以一個字典的形式返回,

  我們的測試圖像如下:

  

 

  例程如下:

# -*- coding:utf-8 -*-

import numpy as np
import cv2
from matplotlib import pyplot as plt

img = cv2.imread('8.jpg',0)
ret,thresh = cv2.threshold(img,127,255,0)
im,contours,hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)

cnt = contours[0]
M = cv2.moments(cnt)
print(M)
#會返回一個字典


#計算重心
cx = int(M['m10']/M['m00'])
cy = int(M['m01']/M['m00'])
  

 

2.輪廓面積

  輪廓面積可以用cv2.contourArea()計算得到,也可以使用矩,M['m00‘]

  print(cv2.contourArea(cnt))

 

3.輪廓周長

  也被稱為弧長。可以使用函數cv2.arcLength()計算得到。這個函數的第二參數可以用來指定對象的形狀是閉合的還是打開的(即曲線)

  print(cv2.arcLength(cnt,True))#試了一下,如果強行賦予False,得到的周長會比用True短一些

 

4.輪廓近似

  將輪廓形狀近似到另外一種有更少點組成的輪廓形狀,新輪廓的點的數目由我們設定的准確度來決定。使用的Douglas-Peucker算法在此不細講了。

  我們假設要在下圖中找一個矩形

  

然而這個圖凹凸不平,直接提取輪廓無法提取到一個完美的矩形。因此我們就可以使用這個函數來近似這個形狀了。這個函數的第二個參數epsilon,是從原始輪廓到近似輪廓的最大距離,是一個准確度參數。因此對它的調整對最后的結果很重要。

  例程如下:

# -*- coding:utf-8 -*-

import numpy as np
import cv2
from matplotlib import pyplot as plt

im = cv2.imread('9.png')
img = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)#用這個方式轉換的原因是最后輸出時希望能看到彩色的的輪廓圖
ret,thresh = cv2.threshold(img,127,255,0)

img,contours,hierarchy = cv2.findContours(thresh,1,2)
cnt = contours[0]

epsilon = 0.1*cv2.arcLength(cnt,True)
approx = cv2.approxPolyDP(cnt,epsilon,True)#這個和上面的True都是表示是閉曲線
#approx得到的僅僅是幾個點集,需要將其連接起來

# cv2.drawContours(im,approx,-1,(0,0,255),3) 該函數只能畫出幾個點
cv2.polylines(im, [approx], True, (0, 255, 0), 2)#需要用這個函數才能畫出輪廓,中間的True也是指示是否為閉曲線的

cv2.imshow('img',im)
cv2.waitKey(0)

最終效果如下:

指定為10%時: 指定為1%時:

 

5.凸包

  凸包與輪廓近似相似,有些時候他們給出的結果是一樣的,但是本質上講他們是不同的。函數cv2,convexHull()可以用來檢測一個曲線是否具有凸性缺陷,並能糾正缺陷。一般來說,凸性曲線總是凸出來的,至少是頻帶。如果有地方凹進去了就被叫做凸性缺陷。如下圖所示:

  紅色表示了他的凸包,而凸性缺陷被雙箭頭標出來了。

  對於參數還有需要說明的地方:

  hull = cv2.convexHull(points[],hull[],clockwise,retirnPoints)

  • point是我們要傳入的輪廓
  • hull 輸出,通常不需要
  • clockwise 方向標志,如果設置為True,輸出的凸包是順時針方向的,否則為逆時針方向
  • returnPoints 默認為True。它會返回凸包上點的坐標。如果設置為False,則會返回凸包點對應於原輪廓上的點坐標

  實際操作中,不如需要獲得上面的凸包,只需要:

  hull = cv2.convexHull(cnt)

即可。但是如果你想獲得凸性缺陷,需要把returnPoints設置為False。以上面的矩形為例,在獲取他的輪廓cnt后,先把returnPoin設置為True查找凸包,會得到矩形的四個角點坐標。再將returnPoints設為False,將得到輪廓點的索引,即前面的四個坐標在原輪廓中的序列位置。

# -*- coding:utf-8 -*-

import numpy as np
import cv2
from matplotlib import pyplot as plt

im = cv2.imread('9.png')
img = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)#用這個方式轉換的原因是最后輸出時希望能看到彩色的的輪廓圖
ret,thresh = cv2.threshold(img,127,255,0)

img,contours,hierarchy = cv2.findContours(thresh,1,2)
cnt = contours[0]

hull = cv2.convexHull(cnt,returnPoints=True)
print(hull)

# cv2.drawContours(im,hull,-1,(0,0,255),3) #該函數只能畫出幾個點
cv2.polylines(im, [hull], True, (0, 255, 0), 2)#需要用這個函數才能畫出輪廓,中間的True也是指示是否為閉曲線的

cv2.imshow('img',im)
cv2.waitKey(0)

 

設置為True時得到的結果是

[[[161 126]]

 [[  8 126]]

 [[  8  10]]

 [[161  10]]]

是矩形四個角點的坐標

設置為False后

[[113]
 [ 60]
 [  0]
 [126]]  

表示的是上面四個點在cnt中的索引號,且不能畫出凸包了

 

6.凸性檢測

  就是檢測一個曲線是不是凸的,只能返回True和False

  k = cv2.isContourConvex(cnt)

7.邊界矩形

  有兩類邊界矩形。

  直邊界矩形 一個直矩形(就是沒有旋轉的矩形)。它不會考慮對象是否旋轉。所以邊界矩形的面積不是最小的。可以使用函數cv2.boundingRect()查找得到的。

  x,y,w,h = cv2.boundingRect(cnt)
  img = cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2)

   返回值中,(x,y)是矩陣左上角的坐標,(w,h)是舉行的寬和高。

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

 
        
# -*- coding:utf-8 -*-

import numpy as np
import cv2
from matplotlib import pyplot as plt

im = cv2.imread('10.png')
img = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)#用這個方式轉換的原因是最后輸出時希望能看到彩色的的輪廓圖
ret,thresh = cv2.threshold(img,127,255,0)

img,contours,hierarchy = cv2.findContours(thresh,1,2)
cnt = contours[0]

#直邊界矩形
x,y,w,h = cv2.boundingRect(cnt)
im = cv2.rectangle(im,(x,y),(x+w,y+h),(0,255,0),2)

#旋轉邊界矩形
s = cv2.minAreaRect(cnt)
a = cv2.boxPoints(s)
a = np.int0(a)#必須轉換a的類型才能用polylines中畫出,我也不知道為啥


cv2.polylines(im,[a],True,(0,0,255),3)

cv2.imshow('img',im)
cv2.waitKey(0)

最終效果如下:

  

 

  

8.最小外接圓

  函數cv2.minEnclosingCircle() 可以幫我們找到一個對象的外切圓。它是所有能夠包括對象的圓中面積中最小的一個。例程如下:

  # -*- coding:utf-8 -*-

import numpy as np
import cv2
from matplotlib import pyplot as plt

im = cv2.imread('10.png')
img = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)#用這個方式轉換的原因是最后輸出時希望能看到彩色的的輪廓圖
ret,thresh = cv2.threshold(img,127,255,0)

img,contours,hierarchy = cv2.findContours(thresh,1,2)
cnt = contours[0]

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

# cv2.polylines(im,[a],True,(0,0,255),3)

cv2.imshow('img',im)
cv2.waitKey(0)

 

 9.橢圓擬合

  使用cv2.fitEllipse()找橢圓,返回值就是旋轉邊界矩形的內切圓。用cv2.ellipse()畫橢圓

  # -*- coding:utf-8 -*-

import numpy as np
import cv2
from matplotlib import pyplot as plt

im = cv2.imread('10.png')
img = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)#用這個方式轉換的原因是最后輸出時希望能看到彩色的的輪廓圖
ret,thresh = cv2.threshold(img,127,255,0)

img,contours,hierarchy = cv2.findContours(thresh,1,2)
cnt = contours[0]

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


cv2.imshow('img',im)
cv2.waitKey(0)

 

10.直線擬合

  類似ゆ根據一組點擬合出一條直線,也可以根據 圖像中的白色點擬合出一條直線,不過過程較為復雜

  書上的例程如下:

# -*- coding:utf-8 -*-

import numpy as np
import cv2
from matplotlib import pyplot as plt

im = cv2.imread('10.png')
img = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)#用這個方式轉換的原因是最后輸出時希望能看到彩色的的輪廓圖
ret,thresh = cv2.threshold(img,127,255,0)

img,contours,hierarchy = cv2.findContours(thresh,1,2)
cnt = contours[0]

rows,cols = im.shape[:2]
#cv2.fitLine(points, distType, param, reps, aeps[, line ]) → line
#points – Input vector of 2D or 3D points, stored in std::vector<> or Mat.
#line – Output line parameters. In case of 2D fitting, it should be a vector of
#4 elements (likeVec4f) - (vx, vy, x0, y0), where (vx, vy) is a normalized
#vector collinear to the line and (x0, y0) is a point on the line. In case of
#3D fitting, it should be a vector of 6 elements (like Vec6f) - (vx, vy, vz,
#x0, y0, z0), where (vx, vy, vz) is a normalized vector collinear to the line
#and (x0, y0, z0) is a point on the line.
#distType – Distance used by the M-estimator
#distType=CV_DIST_L2
#ρ(r) = r2 /2 (the simplest and the fastest least-squares method)
#param – Numerical parameter ( C ) for some types of distances. If it is 0, an optimal value
#is chosen.
#reps – Sufficient accuracy for the radius (distance between the coordinate origin and the
#line).
#aeps – Sufficient accuracy for the angle. 0.01 would be a good default value for reps and
#aeps.
[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)
im = cv2.line(im,(cols-1,righty),(0,lefty),(0,255,0),2)

cv2.imshow('img',im)
cv2.waitKey(0)

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM