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使用内置的近似,其他模式均使用此设定的近似算法)。可取值如下:
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的轮廓查找和填充相关推荐
- 基于OpencV的轮廓填充算法在3D打印机中的应用
在这之前,我们需要了解一下SLC文件的格式,只有对格式有一点了解,我们才能做接下来的工作,首先SLC文件中是通过描述各层中的多段线来描述整个模型的,多段线之间两两相连.对单个轮廓来说,最后一点必须等于 ...
- 【OpenCv】图像的轮廓查找
1 原理 边界或者轮廓可以简单认为成将连续的点(连着边界)连在一起的曲线,具有相同的颜色或者灰度.轮廓在形状分析和物体的检测和识别中很有用. 在机器视觉领域最常用的轮廓查找的算法之一是 Moore ...
- 使用Python,OpenCV进行涂鸦(绘制文字、线、圆、矩形、椭圆、多边形轮廓、多边形填充、箭头~)
使用Python,OpenCV进行涂鸦(绘制文字.线.圆.矩形.椭圆.多边形轮廓.多边形填充.箭头) 1. 效果图 2. 原理 2.1 绘制线:cv2.line(canvas, (300, 0), ( ...
- python使用opencv查找轮廓_(八)OpenCV-Python学习—轮廓查找,绘制和拟合
针对物体轮廓,opencv还提供了一些相关的函数,来处理轮廓查找,绘制,拟合,以及计算轮廓周长和面积等,详细介绍如下: 1. 寻找和绘制轮廓 opencv的findContours()能寻找图片中的轮 ...
- opencv 轮廓查找, 凸包,最小外接矩形,最小外接圆,最小外接椭圆
本章内容: 1. 轮廓查找 2. 绘制轮廓 3. 凸包 4.最小外接矩形 5.最小外接圆 6.最小外接椭圆 1.搜索轮廓 2.绘制轮廓 输出结果 3.凸包 输出结果 4.最小外接矩形 输出结果 5.最 ...
- openCV 轮廓查找-测量物体尺寸
一,利用openCV的findContours轮廓查找功能,用已知物体的尺寸(比如硬币)作为参考,根据实际尺寸与像素尺寸的比列,求出图片中物体的实际大小.存在的问题有两个: 图片的阴影导致轮廓不准确, ...
- Python机器视觉--OpenCV进阶(核心)--图像轮廓查找识别,绘制图像轮廓与图像轮廓的面积周长计算
1.图像轮廓查找识别与绘制图像轮廓 1.1 什么是图像轮廓 图像轮廓是具有相同颜色或灰度的连续点的曲线. 轮廓在形状分析和物体的检测和识别中很有用. 轮廓的作用: 用于图形分析 物体的识别和检测 注意 ...
- OpenCV使用findContours查找轮廓和相关函数——C++
OpenCV使用findContours查找轮廓和相关函数--C++ findContours函数的使用 findContours函数的使用 //查找前景的区域 vector<vector< ...
- OPENCV图像轮廓检测
前面在图像转换的时候学到canny算子,可以检测出图像的轮廓信息,但是,该算子检测到的轮廓信息还需要我们手动的用眼睛去识别,而实际工程应用中,我们需要得到轮廓的具体数学信息,这就涉及到今天的主题,图像 ...
最新文章
- CNN、RNN、GAN都是什么?终于有人讲明白了
- python3 操作redis
- tensorflow打印模型图_从Tensorflow模型文件中解析并显示网络结构图(pb模型篇)...
- php原生sql语法,thinkphp执行原生SQL语句的实现方法
- 判断字符串是否构成回文_构成字符串回文的最小删除数
- (二)容器从入门到深入-初识Kubernetes
- PHP类: SEO必备的伪原创工具 (文章重写)
- linux mdamd工具安装,ubuntu 13.04amd64安装 wine 1.5 office2010
- 【超参数寻优】交叉验证(Cross Validation)超参数寻优的python实现:多参数寻优
- 2018-2019-1 20189204《Linux内核原理与分析》第一周作业
- python语言中strike_基于Python的XSS测试工具XSStrike使用方法
- java计算机毕业设计HTML5旅游网站源码+mysql数据库+系统+lw文档+部署
- 语音增强论文翻译:2017_SEGAN: Speech Enhancement Generative Adversarial Network
- python中1 100的质数_Python求解1到100之间的质数
- python 爬虫 中乱码问题0xb5 和b'\x1f\x8b\x08
- java实现学生信息管理系统
- 基于Python实现的学生信息管理系统
- StarUML 3 中文文档 活动图
- 基于3D关节点的人体动作识别综述(转)
- 【Linux】报错:cp: omitting directory...