1. 程式人生 > >opencv.cv2.findContours()函式

opencv.cv2.findContours()函式

轉自http://blog.csdn.net/sunny2038/article/details/12889059

OpenCV-Python介面中使用cv2.findContours()函式來查詢檢測物體的輪廓。

實現

使用方式如下:

  1. import cv2  
  2. img = cv2.imread('D:\\test\\contour.jpg')  
  3. gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)  
  4. ret, binary = cv2.threshold(gray,127,255,cv2.THRESH_BINARY)  
  5. contours, hierarchy = cv2.findContours(binary,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)  
  6. cv2.drawContours(img,contours,-1,(0,0,255),3)  
  7. cv2.imshow("img", img)  
  8. cv2.waitKey(0)  

需要注意的是cv2.findContours()函式接受的引數為二值圖,即黑白的(不是灰度圖),所以讀取的影象要先轉成灰度的,再轉成二值圖,參見4、5兩行。第六行是檢測輪廓,第七行是繪製輪廓。

結果

原圖如下:

檢測結果如下:

注意,findcontours函式會“原地”修改輸入的影象。這一點可通過下面的語句驗證:

  1. cv2.imshow("binary", binary)  
  2. contours, hierarchy = cv2.findContours(binary,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)  
  3. cv2.imshow("binary2", binary)  
執行這些語句後會發現原圖被修改了。

cv2.findContours()函式

函式的原型為

  1. cv2.findContours(image, mode, method[, contours[, hierarchy[, offset ]]])  
返回兩個值:contours:hierarchy。

引數

第一個引數是尋找輪廓的影象;

第二個引數表示輪廓的檢索模式,有四種(本文介紹的都是新的cv2介面):
    cv2.RETR_EXTERNAL表示只檢測外輪廓
    cv2.RETR_LIST檢測的輪廓不建立等級關係
    cv2.RETR_CCOMP建立兩個等級的輪廓,上面的一層為外邊界,裡面的一層為內孔的邊界資訊。如果內孔內還有一個連通物體,這個物體的邊界也在頂層。
    cv2.RETR_TREE建立一個等級樹結構的輪廓。

第三個引數method為輪廓的近似辦法
    cv2.CHAIN_APPROX_NONE儲存所有的輪廓點,相鄰的兩個點的畫素位置差不超過1,即max(abs(x1-x2),abs(y2-y1))==1
    cv2.CHAIN_APPROX_SIMPLE壓縮水平方向,垂直方向,對角線方向的元素,只保留該方向的終點座標,例如一個矩形輪廓只需4個點來儲存輪廓資訊
    cv2.CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS使用teh-Chinl chain 近似演算法

返回值

cv2.findContours()函式返回兩個值,一個是輪廓本身,還有一個是每條輪廓對應的屬性。

contour返回值

cv2.findContours()函式首先返回一個list,list中每個元素都是影象中的一個輪廓,用numpy中的ndarray表示。這個概念非常重要。在下面drawContours中會看見。通過
  1. print (type(contours))  
  2. print (type(contours[0]))  
  3. print (len(contours))  
可以驗證上述資訊。會看到本例中有兩條輪廓,一個是五角星的,一個是矩形的。每個輪廓是一個ndarray,每個ndarray是輪廓上的點的集合。

由於我們知道返回的輪廓有兩個,因此可通過

  1. cv2.drawContours(img,contours,0,(0,0,255),3)  
  1. cv2.drawContours(img,contours,1,(0,255,0),3)  
分別繪製兩個輪廓,關於該引數可參見下面一節的內容。同時通過
  1. print (len(contours[0]))  
  2. print (len(contours[1]))  
輸出兩個輪廓中儲存的點的個數,可以看到,第一個輪廓中只有4個元素,這是因為輪廓中並不是儲存輪廓上所有的點,而是隻儲存可以用直線描述輪廓的點的個數,比如一個“正立”的矩形,只需4個頂點就能描述輪廓了。

hierarchy返回值

此外,該函式還可返回一個可選的hiararchy結果,這是一個ndarray,其中的元素個數和輪廓個數相同,每個輪廓contours[i]對應4個hierarchy元素hierarchy[i][0] ~hierarchy[i][3],分別表示後一個輪廓、前一個輪廓、父輪廓、內嵌輪廓的索引編號,如果沒有對應項,則該值為負數。

通過

  1. print (type(hierarchy))  
  2. print (hierarchy.ndim)  
  3. print (hierarchy[0].ndim)  
  4. print (hierarchy.shape)  
得到
  1. 3
  2. 2
  3. (124)  
可以看出,hierarchy本身包含兩個ndarray,每個ndarray對應一個輪廓,每個輪廓有四個屬性。

輪廓的繪製

OpenCV中通過cv2.drawContours在影象上繪製輪廓。  

cv2.drawContours()函式

  1. cv2.drawContours(image, contours, contourIdx, color[, thickness[, lineType[, hierarchy[, maxLevel[, offset ]]]]])  
  • 第一個引數是指明在哪幅影象上繪製輪廓;
  • 第二個引數是輪廓本身,在Python中是一個list。
  • 第三個引數指定繪製輪廓list中的哪條輪廓,如果是-1,則繪製其中的所有輪廓。後面的引數很簡單。其中thickness表明輪廓線的寬度,如果是-1(cv2.FILLED),則為填充模式。繪製引數將在以後獨立詳細介紹。

補充:

寫著寫著發現一篇文章介紹不完,所以這裡先作為入門的。更多關於輪廓的資訊有機會再開一篇文章介紹。

但有朋友提出計算輪廓的極值點。可用下面的方式計算得到,如下

  1. pentagram = contours[1#第二條輪廓是五角星
  2. leftmost = tuple(pentagram[:,0][pentagram[:,:,0].argmin()])  
  3. rightmost = tuple(pentagram[:,0][pentagram[:,:,0].argmin()])  
  4. cv2.circle(img, leftmost, 2, (0,255,0),3)   
  5. cv2.circle(img, rightmost, 2, (0,0,255),3)   

注意!假設輪廓有100個點,OpenCV返回的ndarray的維數是(100, 1, 2)!!!而不是我們認為的(100, 2)。切記!!!人民郵電出版社出版了一本《NumPy攻略:Python科學計算與資料分析》,推薦去看一下。

更新:關於pentagram[:,0]的意思

在numpy的陣列中,用逗號分隔的是軸的索引。舉個例子,假設有如下的陣列:

  1. a = np.array([[[3,4]], [[1,2]],[[5,7]],[[3,7]],[[1,8]]])  
其shape是(5, 1, 2)。與我們的輪廓是相同的。那麼a[:,0]的結果就是:
  1. [3,4], [1,2], [5,7], [3,7], [1,8]  
這裡a[:,0]的意思就是a[0:5,0],也就是a[0:5,0:0:2],這三者是等價的

回頭看一下,a的shape是(5,1,2),表明是三個軸的。在numpy的陣列中,軸的索引是通過逗號分隔的。同時冒號索引“:”表示的是該軸的所有元素。因此a[:, 0]表示的是第一個軸的所有元素和第二個軸的第一個元素。在這裡既等價於a[0:5, 0]。

再者,若給出的索引數少於陣列中總索引數,則將已給出的索引樹預設按順序指派到軸上。比如a[0:5,0]只給出了兩個軸的索引,則第一個索引就是第一個軸的,第二個索引是第二個軸的,而第三個索引沒有,則預設為[:],即該軸的所有內容。因此a[0:5,0]也等價於a[0:5,0:0:2]。

再詳細一點,a的全體內容為:[[[3,4]], [[1,2]],[[5,7]],[[3,7]],[[1,8]]]。去掉第一層方括號,其中有五個元素,每個元素為[[3,4]]這樣的,所以第一個索引的範圍為[0:5]。注意OpenCV函式返回的多維陣列和常見的numpy陣列的不同之處!

觀察[[3,4]],我們發現其中只有一個元素,即[3, 4],第二個索引為[0:1]。

再去掉一層方括號,我們面對的是[3,4],有兩個元素,所以第三個索引的範圍為[0:2]。

再次強調一下OpenCVPython介面函式返回的NumPy陣列和普通的NumPy陣列在組織上的不同之處。

PS:OpenCV-Python討論群——219962286,歡迎大家加入互相探討學習。

得到的結果為如下:


參考資料:

1、《Opencv2 Computer Vision Application Programming Cookbook》

2、《OpenCV References Manule》

相關推薦

opencv.cv2.findContours()函式

轉自http://blog.csdn.net/sunny2038/article/details/12889059 OpenCV-Python介面中使用cv2.findContours()函式來查詢檢測物體的輪廓。 實現 使用方式如下: import cv2

OpenCVfindContours函式解讀

轉載自:http://blog.csdn.net/u012062327 參考:opencv documentation findContours()函式原型: void findContours(InputOutputArray image, OutputArrayOfA

OpenCVfindContours函式的使用

從二值影象中找出物件的輪廓: OpenCV中函式findContours()用於中物件的輪廓,有兩種形式: 第一種: void findContours( InputOutputArray image, OutputArrayOfArrays contours,      

OpenCVfindcontours函式hierarchy輪廓層級詳解

最近在查閱OpenCV輪廓處理函式方面時,我發現有部分文章對findcontours函式中輪廓層級提取的描述有錯誤,特寫一篇有關輪廓提取方面的文章(僅僅介紹容易出錯的hierarchy層級輪廓)。 函式原型為:findContours(image,contours,hier

Python opencv2和opencv3中的cv2.findContours函式使用

接著上一個部落格:關於 Python opencv 使用中的 ValueError: too many values to unpack(http://blog.csdn.net/caicai2526/article/details/79627370)介紹cv2

opencv中的cv2.cvtColor()函式中將BGR圖轉換為YCrCb及YCR_CB所使用的公式及程式碼驗證

【時間】2018.11.13 【題目】opencv中的cv2.cvtColor()函式中將BGR圖轉換為YCrCb及YCR_CB所使用的公式及程式碼驗證 概述 在opencv中,可以使用cv2.cvtColor()函式將BGR圖轉換為YCrCb及YCR_CB,本文主要講述他們所使用的由B

opencv輪廓檢測之FindContours函式演算法解釋

在檢測物體的輪廓時,我們通常會使用到opencv中的findcontour和drawcontour,比較常用而且效果不錯。 1985年,satoshi suzuki發表了一篇論文,Topological structural analysis of digitized bi

Opencv關於findcontours中斷問題

class OS ont 問題解決 堆棧 tours dll xxxx 版本     本人是VS2012+CV3.0,最近幾天需要用到findcontours函數,但是缺總是遇到中斷和 (xxxx.dll)什麽訪問不了,總之就是百度到的是堆棧問題。通過百度各種解決就是不行

OpenCV-Python官方文件三——在OpenCV中繪製函式

在OpenCV中繪製函式 目標 · 學習使用OpenCV繪製不同的幾何形狀 · 您將學習以下函式:cv2.line(),cv2.circle(),cv2.rectangle(),cv2.ellipse(),cv2.putText()等。 程式碼  &nbs

opencv之type()函式返回值對應表

opencv之type()函式返回值對應表 cv::Mat 類的物件有一個成員函式 type() 用來返回矩陣元素的資料型別,返回值是 int 型別,不同的返回值代表不同的型別。 int Mat::type() const 返回值與具體型別對應關係表: | |C1| C2| C3| C4| --|--|

最近鄰插值和雙線性插值的基本原理 以及OpenCV中resize函式的用法改變影象的大小

最近鄰插值和雙線性插值的基本原理 影象的縮放很好理解,就是影象的放大和縮小。傳統的繪畫工具中,有一種叫做“放大尺”的繪畫工具,畫家常用它來放大圖畫。當然,在計算機上,我們不再需要用放大尺去放大或縮小影象了,把這個工作交給程式來完成就可以了。下面就來講講計算機怎麼來放大縮小圖象;在本文中,

opencv之GaussianBlur()函式

opencv之GaussianBlur()函式 2018年04月17日 16:42:50 duwangthefirst 閱讀數:1507 標籤: opencvGaussianFilter高斯濾波影象去噪影象平滑 更多 個人分類: O

Opencv中copyTo()函式的使用方法

https://www.cnblogs.com/phoenixdsg/p/8420716.html 在Mat矩陣類的成員函式中copyTo(roi , mask)函式是非常有用的一個函式,尤其是後面的mask可以實現蒙版的功能,我們用幾個例項來說明它的作用。我們要注意mask的資料型別,必須是C

opencv 平行計算函式 parallel_for_的使用

opencv 平行計算函式 parallel_for_ 前面的話 在使用opencv的過程中,對圖片的處理計算量還是很大的,所以在實施執行的程式中如何高效的計算會節省很多時間。現有的方法有很多,如OpenMp,TBB,OpenCL,當然還有Nvidia的CUDA。  但是OpenMP在wi

0005-用OpenCV的resize函式實現影象的縮放

影象縮放是什麼意思這裡不用說了吧! 在OpenCV中用resize函式實現影象的縮放,下面介紹這個函式!resize函式原型如下: C++: void resize(InputArray src, OutputArray dst, Size dsize, double fx=0, double fy

0024-利用OpenCV的filter2D函式作影象的卷積操作和協相關操作

影象的卷積操作是影象處理中最常用的操作之一,一般是用核算子來實現卷積操作。什麼叫核算子?請移步博文https://blog.csdn.net/lehuoziyuan/article/details/84101788 OpenCV用函式filter2D來實現對影象或矩陣的卷積操作。這個函式本質上做

0019-用OpenCV的distanceTransform函式作影象的距離變換

距離變換運算用於計算二值化影象中的每一個非零點距自己最近的零點的距離,距離變換影象上越亮的點,代表了這一點距離零點的距離越遠。距離變換通常用於細化字元的輪廓和查詢物體的質心(中心)。 OpenCV提供了distanceTransform函式用於計算二值化影象的距離變換。這個函式的原型如下: C++:

0030-用OpenCV的inpaint函式做影象的汙點修復

OpenCV提供了inpaint函式做影象的汙點修復,它是基於畫素鄰域計算進行的修復,原型如下: C++: void inpaint(InputArray src, InputArray inpaintMask, OutputArray dst, double inpaintRadius, int

0027-用OpenCV的GaussianBlur函式做高斯濾波

高斯濾波器是一類根據高斯函式的形狀來選擇權值的線性平滑濾波器,聽說高斯濾波器對於服從正太分佈(高斯分佈)的噪聲非常有效,然而實際來看,貌似效果也不怎麼樣啊,具體的大家可以看本篇帖子程式碼的執行結果,是筆者哪裡沒操作對麼?GaussianBlur函式原型如下: C++: void GaussianBl

opencv--基本常用函式【1】

載入影象 函式原型 imread() Mat cv :: imread(const String& 檔名, //要載入的檔案的名稱 INT flags =IMREAD_COLOR //可以採用cv :: ImreadModes值的標誌 )