網站首頁 編程語言 正文
注: 這篇文章用的OpenCV版本是2.4.10, 3以上的OpenCV版本相關函數可能有改動
Opencv中通過使用findContours函數,簡單幾個的步驟就可以檢測出物體的輪廓,很方便。這些準備繼續探討一下findContours方法中各參數的含義及用法,比如要求只檢測最外層輪廓該怎么辦?contours里邊的數據結構是怎樣的?hierarchy到底是什么鬼?Point()有什么用?
先從findContours函數原型看起:
findContours( InputOutputArray image, OutputArrayOfArrays contours, OutputArray hierarchy, int mode, int method, Point offset=Point());
第一個參數:image,單通道圖像矩陣,可以是灰度圖,但更常用的是二值圖像,一般是經過Canny、拉普拉斯等邊緣檢測算子處理過的二值圖像;
第二個參數:contours,定義為“vector<vector<Point>> contours”,是一個向量,并且是一個雙重向量,向量內每個元素保存了一組由連續的Point點構成的點的集合的向量,每一組Point點集就是一個輪廓。 ?
有多少輪廓,向量contours就有多少元素。
第三個參數:hierarchy,定義為“vector<Vec4i> hierarchy”,先來看一下Vec4i的定義:
typedef ? ?Vec<int, 4> ? Vec4i;;
Vec4i是Vec<int,4>的別名,定義了一個“向量內每一個元素包含了4個int型變量”的向量。
所以從定義上看,hierarchy也是一個向量,向量內每個元素保存了一個包含4個int整型的數組。
向量hiararchy內的元素和輪廓向量contours內的元素是一一對應的,向量的容量相同。
hierarchy向量內每一個元素的4個int型變量——hierarchy[i][0] ~hierarchy[i][3],分別表示第i個輪廓的后一個輪廓、前一個輪廓、父輪廓、內嵌輪廓的索引編號。如果當前輪廓沒有對應的后一個輪廓、前一個輪廓、父輪廓或內嵌輪廓的話,則hierarchy[i][0] ~hierarchy[i][3]的相應位被設置為默認值-1。
第四個參數:int型的mode,定義輪廓的檢索模式:
取值一:CV_RETR_EXTERNAL只檢測最外圍輪廓,包含在外圍輪廓內的內圍輪廓被忽略
取值二:CV_RETR_LIST ? 檢測所有的輪廓,包括內圍、外圍輪廓,但是檢測到的輪廓不建立等級關系,彼此之間獨立,沒有等級關系,這就意味著這個檢索模式下不存在父輪廓或內嵌輪廓,所以hierarchy向量內所有元素的第3、第4個分量都會被置為-1,具體下文會講到
取值三:CV_RETR_CCOMP ?檢測所有的輪廓,但所有輪廓只建立兩個等級關系,外圍為頂層,若外圍內的內圍輪廓還包含了其他的輪廓信息,則內圍內的所有輪廓均歸屬于頂層
取值四:CV_RETR_TREE, 檢測所有輪廓,所有輪廓建立一個等級樹結構。外層輪廓包含內層輪廓,內層輪廓還可以繼續包含內嵌輪廓。
第五個參數:int型的method,定義輪廓的近似方法:
取值一:CV_CHAIN_APPROX_NONE 保存物體邊界上所有連續的輪廓點到contours向量內
取值二:CV_CHAIN_APPROX_SIMPLE 僅保存輪廓的拐點信息,把所有輪廓拐點處的點保存入contours向量內,拐點與拐點之間直線段上的信息點不予保留
取值三和四:CV_CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS使用teh-Chinl chain 近似算法
第六個參數:Point偏移量,所有的輪廓信息相對于原始圖像對應點的偏移量,相當于在每一個檢測出的輪廓點上加上該偏移量,并且Point還可以是負值!
下邊用效果圖對比一下findContours函數中各參數取不同值時,向量contours和hierarchy的內容如何變化,有何異同。
主體程序如下:
#include "core/core.hpp" #include "highgui/highgui.hpp" #include "imgproc/imgproc.hpp" #include "iostream" using namespace std; using namespace cv; int main(int argc,char *argv[]) { Mat imageSource=imread(argv[1],0); imshow("Source Image",imageSource); Mat image; GaussianBlur(imageSource,image,Size(3,3),0); Canny(image,image,100,250); vector<vector<Point>> contours; vector<Vec4i> hierarchy; findContours(image,contours,hierarchy,RETR_TREE,CHAIN_APPROX_SIMPLE,Point()); Mat imageContours=Mat::zeros(image.size(),CV_8UC1); Mat Contours=Mat::zeros(image.size(),CV_8UC1); //繪制 for(int i=0;i<contours.size();i++) { //contours[i]代表的是第i個輪廓,contours[i].size()代表的是第i個輪廓上所有的像素點數 for(int j=0;j<contours[i].size();j++) { //繪制出contours向量內所有的像素點 Point P=Point(contours[i][j].x,contours[i][j].y); Contours.at<uchar>(P)=255; } //輸出hierarchy向量內容 char ch[256]; sprintf(ch,"%d",i); string str=ch; cout<<"向量hierarchy的第" <<str<<" 個元素內容為:"<<endl<<hierarchy[i]<<endl<<endl; //繪制輪廓 drawContours(imageContours,contours,i,Scalar(255),1,8,hierarchy); } imshow("Contours Image",imageContours); //輪廓 imshow("Point of Contours",Contours); //向量contours內保存的所有輪廓點集 waitKey(0); return 0; }
程序中所用原始圖像如下:
通過調整第四個參數mode——輪廓的檢索模式、第五個參數method——輪廓的近似方式和不同的偏移量Point(),就可以得到以下效果。
一、mode取值“CV_RETR_EXTERNAL”
method取值“CV_CHAIN_APPROX_NONE”,即只檢測最外層輪廓,并且保存輪廓上所有點:
輪廓:
只有最外層的輪廓被檢測到,內層的輪廓被忽略
contours向量內所有點集:
保存了所有輪廓上的所有點,圖像表現跟輪廓一致
hierarchy向量:
重溫一下hierarchy向量————向量中每個元素的4個整形分別對應當前輪廓的后一個輪廓、前一個輪廓、父輪廓、內嵌輪廓的索引編號。
本次參數配置下,hierarchy向量內有3個元素,分別對應于3個輪廓。以第2個輪廓(對應向量內第1個元素)為例,內容為[2,0,-1,-1], “2”表示當前輪廓的后一個輪廓的編號為2,“0”表示當前輪廓的前一個輪廓編號為0,其后2個“-1”表示為空,因為只有最外層輪廓這一個等級,所以不存在父輪廓和內嵌輪廓。
二、 mode取值“CV_RETR_LIST”
method取值“CV_CHAIN_APPROX_SIMPLE”,即檢測所有輪廓,但各輪廓之間彼此獨立,不建立等級關系,并且僅保存輪廓上拐點信息:
檢測到的輪廓跟上文“一”中是一致的,不再顯示。
contours向量內所有點集:
contours向量中所有的拐點信息得到了保留,但是拐點與拐點之間直線段的部分省略掉了。
hierarchy向量(截取一部分):
本次參數配置下,檢測出了較多輪廓。第1、第2個整形值分別指向上一個和下一個輪廓編號,由于本次配置mode取
值“RETR_LIST”,各輪廓間各自獨立,不建立等級關系,所以第3、第4個整形參數為空,設為值-1。
三、mode取值“CV_RETR_TREE”
method取值“CV_CHAIN_APPROX_NONE”,即檢測所有輪廓,輪廓間建立外層、內層的等級關系,并且保存輪廓上所有點。
contours向量內所有點集:
所有內外層輪廓都被檢測到,contours點集組成的圖形跟輪廓表現一致。
hierarchy向量(截取一部分)
本次參數配置要求檢測所有輪廓,每個輪廓都被劃分等級,最外圍、第一內圍、第二內圍等等,所以除第1個最后一個輪廓外,其他輪廓都具有不為-1的第3、第4個整形參數,分別指向當前輪廓的父輪廓、內嵌輪廓索引編號。
四、Point()偏移量設置
使用三中的參數配置,設置偏移量Point為Point(45,30)。
此時輪廓圖像為:
可以看到輪廓圖像整體向右下角有一個偏轉,偏轉量就是設置的(45,30)。
這個偏移量的設置不能過大或過?。ㄘ摲较蛏系倪^?。?,若圖像上任一點加上該偏移量后超出圖像邊界,程序會內存溢出報錯。
findContours函數的各參數就探討到此,其他參數配置的情況大同小異。值得關注一下的是繪制輪廓的函數drawContours中最后一個參數是一個Point類型的offset,這個offset跟findContours函數中的offset含義一致,設置之后所繪制的輪廓是原始輪廓上所有像素點加上該偏移量offset后的效果。
當所分析圖像是另外一個圖像的ROI的時候,這個offset偏移量就可以大顯身手了。通過加減這個偏移量,就可以把ROI圖像的檢測結果投影到原始圖像對應位置上。
原文鏈接:https://blog.csdn.net/dcrmg/article/details/51987348
相關推薦
- 2022-05-09 python中pip安裝庫時出現Read?timed?out解決辦法_python
- 2022-06-15 axios?gin的GET和POST請求實現示例_Golang
- 2022-12-24 C#?Math中常用數學運算的示例詳解_C#教程
- 2023-02-05 Flutter實現固定header底部滑動頁效果示例_Android
- 2022-07-25 Android自定義View原理(實戰)_Android
- 2022-12-01 Flutter路由框架Fluro使用教程詳細講解_Android
- 2022-12-08 C語言程序如何求學生總成績和平均成績_C 語言
- 2022-04-16 python用socket實現協議TCP長連接框架_python
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支