日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

OpenCV的轮廓查找和填充

發布時間:2025/3/21 编程问答 50 豆豆
生活随笔 收集整理的這篇文章主要介紹了 OpenCV的轮廓查找和填充 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

OpenCV的輪廓查找有C版本和C++版本,當輪廓比較復雜的時候,例如嵌入多層輪廓,如果方法不當那么很容易會漏處理一些輪廓。本文介紹了復雜輪廓場景下的幾種主要的查找輪廓和顏色填充方法。

1:cvFindContours函數介紹

int?cvFindContours( CvArr* image, CvMemStorage* storage, CvSeq** first_contour, int header_size=sizeof(CvContour), int

? ? ? ? mode=CV_RETR_LIST, ?int method=CV_CHAIN_APPROX_SIMPLE, CvPoint offset=cvPoint(0,0) );

image:?8比特單通道的源二值圖像。非零像素作為1處理,0像素保存不變。從一個灰度圖像得到二值圖像的函數有:cvThreshold,cvAdaptiveThreshold和cvCanny。

storage:?返回輪廓的容器。

first_contour:?輸出參數,用于存儲指向第一個外接輪廓。

header_size:?header序列的尺寸.如果選擇method = CV_CHAIN_CODE, 則header_size >= sizeof(CvChain);其他,則 header_size >= sizeof(CvContour)。

mode:

CV_RETR_EXTERNAL:只檢索最外面的輪廓;
CV_RETR_LIST:檢索所有的輪廓,并將其放入list中;
CV_RETR_CCOMP:檢索所有的輪廓,并將他們組織為兩層:頂層是各部分的外部邊界,第二層是空洞的邊界;
CV_RETR_TREE:檢索所有的輪廓,并重構嵌套輪廓的整個層次。

method:?邊緣近似方法(除了CV_RETR_RUNS使用內置的近似,其他模式均使用此設定的近似算法)??扇≈等缦?#xff1a;

CV_CHAIN_CODE:以Freeman鏈碼的方式輸出輪廓,所有其他方法輸出多邊形(頂點的序列)。
CV_CHAIN_APPROX_NONE:將所有的連碼點,轉換成點。
CV_CHAIN_APPROX_SIMPLE:壓縮水平的、垂直的和斜的部分,也就是,函數只保留他們的終點部分。
CV_CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS:使用the flavors of Teh-Chin chain近似算法的一種。
CV_LINK_RUNS:通過連接水平段的1,使用完全不同的邊緣提取算法。使用CV_RETR_LIST檢索模式能使用此方法。

offset:偏移量,用于移動所有輪廓點。當輪廓是從圖像的ROI提取的,并且需要在整個圖像中分析時,這個參數將很有用。

討論部分cvDrawContours中的案例顯示了任何使用輪廓檢測連通區域。輪廓可以用于形狀分析和目標識別——可以參考文件夾OpenCV sample中的squares.c

2:找輪廓及顏色填充

方法1:樹形遍歷

? ? ? ? 由contours的h_next和 v_next指針組成一個龐大的樹形結構,如下面的圖示,其中藍色表示v_next,綠色表示h_next。如果不了解contours結構的話,很容易僅僅遍歷v_next或者h_next,這樣實際上會漏掉一些需要處理的輪廓。要全部遍歷所有輪廓需要編寫不少代碼,這個還沒搜索到直接用這種方式遍歷輪廓的代碼。需要注意的是,很多博文介紹的利用h_next或者v_next的方法都是會缺失不少輪廓的,輪廓的復雜會導致整個樹也變的很復雜,所以建議還是不要用這種方式來遍歷輪廓。我一開始用的就是這種方法,應該說是琢磨了好長時間,才知道為什么這種方法的輪廓數總是偏少。

?

?

方法2:cvFindNextContour方法

本方法是利用了輪廓掃描器CvContourScanner,使用cvStartFindContours、cvFindNextContour、cvEndFindContours函數獲取從外到內的輪廓,獲取一層輪廓進行一次顏色的填充。具體后面使用的原始輪廓圖如下所示:

#include “opencv/cv.h”
#include “opencv/highgui.h”
int main(int argc, char **argv)
{

IplImage * pSrcImg= cvLoadImage(“E:\\11.jpg”);
IplImage * pGrayImg =cvCreateImage(cvSize(pSrcImg->width,pSrcImg->height),IPL_DEPTH_8U,1);
IplImage * pThresholdImg =cvCreateImage(cvSize(pSrcImg->width,pSrcImg->height),IPL_DEPTH_8U,1);
IplImage * pDstImg =cvCreateImage(cvSize(pSrcImg->width,pSrcImg->height),IPL_DEPTH_8U,3);

cvSetZero(pDstImg);
srand((int)time(0)); ??
CvSeq * contours = 0;
CvMemStorage * storage=cvCreateMemStorage(0);
CvScalar color=cvScalar( rand()&255, rand()&255, rand()&255 );

cvCvtColor(pSrcImg,pGrayImg,CV_BGR2GRAY);
cvNot(pGrayImg,pGrayImg);
cvThreshold(pGrayImg,pThresholdImg,100,255,CV_THRESH_BINARY);
cvSet(pDstImg,color);

CvContourScanner scanner = cvStartFindContours(pThresholdImg, storage,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? sizeof(CvContour),CV_RETR_TREE ,CV_CHAIN_APPROX_NONE);
while (contours=cvFindNextContour(scanner))
{

color=cvScalar( rand()&255, rand()&255, rand()&255 );
cvDrawContours(pDstImg, contours, color,color, 0,CV_FILLED);

};
contours= cvEndFindContours(&scanner);

cvSaveImage(“dst.jpg”,pDstImg);
cvReleaseImage(&pDstImg);
cvReleaseImage(&pGrayImg);
cvReleaseImage(&pThresholdImg);
cvReleaseMemStorage(&storage);
return 0;

}

?方法3:cvNextTreeNode方法

本方法是利用cvFindContours,先找到所有輪廓,再使用樹節點的迭代器CvTreeNodeIterator的函數cvNextTreeNode,獲取從外到內的輪廓,并進行顏色的填充。

#include “opencv/cv.h”
#include “opencv/highgui.h”

int main(int argc, char **argv)
{

IplImage * pSrcImg= cvLoadImage(“E:\\11.jpg”);
IplImage * pGrayImg =cvCreateImage(cvSize(pSrcImg->width,pSrcImg->height),IPL_DEPTH_8U,1);
IplImage * pThresholdImg =cvCreateImage(cvSize(pSrcImg->width,pSrcImg->height),IPL_DEPTH_8U,1);
IplImage * pDstImg =cvCreateImage(cvSize(pSrcImg->width,pSrcImg->height),IPL_DEPTH_8U,3);

cvSetZero(pDstImg);
srand((int)time(0));
CvSeq * contours = 0;
CvMemStorage * storage=cvCreateMemStorage(0);
CvScalar color=cvScalar( rand()&255, rand()&255, rand()&255 );

cvCvtColor(pSrcImg,pGrayImg,CV_BGR2GRAY);
cvNot(pGrayImg,pGrayImg);
cvThreshold(pGrayImg,pThresholdImg,100,255,CV_THRESH_BINARY);
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?cvFindContours(pThresholdImg,storage,&contours,sizeof(CvContour),
CV_RETR_TREE ,CV_CHAIN_APPROX_NONE);
cvSet(pDstImg,color);

CvTreeNodeIterator iterator;?
cvInitTreeNodeIterator(&iterator,contours,3);?
while( 0 != (contours = (CvSeq*)cvNextTreeNode(&iterator)) )?
{

color=cvScalar( rand()&255, rand()&255, rand()&255 );
cvDrawContours(pDstImg, contours, color,color, 0,CV_FILLED);

}
cvSaveImage(“dst.jpg”,pDstImg);
cvReleaseImage(&pDstImg);
cvReleaseImage(&pGrayImg);
cvReleaseImage(&pThresholdImg);
cvReleaseMemStorage(&storage);?
return 0;

}

方法4:?C++的iterator方法

本方法是利用OpenCV的C++函數findContours,獲取從外到內的輪廓,并利用const_iterator 來逐個找到所有的輪廓。從編碼的效果來看,最開始的輪廓是最外延的輪廓,然后逐漸找內部的輪廓,所以進行顏色填充的時候,不會出現外面的大輪廓覆蓋掉內部的小輪廓的問題。

#include “opencv/cv.h”
#include “opencv/highgui.h”

using namespace cv;

int main( int argc, char** argv )
{

vector<Vec4i> hierarchy;
vector<vector<Point> > contours;
vector<vector<Point>>::const_iterator itContours;

srand((int)time(0));
Mat src = imread(“E:\\11.jpg”,0);
Mat dst = Mat::zeros(src.rows, src.cols, CV_8UC3);
CvScalar color=cvScalar( rand()&255, rand()&255, rand()&255 );

src = src > 100;
findContours( src, contours, hierarchy, CV_RETR_TREE,CV_CHAIN_APPROX_NONE );

itContours=contours.begin();
int i=0;
for(;itContours!=contours.end();++itContours)
{

color=cvScalar( rand()&255, rand()&255, rand()&255 );
drawContours( dst,contours ,i, color, CV_FILLED );
i++;

}
imwrite(“dst.jpg”,dst);

}

必須采用for(;itContours!=contours.end();++itContours)的循環方式。

如果采用for(?;?idx?>=?0;?idx?=?hierarchy[idx][0]?)的循環方式,會導致大的輪廓顏色覆蓋掉其內部小的輪廓顏色。

?結果

如下為兩次運行的效果圖,其中C語言版本不會將整個圖片的外延作為一個輪廓,所以這部分顏色要額外先填充。

從編碼效率來看,C++版本的編碼效率要高于C版本,因為不需要考慮很多的內存的釋放等問題。

?

?

?

?

?

?

?

?

參考資料:

http://baike.baidu.com/view/4111188.htm

http://blog.csdn.net/augusdi/article/details/9000276

http://blog.csdn.net/augusdi/article/details/9000893

http://blog.csdn.net/timidsmile/article/details/8519751

聲明:

如果轉載了本文,也請注明轉載出處:http://www.cvrobot.net/opencv-find-and-draw-contours/

總結

以上是生活随笔為你收集整理的OpenCV的轮廓查找和填充的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。