使用cvFindContours函数与cvFillPoly填充连通区内部空洞

</pre></h1><h1 style="text-align: center;">OpenCV基于轮廓填充连通区内部空洞</h1><h2>前言:</h2><div><span style="font-size:18px"><span style="white-space:pre"></span>最近在做火焰识别项目时使用了一种火焰颜色模型分割疑似火焰区域,由于火焰内部温度高、焰色偏白而被该模型舍弃,造成火焰连通区域内部有空洞,影响进一步的火焰判断。通过查找资料学习,我使用cvFindContours()函数与cvFillPoly()函数填充连通区内部空洞,取得了良好的效果,特写此片博文总结、分享我的经验。</span></div><div><h2><span style="font-size:24px">1. 主要函数介绍</span></h2><div><span style="font-size:18px"></span></div><h3><span style="font-size:18px"><span style="font-size:18px">1.1 FindContours</span></span></h3><span style="font-size:18px"><strong>在二值图像中寻找轮廓 </strong></span></div><div><span style="font-size:18px">int <span style="font-size:18px">cvFindContours</span>( CvArr* image, CvMemStorage* storage, CvSeq** first_contour,<span style="white-space:pre"></span>int header_size=sizeof(CvContour), int mode=CV_RETR_LIST,<span style="white-space:pre"></span>int method=CV_CHAIN_APPROX_SIMPLE, CvPoint offset=cvPoint(0,0) );</span></div><div><span style="font-size:18px"><strong>【参数介绍】image </strong><span style="white-space:pre"></span>输入的 8-比特、单通道图像. 非零元素被当成 1, 0 象素值保留为 0 – 从而图像被看成二值的。为了从灰度图像中得到这样的二值图像,可以使用 cvThreshold, cvAdaptiveThreshold 或 cvCanny. 本函数改变输入图像内容。<strong>storage</strong><span style="white-space:pre"></span>得到的轮廓的存储容器 <strong>first_contour </strong><span style="white-space:pre"></span>输出参数:包含第一个输出轮廓的指针 <strong>header_size </strong><span style="white-space:pre"></span>如果 method=CV_CHAIN_CODE,则序列头的大小 >=sizeof(CvChain),否则 >=sizeof(CvContour) .<strong>mode </strong><span style="white-space:pre"></span>提取模式. <span style="white-space:pre"></span>CV_RETR_EXTERNAL – 只提取最外层的轮廓 <span style="white-space:pre"></span>CV_RETR_LIST – 提取所有轮廓,并且放置在 list 中 <span style="white-space:pre"></span>CV_RETR_CCOMP – 提取所有轮廓,并且将其组织为两层的 hierarchy: 顶层为连通域的外围边界,次层为洞的内层边界。<span style="white-space:pre"></span>CV_RETR_TREE – 提取所有轮廓,并且重构嵌套轮廓的全部 hierarchy <strong>method </strong><span style="white-space:pre"></span>逼近方法 (对所有节点, 不包括使用内部逼近的 CV_RETR_RUNS). <span style="white-space:pre"></span>CV_CHAIN_CODE – Freeman 链码的输出轮廓. 其它方法输出多边形(定点序列).<span style="white-space:pre"></span>CV_CHAIN_APPROX_NONE – 将所有点由链码形式翻译(转化)为点序列形式<span style="white-space:pre"></span>CV_CHAIN_APPROX_SIMPLE – 压缩水平、垂直和对角分割,即函数只保留末端的象素点;<span style="white-space:pre"></span>CV_CHAIN_APPROX_TC89_L1, <span style="white-space:pre"></span>CV_CHAIN_APPROX_TC89_KCOS – 应用 Teh-Chin 链逼近算法. CV_LINK_RUNS – 通过连接为 1 的水平碎片<span style="white-space:pre"></span>使用完全不同的轮廓提取算法。仅有 CV_RETR_LIST 提取模式可以在本方法中应用. <strong>offset </strong><span style="white-space:pre"></span>每一个轮廓点的偏移量. 当轮廓是从图像 ROI 中提取出来的时候,使用偏移量有用,,因为可以从整个图像上下文来对轮廓做分析.<span style="white-space:pre"></span>函数 <span style="color:#ffffff; background-color:#3399ff"></span><span style="font-size:18px">cvFindContours</span>从二值图像中提取轮廓,并且返回提取轮廓的数目。指针 first_contour 的内容由函数填写。它包含第一个最外层轮廓的指针,如果指针为 NULL,则没有检测到轮廓(比如图像是全黑的)。其它轮廓可以从 first_contour 利用 h_next 和 v_next 链接访问到。 在 cvDrawContours 的样例显示如何使用轮廓来进行连通域的检测。轮廓也可以用来做形状分析和对象识别。</span></div><div><h3><span style="font-size:18px"><strong>1.2 FillPoly</strong></span></h3><span style="font-size:18px">填充多边形内部 void cv</span><span style="font-size:18px">FillPoly</span><span style="font-size:18px">( CvArr* img, CvPoint** pts, int* npts, int contours,</span><span style="font-size:18px"><span style="white-space:pre"></span>CvScalar color, int line_type=8, int shift=0 );</span></div><div><span style="font-size:18px">【参数介绍】<strong><span style="white-space:pre"></span>img </strong><span style="white-space:pre"></span>图像。 <strong><span style="white-space:pre"></span>pts </strong><span style="white-space:pre"></span>指向多边形的数组指针。 <span style="white-space:pre"></span>npts <span style="white-space:pre"></span>多边形的顶点个数的数组。 <strong><span style="white-space:pre"></span>contours </strong><span style="white-space:pre"></span>组成填充区域的线段的数量。 <strong><span style="white-space:pre"></span>color </strong><span style="white-space:pre"></span>多边形的颜色。 <strong><span style="white-space:pre"></span>line_type </strong><span style="white-space:pre"></span>组成多边形的线条的类型。 <strong><span style="white-space:pre"></span>shift </strong><span style="white-space:pre"></span>顶点坐标的小数点位数。 <span style="white-space:pre"></span>函数cvFillPoly用于一个单独被多边形轮廓所限定的区域内进行填充。函数可以填充复杂的区域,例如,有漏洞的区域和有交叉点的区域等等。  </span></div><h2><span style="font-size:24px">2. 编程实现</span></h2><div><span style="font-size:18px; white-space:pre"></span><span style="font-size:18px">函数fiilSeg()输入为经过颜色分割的火焰图片(需转为单通道灰度图),输出为填补了空洞的二值图像。</span><pre name="code" class="cpp" style="font-size:18px;">//根据分割结果确定轮廓并填充void fillSeg(IplImage *src,IplImage *tempdst){CvSeq * contour = NULL;CvMemStorage * storage = cvCreateMemStorage();//在二值图像中寻找轮廓,CV_CHAIN_APPROX_SIMPLE – 压缩水平、垂直和对角分割,即函数只保留末端的象素点cvFindContours(src,storage,&contour,sizeof(CvContour),CV_RETR_CCOMP ,CV_CHAIN_APPROX_SIMPLE);cvZero(tempdst);for( contour; contour != 0; contour = contour->h_next){//轮廓的方向影响面积的符号。因此函数也许会返回负的结果。应用函数 fabs() 得到面积的绝对值。 double area = cvContourArea( contour,CV_WHOLE_SEQ );//计算整个轮廓或部分轮廓的面积if(fabs(area) < 10){continue;}//CvScalar color = CV_RGB( 255, 255, 255 );CvPoint *point = new CvPoint[contour->total];CvPoint *Point;//printf("图像分割contour->total\t%d\n",contour->total);for (int i = 0;i<contour->total;i++){Point = (CvPoint*)cvGetSeqElem(contour,i);point[i].x =Point->x;point[i].y = Point->y;}int pts[1] = {contour->total};cvFillPoly(tempdst,&point,pts,1,CV_RGB(255,255,255));//填充多边形内部 }}

下图a原始图片,图b为本函数的作用效果图。作图为经过颜色模型分割的火焰区域,绿色框标注出了火焰内部的空洞;右图是经过填充的图案。内部空洞完全填充,并且火焰轮廓没有受到侵蚀。

享受每一刻的感觉,欣赏每一处的风景,这就是人生。

使用cvFindContours函数与cvFillPoly填充连通区内部空洞

相关文章:

你感兴趣的文章:

标签云: