1. 程式人生 > >opencv 影象輪廓處理

opencv 影象輪廓處理

1、 初識輪廓

目標
理解什麼是輪廓
學習找輪廓,繪製輪廓函式: cv2.findContours(), cv2.drawContours()

1.1 什麼是輪廓

  輪廓可以簡單認為成將連續的點(連著邊界)連在一起的曲線,具有相同的顏色或者灰度。輪廓在形狀分析和物體的檢測和識別中很有用。
  • 為了更加準確,要使用二值化影象。在尋找輪廓之前,要進行閾值化處理或者 Canny 邊界檢測。
  • 查詢輪廓的函式會修改原始影象。如果你在找到輪廓之後還想使用原始影象的話,你應該將原始影象儲存到其他變數中。
  • 在 OpenCV 中,查詢輪廓就像在黑色背景中超白色物體,要找的物體應該是白色而背景應該是黑色。
讓我們看看如何在一個二值影象中查詢輪廓:
  函式 cv2.findContours() 有三個引數,第一個是輸入影象,第二個是輪廓檢索模式,第三個是輪廓近似方法。返回值有三個,第一個是影象,第二個是輪廓,第三個是(輪廓的)層析結構。輪廓(第二個返回值)是一個 Python列表,其中儲存這影象中的所有輪廓。每一個輪廓都是一個 Numpy 陣列,包含物件邊界點(x, y)的座標。
注意:我們後邊會對第二和第三個引數,以及層次結構進行詳細介紹。在那之
前,例子中使用的引數值對所有影象都是適用的。

1.2 怎樣繪製輪廓

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

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

im = cv2.imread('image/2.png')
imgray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(imgray, 127
, 255, 0) image,contours,hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) #img = cv2.drawContour(image, contours, -1, (0,255,0),3) img = cv2.drawContours(image, contours, 3, (0,255,0),3) #兩種方法效果相似,大多數使用第二種方法 plt.subplot(121), plt.imshow(im) plt.title("Original"),plt.xticks([]),plt.yticks([]) plt.subplot(122
), plt.imshow(img) plt.title("Contours"),plt.xticks([]),plt.yticks([]) plt.show()

結果圖:
這裡寫圖片描述

1.3 輪廓的近似方法

  這是函式 cv2.findCountours() 的第三個引數。它到底代表什麼意思呢?上邊我們已經提到輪廓是一個形狀具有相同灰度值的邊界。它會存貯形狀邊界上所有的 (x, y) 座標。但是需要將所有的這些邊界點都儲存嗎?這就是這個引數要告訴函式 cv2.findContours 的。
  這個引數如果被設定為 cv2.CHAIN_APPROX_NONE,所有的邊界點都會被儲存。但是我們真的需要這麼多點嗎?例如,當我們找的邊界是一條直線時,需要直線上所有的點來表示直線嗎?不是的,我們只需要這條直線
的兩個端點而已。這就是 cv2.CHAIN_APPROX_SIMPLE 要做的。它會將輪廓上的冗餘點都去掉,壓縮輪廓,從而節省記憶體開支。
  用下圖中的矩形來演示這個技術。在輪廓列表中的每一個座標上畫一個藍色圓圈。第一個圖顯示使用 cv2.CHAIN_APPROX_NONE 的效果,一共 734 個點。第二個圖是使用 cv2.CHAIN_APPROX_SIMPLE 的結
果,只有 4 個點.
效果圖:
這裡寫圖片描述

2、 輪廓特徵

目標
查詢輪廓的不同特徵,例如面積,周長,重心,邊界框等。
學習輪廓相關函式

2.1 矩

  影象的矩可以幫助我們計算影象的質心,面積等。詳細資訊請檢視維基百科Image Moments。
  函式 cv2.moments() 會將計算得到的矩以一個字典的形式返回。如下:

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

img = cv2.imread('image/7.png')
imgray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(imgray, 127, 255, 0)
contours,hierarchy = cv2.findContours(thresh, 1,2)
cnt = contours[0]
M = cv2.moments(cnt)
print M 

根據這些矩的值,我們可以計算出物件的重心: Cx = M10/ M00 , Cy = M 01/M00

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

2.2 輪廓面積、周長

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

area = cv2.contourArea(cnt)

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

perimeter = cv2.arcLength(cnt,True)

2.3 輪廓近似

  將輪廓形狀近似到另外一種由更少點組成的輪廓形狀,新輪廓的點的數目由我們設定的準確度來決定。使用的Douglas-Peucker演算法,你可以到維基百科獲得更多此演算法的細節。
  為了幫助理解,假設我們要在一幅影象中查詢一個矩形,但是由於影象的種種原因,我們不能得到一個完美的矩形,而是一個“壞形狀”(如下圖所示)。現在你就可以使用這個函式來近似這個形狀()了。這個函式的第二個引數叫epsilon,它是從原始輪廓到近似輪廓的最大距離。它是一個準確度引數。選擇一個好的 epsilon 對於得到滿意結果非常重要。

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

  下邊,第二幅圖中的綠線是當 epsilon = 10% 時得到的近似輪廓,第三幅圖是當 epsilon = 1% 時得到的近似輪廓。第三個引數設定弧線是否閉合。
這裡寫圖片描述
參考:OpenCV官方教程中文版(For Python)