【第二部分 图像处理】第3章 Opencv图像处理进阶【4 图像轮廓A】
2018-03-08 21:29
661 查看
3.1查找并绘制轮廓
1985年,satoshi suzuki发表的《Topological structural analysis of digitized binary images by border following》论文介绍了两种算法来实现轮廓的提取,当然输入的图像是二值图像。findcontour就是基于这篇论文的思路来实现。他主要介绍了两种算法,用来对数字二值图像进行拓扑分析。第一种算法是在确定二值图像边界的围绕关系,即确定外边界、孔边界以及他们的层次关系,由于这些边界和原图的区域具有一一对应关系(外边界对应像素值为1的连通区域,孔边界对应像素值为0的区域),因此我们就可以用边界来表示原图。第二种算法,是第一种算法的修改版本,本质一样,但是它只找最外面的边界。下面就跟着笔者一起使用OpenCV查找轮廓并绘制出来。
3.1.1查找并绘制轮廓API
3.1.1.1查找并绘制轮廓函数
寻找轮廓:findContours()函数C++:findContours( InputOutputArray image, OutputArrayOfArrays contours, OutputArray hierarchy, int mode, int method, Point offset=Point());
【参数】
第一个参数:image,单通道图像矩阵,可以是灰度图,但更常用的是二值图像,一般是经过Canny、拉普拉斯等边缘检测算子处理过的二值图像;
第二个参数:contours,定义为“vector
void findContours( InputOutputArray image, OutputArrayOfArrays contours, int mode, int method, Point offset = Point());
绘制轮廓:drawContours()函数
C++: void drawContours(InputOutputArray image, InputArrayOfArrays contours, int contourIdx, const Scalar& color, int thickness=1, 4000 int lineType=8, InputArray hierarchy=noArray(), int maxLevel=INT_MAX, Point offset=Point() )
【参数】
第一个参数,image – 目标图像,填充Mat的对象;
第二个参数,contours – 所有的输入轮廓。每一个轮廓都存储一个点向量,即point类型的 vector表示。
第三个参数,contourIdx – 轮廓绘制的指示。如果为负值,则绘制所有轮廓。
第四个参数,color – 轮廓的颜色。
第五个参数,thickness – Thickness of lines the contours are drawn with. If it is negative (for example, thickness=CV_FILLED ), the contour interiors are drawn.
第六个参数,lineType – Line connectivity. See line() for details.
第七个参数,hierarchy – Optional information about hierarchy. It is only needed if you want to draw only some of the contours (see maxLevel ).
第八个参数,maxLevel – Maximal level for drawn contours. If it is 0, only the specified contour is drawn. If it is 1, the function draws the contour(s) and all the nested contours. If it is 2, the function draws the contours, all the nested contours, all the nested-to-nested contours, and so on. This parameter is only taken into account when there is hierarchy available.
第九个参数,offset – Optional contour shift parameter. Shift all the drawn contours by the specified .
【注】OpenCV3在thickness的每个取值去掉了“CV_”。
3.1.1.2查找并绘制轮廓函数源码
寻找轮廓:findContours()函数/*【findContours ( )源代码】*********************************************************** * @Version:OpenCV 3.0.0(Opnencv2和Opnencv3差别不大,Linux和PC的对应版本源码完全一样,均在对应的安装目录下) * @源码路径:…\opencv\sources\modules\imgproc\src\ contours.cpp * @起始行数:1705行 ********************************************************************************/ void cv::findContours( InputOutputArray _image, OutputArrayOfArrays _contours, OutputArray _hierarchy, int mode, int method, Point offset ) { // Sanity check: output must be of type vector<vector<Point>> CV_Assert((_contours.kind() == _InputArray::STD_VECTOR_VECTOR || _contours.kind() == _InputArray::STD_VECTOR_MAT || _contours.kind() == _InputArray::STD_VECTOR_UMAT)); CV_Assert(_contours.empty() || (_contours.channels() == 2 && _contours.depth() == CV_32S)); Mat image = _image.getMat(); MemStorage storage(cvCreateMemStorage()); CvMat _cimage = image; CvSeq* _ccontours = 0; if( _hierarchy.needed() ) _hierarchy.clear(); cvFindContours(&_cimage, storage, &_ccontours, sizeof(CvContour), mode, method, offset); if( !_ccontours ) { _contours.clear(); return; } Seq<CvSeq*> all_contours(cvTreeToNodeSeq( _ccontours, sizeof(CvSeq), storage )); int i, total = (int)all_contours.size(); _contours.create(total, 1, 0, -1, true); SeqIterator<CvSeq*> it = all_contours.begin(); for( i = 0; i < total; i++, ++it ) { CvSeq* c = *it; ((CvContour*)c)->color = (int)i; _contours.create((int)c->total, 1, CV_32SC2, i, true); Mat ci = _contours.getMat(i); CV_Assert( ci.isContinuous() ); cvCvtSeqToArray(c, ci.ptr()); } if( _hierarchy.needed() ) { _hierarchy.create(1, total, CV_32SC4, -1, true); Vec4i* hierarchy = _hierarchy.getMat().ptr<Vec4i>(); it = all_contours.begin(); for( i = 0; i < total; i++, ++it ) { CvSeq* c = *it; int h_next = c->h_next ? ((CvContour*)c->h_next)->color : -1; int h_prev = c->h_prev ? ((CvContour*)c->h_prev)->color : -1; int v_next = c->v_next ? ((CvContour*)c->v_next)->color : -1; int v_prev = c->v_prev ? ((CvContour*)c->v_prev)->color : -1; hierarchy[i] = Vec4i(h_next, h_prev, v_next, v_prev); } } }
/*【findContours ( )源代码】*********************************************************** * @Version:OpenCV 3.0.0(Opnencv2和Opnencv3差别不大,Linux和PC的对应版本源码完全一样,均在对应的安装目录下) * @源码路径:…\opencv\sources\modules\imgproc\src\ contours.cpp * @起始行数:1758行 ********************************************************************************/ void cv::findContours( InputOutputArray _image, OutputArrayOfArrays _contours, int mode, int method, Point offset) { findContours(_image, _contours, noArray(), mode, method, offset); }
从源码可以看出,上面一种实现就是第一种方式的特殊实现而已。
绘制轮廓:drawContours()函数
/*【drawContours ( )源代码】********************************************************** * @Version:OpenCV 3.0.0(Opnencv2和Opnencv3差别不大,Linux和PC的对应版本源码完全一样,均在对应的安装目录下) * @源码路径:…\opencv\sources\modules\imgproc\src\ drawing.cpp * @起始行数:2275行 ********************************************************************************/ void cv::drawContours( InputOutputArray _image, InputArrayOfArrays _contours, int contourIdx, const Scalar& color, int thickness, int lineType, InputArray _hierarchy, int maxLevel, Point offset ) { Mat image = _image.getMat(), hierarchy = _hierarchy.getMat(); CvMat _cimage = image; size_t ncontours = _contours.total(); size_t i = 0, first = 0, last = ncontours; std::vector<CvSeq> seq; std::vector<CvSeqBlock> block; if( !last ) return; seq.resize(last); block.resize(last); for( i = first; i < last; i++ ) seq[i].first = 0; if( contourIdx >= 0 ) { CV_Assert( 0 <= contourIdx && contourIdx < (int)last ); first = contourIdx; last = contourIdx + 1; } for( i = first; i < last; i++ ) { Mat ci = _contours.getMat((int)i); if( ci.empty() ) continue; int npoints = ci.checkVector(2, CV_32S); CV_Assert( npoints > 0 ); cvMakeSeqHeaderForArray( CV_SEQ_POLYGON, sizeof(CvSeq), sizeof(Point), ci.ptr(), npoints, &seq[i], &block[i] ); } if( hierarchy.empty() || maxLevel == 0 ) for( i = first; i < last; i++ ) { seq[i].h_next = i < last-1 ? &seq[i+1] : 0; seq[i].h_prev = i > first ? &seq[i-1] : 0; } else { size_t count = last - first; CV_Assert(hierarchy.total() == ncontours && hierarchy.type() == CV_32SC4 ); const Vec4i* h = hierarchy.ptr<Vec4i>(); if( count == ncontours ) { for( i = first; i < last; i++ ) { int h_next = h[i][0], h_prev = h[i][1], v_next = h[i][2], v_prev = h[i][3]; seq[i].h_next = (size_t)h_next < count ? &seq[h_next] : 0; seq[i].h_prev = (size_t)h_prev < count ? &seq[h_prev] : 0; seq[i].v_next = (size_t)v_next < count ? &seq[v_next] : 0; seq[i].v_prev = (size_t)v_prev < count ? &seq[v_prev] : 0; } } else { int child = h[first][2]; if( child >= 0 ) { addChildContour(_contours, ncontours, h, child, seq, block); seq[first].v_next = &seq[child]; } } } cvDrawContours( &_cimage, &seq[first], color, color, contourIdx >= 0 ? -maxLevel : maxLevel, thickness, lineType, offset ); }
3.1.2查找并绘制轮廓实例
轮廓查找实例代码参看附件【demo1】。
图1
图2
查找并绘制轮廓综合实例
代码参看附件【demo2】。
图3
参考:
中文
英文
本章参考代码
点击进入相关文章推荐
- 【第二部分 图像处理】第3章 Opencv图像处理进阶【4 图像轮廓C】
- 【第二部分 图像处理】第3章 Opencv图像处理进阶【4 图像轮廓D】
- 【第二部分 图像处理】第3章 Opencv图像处理进阶【2 图像变换B-霍夫变换】
- 【第二部分 图像处理】第3章 Opencv图像处理进阶【3 直方图与匹配 C】
- 【第二部分 图像处理】第3章 Opencv图像处理进阶【2 图像变换C-重影射】
- 【第二部分 图像处理】第3章 Opencv图像处理进阶【3 直方图与匹配 D】
- 【第二部分 图像处理】第3章 Opencv图像处理进阶【6角点检测 C】
- 【第二部分-图像处理】第3章 Opencv图像处理进阶-【1 图像处理A-滤波】(imgproc组件、feature2D组件)
- 【第二部分 图像处理】第3章 Opencv图像处理进阶【6角点检测 A】
- 【第二部分 图像处理】第3章 Opencv图像处理进阶-【1 图像处理E-阈值化】(imgproc组件、feature2D组件)
- 【第二部分 图像处理】第3章 Opencv图像处理进阶【3 直方图与匹配 E】
- 【第二部分 图像处理】第3章 Opencv图像处理进阶【6角点检测 B】
- 【第二部分 图像处理】第3章 Opencv图像处理进阶【6角点检测 D】
- 【第二部分 图像处理】第3章 Opencv图像处理进阶【3 直方图与匹配 B】
- 【第二部分 图像处理】第3章 Opencv图像处理进阶【3 直方图与匹配 A】
- 【第二部分-图像处理】第1章 Opencv图像处理入门
- 【第二部分 图像处理】第4章 Opencv图像处理高阶【1马赛克】
- 【第二部分-图像处理】第2章 Opencv图像处理初阶(core组件)
- 【第二部分 图像处理】第4章 Opencv图像处理高阶【3图像修复】
- 【第二部分 图像处理】第4章 Opencv图像处理高阶【2毛玻璃滤镜】