OpenCV 对轮廓的绘图与筛选操作总结

OpenCV利用findContours找到图像中的轮廓,根据这些轮廓的特征进行筛选有利于进一步逼近最终的兴趣区域,减少其他算法的时间,提高代码的运行效率,而对轮廓的绘图则可以直观的看到筛选结果。

其实绘图的函数在下面的博客中就已经总结过,不过这次换了一个思路重新温习下这些函数,并把他们应用到轮廓的绘图中。 http://blog.csdn.net/chaipp0607/article/details/56277479

轮廓绘制

drawContours(Image, contours, k, Scalar(255,0,0), CV_FILLED);

drawContours()函数用于绘制轮廓,Image为目标图像,Contours为找到的轮廓的合集,k为第几个轮廓(如果为负值则绘制全部轮廓),Scalar(255,0,0)决定了绘制的颜色,需要注意的地方是,如果Scalar为三个颜色的话,那么目标图像需要是三通道才可以,最后一个参数为线条宽度,如果为CV_FILLED的话则填充轮廓。 以上并不是drawContours()函数的所有参数,但是剩下的参数一般都有默认值或者不常用到,所以在这里不介绍。

应用:

SrcImage = imread("22.png",1);
imshow("原图",SrcImage);
cvtColor(SrcImage,grayImage,CV_BGR2GRAY);
threshold(grayImage,thresholdImage, 0, 255, CV_THRESH_OTSU+CV_THRESH_BINARY);
vector<vector<Point> > contours;
vector<Vec4i>hierarchy;
findContours(thresholdImage,contours,hierarchy,CV_RETR_TREE,CV_CHAIN_APPROX_NONE);  
drawContours(SrcImage, contours,-1,Scalar(255,0,0), CV_FILLED);
imshow("填充",SrcImage);

以上代码用于填充所有找到的轮廓,结果如下:

轮廓尺寸 尺寸这个词并不准确,其实是轮廓的size,也就是把轮廓围起来的点的个数,我们都知道OpenCV中的一个轮廓其实是点的合集,所以如果一个轮廓在图像上的相对大,那么他的点的个数也就相应的会变多,这可以作为筛选的简单标准之一。

    vector<vector<Point> > contours;
    vector<Vec4i>hierarchy;
    findContours(thresholdImage,contours,hierarchy,CV_RETR_TREE,CV_CHAIN_APPROX_NONE);  
    for(int k = 0; k < (int)contours.size(); k++)   
    {
        if (contours.at(k).size()>400)
        drawContours(SrcImage, contours,k,Scalar(255,0,0), CV_FILLED);      
    }
    imshow("填充",SrcImage);

其中(int)contours.size()为第几个轮廓,而contours.at(k).size()则为轮廓的点的个数,为了让点的个数与轮廓的大小成正比,在findContours()时将参数设置为CV_CHAIN_APPROX_NONE,具体可见: http://blog.csdn.net/chaipp0607/article/details/61431922

以上代码用于填充尺寸大于400的轮廓,结果如下:

轮廓面积 根据矩的定义,函数的零阶原点矩为质量,对于轮廓而言即为轮廓的面积,所以零阶原点矩的数值可以更好的表征出轮廓的面积。 具体可见:https://cloud.tencent.com/developer/article/1009992

vector<vector<Point> > contours;
    vector<Vec4i>hierarchy;
    findContours(thresholdImage,contours,hierarchy,CV_RETR_TREE,CV_CHAIN_APPROX_NONE);  
    vector<Moments> mu(contours.size() );   
    for(int k = 0; k < (int)contours.size(); k++)   
    {
        mu[k] = moments( contours[k], false ); 
        if (mu[k].m00>1000)
        drawContours(SrcImage, contours,k,Scalar(255,0,0), CV_FILLED);      
    }
    imshow("填充",SrcImage);

以上代码用于填充面积大于1000的轮廓,结果如下:

轮廓质心 同样,我们可以根据轮廓的零阶原点矩与一阶原点矩求得轮廓的质心。

    vector<vector<Point> > contours;
    vector<Vec4i>hierarchy;
    findContours(thresholdImage,contours,hierarchy,CV_RETR_TREE,CV_CHAIN_APPROX_NONE);  
    vector<Moments> mu(contours.size() );   
    vector<Point2f> mc( contours.size() );
    for(int k = 0; k < (int)contours.size(); k++)   
    {
        mu[k] = moments( contours[k], false ); 
        mc[k] = Point2d( mu[k].m10/mu[k].m00 , mu[k].m01/mu[k].m00 );
        if (mc[k].x>SrcImage.cols/2)
        drawContours(SrcImage, contours,k,Scalar(255,0,0), CV_FILLED);      
    }
    imshow("填充",SrcImage);

以上代码用于填充质心在图像中线右侧的轮廓,结果如下:

轮廓的外接椭圆 轮廓的外接椭圆能够提供长短轴与角度的信息,而长短轴的比值使轮廓具有尺度不变的特性。 OpenCV利用fitEllipse()函数创建轮廓(二维点集)的外接椭圆拟合,该函数的定义:

CV_EXPORTS_W RotatedRect fitEllipse( InputArray points );

可见,它的参数只有二维的点集做输入,而函数的类型为RotatedRect ,RotatedRect 为OpenCV中的一个常用数据类型——可旋转的2D矩形。所以我们可以利用这个类型定义的对象用来接fitEllipse()函数的返回结果。而椭圆的长短轴其实本质上是RotatedRect 类中的宽度和高度成员。

    vector<vector<Point> > contours;
    vector<Vec4i>hierarchy;
    findContours(thresholdImage,contours,hierarchy,CV_RETR_TREE,CV_CHAIN_APPROX_NONE);  

    for(int k = 0; k < (int)contours.size(); k++)   
    {
        if (contours.at(k).size()>6)
        {
            RotatedRect rRect = fitEllipse(contours.at(k)); 
            double majorAxis = rRect.size.height > rRect.size.width ? rRect.size.height : rRect.size.width;
            double minorAxis = rRect.size.height > rRect.size.width ? rRect.size.width : rRect.size.height;
            double angle = rRect.angle;
            if (majorAxis>70)
            {
                drawContours(SrcImage, contours,k,Scalar(255,0,0), CV_FILLED);      
                ellipse(SrcImage,rRect,Scalar(0,0,255));
            }
        }
    }
    imshow("填充",SrcImage);

以上代码用于填充长轴在70以上的轮廓并利用ellipse()函数画出这些轮廓的外接椭圆,结果如下:

除此之外,我们还可以画出外接椭圆的外接矩形,由于RotatedRect类提供了一个叫做boundingRect()的成员函数(该函数声明在了RotatedRect类中,其实他是个Rect类型的函数,也可以单独使用,下面会具体提到这个函数),用于返回包含旋转矩形的最小直正矩形,所以我们简单修改代码后,即可同时画出椭圆的外接矩形:

                rectangle(SrcImage,rRect.boundingRect(),Scalar(0,255,0));

轮廓的外接矩形 外接矩形和外接椭圆的用法差不多: OpenCV利用boundingRect()函数创建轮廓(二维点集)的外接矩形,该函数的定义:

CV_EXPORTS_W Rect boundingRect( InputArray points );

可见,它的参数只有二维的点集做输入,而函数的类型为Rect ,Rect 为OpenCV中的一个另一个常用数据类型——2D直正矩形类。所以我们可以利用这个类型定义的对象用来接boundingRect()函数的返回结果。而矩形的位置和宽高信息其实本质上是Rect 类中的位置,宽度和高度成员。

    vector<vector<Point> > contours;
    vector<Vec4i>hierarchy;
    findContours(thresholdImage,contours,hierarchy,CV_RETR_TREE,CV_CHAIN_APPROX_NONE);  
    for(int k = 0; k < (int)contours.size(); k++)   
    {
        if (contours.at(k).size()>6)
        {
            Rect position = boundingRect(contours.at(k));
            if (position.x<SrcImage.cols/2)
            {
                drawContours(SrcImage, contours,k,Scalar(255,0,0), CV_FILLED);      
                rectangle(SrcImage,position,Scalar(0,0,255));
            }
        }
    }
    imshow("填充",SrcImage);

以上代码用于填充外接矩形的横坐标(左上角点)在图像中线左侧的轮廓并利用rectangle()函数画出这些轮廓的外接椭圆,结果如下:

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏工科狗和生物喵

【机器视觉与图像处理】基于MATLAB+Hough的圆检测

本次文章,没有太多好写的,就是最近做的一个机器视觉的课程设计作业,是要做一个流水线的生产线建模以及对于产品的检测识别,我个人承包了圆心半径检测的内容,熬了好几天...

861
来自专栏一棹烟波

OpenCV两种畸变校正模型源代码分析以及CUDA实现

图像算法中会经常用到摄像机的畸变校正,有必要总结分析OpenCV中畸变校正方法,其中包括普通针孔相机模型和鱼眼相机模型fisheye两种畸变校正方法。 普通相机...

4218
来自专栏懒人开发

(8.2)James Stewart Calculus 5th Edition:Area of a Surface of Revolution

1033
来自专栏贾志刚-OpenCV学堂

基于梯度下降算法求解线性回归

基于梯度下降算法求解线性回归 一:线性回归(Linear Regression) 梯度下降算法在机器学习方法分类中属于监督学习。利用它可以求解线性回归问题,计算...

33011
来自专栏数据结构与算法

计算几何笔记

若向量$(x, y)$旋转角度为$a$,则旋转后的向量为$(xcosa - ysina, y cosa + xsina)$

702
来自专栏一棹烟波

OpenCV3.4两种立体匹配算法效果对比

 以OpenCV自带的Aloe图像对为例: ? ? ? 1.BM算法(Block Matching) 参数设置如下: int numberOfDispa...

8064
来自专栏AI研习社

25 行 Python 代码就能实现人脸识别?这篇文章告诉你详情

首先,在阅读本文之前,需要注意以下几点: 建议先读一遍本文再跑代码——你需要理解这些代码是干什么的。成功跑一遍不是目的,能够举一反三、在新任务上找出 bug 才...

3687
来自专栏一心无二用,本人只专注于基础图像算法的实现与优化。

基于局部均方差相关信息的图像去噪及其在实时磨皮美容算法中的应用。      在1979年Lee发表的论文《Lee Filter Digital Image Enhancement and Noise

     在1979年Lee发表的论文《Lee Filter Digital Image Enhancement and Noise Filtering by ...

1825
来自专栏用户2442861的专栏

基于级联分类器的多目标检测

原文地址:http://blog.csdn.NET/ariesjzj/article/details/8639208

451
来自专栏WOLFRAM

用 Mathematica 生成迷宫

2264

扫码关注云+社区