【OpenCV入门指南】第五篇 轮廓检测 上

    xiaoxiao2021-08-18  80

    【OpenCV入门指南】第五篇 轮廓检测 上

    《【OpenCV入门指南】第三篇Canny边缘检测》中介绍了边缘检测,本篇介绍轮廓检测,轮廓检测的原理通俗的说就是掏空内部点,比如原图中有3*3的矩形点。那么就可以将中间的那一点去掉。

           OpenCV中使用轮廓检测是非常方便。直接使用cvFindContours函数就能完成对图像轮廓的检测。下面就来看看这个函数的用法。

    OpenCV入门指南》系列文章地址:http://blog.csdn.net/morewindows/article/category/863841

     

    一.关键函数

    1.1  cvFindContours

    函数功能:对图像进行轮廓检测,这个函数将生成一条链表以保存检测出的各个轮廓信息,并传出指向这条链表表头的指针。

    函数原型:

    int cvFindContours(

      CvArrimage,

      CvMemStoragestorage,

      CvSeq** first_contour  

      int header_size=sizeof(CvContour),

      int mode=CV_RETR_LIST  

      int method=CV_CHAIN_APPROX_SIMPLE,

      CvPoint offset=cvPoint(0,0)

    );

    函数说明:

    第一个参数表示输入图像,必须为一个8位的二值图像。图像的二值化请参见《【OpenCV入门指南】第四篇图像的二值化》。

     

    第二参数表示存储轮廓的容器。为CvMemStorage类型,定义在OpenCV\core\types_c.h中。

     

    第三个参数为输出参数,这个参数将指向用来存储轮廓信息的链表表头。

     

    第四个参数表示存储轮廓链表的表头大小,当第六个参数传入CV_CHAIN_CODE时,要设置成sizeof(CvChain),其它情况统一设置成sizeof(CvContour)。

     

    第五个参数为轮廓检测的模式,有如下取值:

    CV_RETR_EXTERNAL:只检索最外面的轮廓;

      CV_RETR_LIST:检索所有的轮廓,并将其保存到一条链表当中;

      CV_RETR_CCOMP:检索所有的轮廓,并将他们组织为两层:顶层是各部分的外部边界,第二层是空洞的边界;

    CV_RETR_TREE:检索所有的轮廓,并重构嵌套轮廓的整个层次,可以参见下图。

    第六个参数用来表示轮廓边缘的近似方法的,常用值如下所示:

    CV_CHAIN_CODE:以Freeman链码的方式输出轮廓,所有其他方法输出多边形(顶点的序列)。

      CV_CHAIN_APPROX_SIMPLE:压缩水平的、垂直的和斜的部分,也就是,函数只保留他们的终点部分。

     

    第七个参数表示偏移量,比如你要从图像的(100, 0)开始进行轮廓检测,那么就传入(100, 0)。

     

    使用cvFindContours函数能检测出图像的轮廓,将轮廓绘制出来则需要另一函数——cvDrawContours来配合了。下面介绍cvDrawContours函数。

     

    1.2  cvDrawContours

    函数功能:在图像上绘制外部和内部轮廓

    函数原型:

    void cvDrawContours(

      CvArr *img,

      CvSeqcontour,

      CvScalar external_color,

      CvScalar hole_color,

      int max_level,

      int thickness=1,

      int line_type=8,

      CvPoint offset=cvPoint(0,0)

    );

    第一个参数表示输入图像,函数将在这张图像上绘制轮廓。

    第二个参数表示指向轮廓链表的指针。

    第三个参数和第四个参数表示颜色,绘制时会根据轮廓的层次来交替使用这二种颜色。

    第五个参数表示绘制轮廓的最大层数,如果是0,只绘制contour;如果是1,追加绘制和contour同层的所有轮廓;如果是2,追加绘制比contour低一层的轮廓,以此类推;如果值是负值,则函数并不绘制contour后的轮廓,但是将画出其子轮廓,一直到abs(max_level) - 1层。

    第六个参数表示轮廓线的宽度,如果为CV_FILLED则会填充轮廓内部。

    第七个参数表示轮廓线的类型。

    第八个参数表示偏移量,如果传入(1020),那绘制将从图像的(1020)处开始。

     

    二.示例程序代码

    下面用一个非常简单的例子展示如何使用轮廓检测。

    [cpp]  view plain  copy //图像的轮廓检测上   //By MoreWindows (http://blog.csdn.net/MoreWindows)   #include <opencv2/opencv.hpp>   using namespace std;   #pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"")   int main( int argc, char** argv )   {          const char *pstrWindowsSrcTitle = "原图(http://blog.csdn.net/MoreWindows)";       const char *pstrWindowsOutLineTitle = "轮廓图(http://blog.csdn.net/MoreWindows)";              const int IMAGE_WIDTH = 400;       const int IMAGE_HEIGHT = 200;          // 创建图像       IplImage *pSrcImage = cvCreateImage(cvSize(IMAGE_WIDTH, IMAGE_HEIGHT), IPL_DEPTH_8U, 3);       // 填充成白色       cvRectangle(pSrcImage, cvPoint(0, 0), cvPoint(pSrcImage->width, pSrcImage->height), CV_RGB(255, 255, 255), CV_FILLED);       // 画圆       CvPoint ptCircleCenter = cvPoint(IMAGE_WIDTH / 4, IMAGE_HEIGHT / 2);       int nRadius = 80;       cvCircle(pSrcImage, ptCircleCenter, nRadius, CV_RGB(255, 255, 0), CV_FILLED);       ptCircleCenter = cvPoint(IMAGE_WIDTH / 4, IMAGE_HEIGHT / 2);       nRadius = 30;       cvCircle(pSrcImage, ptCircleCenter, nRadius, CV_RGB(255, 255, 255), CV_FILLED);       // 画矩形       CvPoint ptLeftTop = cvPoint(IMAGE_WIDTH / 2 + 20, 20);       CvPoint ptRightBottom = cvPoint(IMAGE_WIDTH - 20, IMAGE_HEIGHT - 20);       cvRectangle(pSrcImage, ptLeftTop, ptRightBottom, CV_RGB(0, 255, 255), CV_FILLED);       ptLeftTop = cvPoint(IMAGE_WIDTH / 2 + 60, 40);       ptRightBottom = cvPoint(IMAGE_WIDTH - 60, IMAGE_HEIGHT - 40);       cvRectangle(pSrcImage, ptLeftTop, ptRightBottom, CV_RGB(255, 255, 255), CV_FILLED);       // 显示原图       cvNamedWindow(pstrWindowsSrcTitle, CV_WINDOW_AUTOSIZE);       cvShowImage(pstrWindowsSrcTitle, pSrcImage);             // 转为灰度图       IplImage *pGrayImage =  cvCreateImage(cvGetSize(pSrcImage), IPL_DEPTH_8U, 1);       cvCvtColor(pSrcImage, pGrayImage, CV_BGR2GRAY);       // 转为二值图       IplImage *pBinaryImage = cvCreateImage(cvGetSize(pGrayImage), IPL_DEPTH_8U, 1);       cvThreshold(pGrayImage, pBinaryImage, 250, 255, CV_THRESH_BINARY);             // 检索轮廓并返回检测到的轮廓的个数       CvMemStorage *pcvMStorage = cvCreateMemStorage();       CvSeq *pcvSeq = NULL;       cvFindContours(pBinaryImage, pcvMStorage, &pcvSeq, sizeof(CvContour), CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, cvPoint(0, 0));              // 画轮廓图       IplImage *pOutlineImage = cvCreateImage(cvGetSize(pSrcImage), IPL_DEPTH_8U, 3);       int nLevels = 5;       // 填充成白色       cvRectangle(pOutlineImage, cvPoint(0, 0), cvPoint(pOutlineImage->width, pOutlineImage->height), CV_RGB(255, 255, 255), CV_FILLED);       cvDrawContours(pOutlineImage, pcvSeq, CV_RGB(255,0,0), CV_RGB(0,255,0), nLevels, 2);       // 显示轮廓图       cvNamedWindow(pstrWindowsOutLineTitle, CV_WINDOW_AUTOSIZE);       cvShowImage(pstrWindowsOutLineTitle, pOutlineImage);             cvWaitKey(0);          cvReleaseMemStorage(&pcvMStorage);          cvDestroyWindow(pstrWindowsSrcTitle);       cvDestroyWindow(pstrWindowsOutLineTitle);       cvReleaseImage(&pSrcImage);       cvReleaseImage(&pGrayImage);       cvReleaseImage(&pBinaryImage);       cvReleaseImage(&pOutlineImage);       return 0;   }  

    运行结果如下图所示:

    由图可以看出,轮廓线已经按层次交替的绘制成功了,读者可以修改程序中的cvDrawContours中的nLevels参数,看看图形会有什么变化。

    转载请注明原文地址: https://ju.6miu.com/read-676583.html

    最新回复(0)