opencv学习--轮廓检测

      轮廓检测,是图像处理中比较重要的一个部分。findContourheDrawContours

      参考地址:https://www.cnblogs.com/dengxiaojun/p/5252294.html

                       https://blog.csdn.net/zhangjikuan/article/details/39853879

                      https://blog.csdn.net/qq_15947787/article/details/72773893?ABstrategy=codes_snippets_optimize_v3

                      

一、轮廓概述

       轮廓可以简单认为成将连续的点(连着边界)连在一起的曲线,具有相同的颜色或者灰度。轮廓在形状分析和物体的检测和识别中很有用。 
  • 为了更加准确,要使用二值化图像。在寻找轮廓之前,要进行阈值化处理或者 Canny 边界检测。 
  • 查找轮廓的函数会修改原始图像。如果你在找到轮廓之后还想使用原始图像的话,你应该将原始图像存储到其他变量中。 
  • 在 OpenCV 中,查找轮廓就像在黑色背景中超白色物体,要找的物体应该是白色而背景应该是黑色。

二、 寻找轮廓

       函数cv::findContour是从二值图像中来计算轮廓的,它可以使用cv::Canny()函数处理的图像,因为这样的图像含有边缘像素;也可以使用cv::threshold()或者cv::adaptiveThreshold()处理后的图像,其边缘隐含在正负区域的交界处。

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)

);

findContours(threshold_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));

       第一个参数:image,单通道图像矩阵,可以是灰度图等,此处为threshold_output是一个二值图像;

      第二个参数:contours,定义为“vector<vector<Point>> contours”,是一个双重向量,向量内每个元素保存了一组由连续的Point点构成的点的集合的向量,每一组Point点集就是一个轮廓。有多少轮廓,向量contours就有多少元素。

      第三个参数:hierarchy,为输出参数,这个参数将指向用来存储轮廓信息的链表表头。hierarchy向量内每一个元素的4个int型变量——hierarchy[i][0] ~hierarchy[i][3],分别表示第i个轮廓的后一个轮廓、前一个轮廓、父轮廓、内嵌轮廓的索引编号。如果当前轮廓没有对应的后一个轮廓、前一个轮廓、父轮廓或内嵌轮廓的话,则hierarchy[i][0] ~hierarchy[i][3]的相应位被设置为默认值-1。

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

     第五个参数:int型的mode,定义轮廓的检索模式:

           取值一:CV_RETR_EXTERNAL只检测最外围轮廓,包含在外围轮廓内的内围轮廓被忽略。

           取值二:CV_RETR_LIST   检测所有的轮廓,包括内围、外围轮廓,但是检测到的轮廓不建立等级关

                  系,彼此之间独立,没有等级关系,这就意味着这个检索模式下不存在父轮廓或内嵌轮廓,

                  所以hierarchy向量内所有元素的第3、第4个分量都会被置为-1。

           取值三:CV_RETR_CCOMP  检测所有的轮廓,但所有轮廓只建立两个等级关系,外围为顶层,若外围

                  内的内围轮廓还包含了其他的轮廓信息,则内围内的所有轮廓均归属于顶层

           取值四:CV_RETR_TREE, 检测所有轮廓,所有轮廓建立一个等级树结构。外层轮廓包含内层轮廓,内

                   层轮廓还可以继续包含内嵌轮廓。

    第六个参数:int型的method,定义轮廓的近似方法:

           取值一:CV_CHAIN_APPROX_NONE 保存物体边界上所有连续的轮廓点到contours向量内

           取值二:CV_CHAIN_APPROX_SIMPLE 仅保存轮廓的拐点信息,把所有轮廓拐点处的点保存入contours

                   向量内,拐点与拐点之间直线段上的信息点不予保留

           取值三和四:CV_CHAIN_APPROX_TC89_L1,CV_CHAIN_APPROX_TC89_KCOS使用teh-Chinl chain 近似算法

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

 

三、轮廓绘制

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

函数原型:

void cvDrawContours(

  CvArr *img,

  CvSeq* contour,

  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则会填充轮廓内部。

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

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

 

程序:对普通图像进行检测,绘制轮廓。


 
#include "stdafx.h"
#include <opencv2/opencv.hpp>  
using namespace std;  
#pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"")  
IplImage *g_pGrayImage = NULL;  
const char *pstrWindowsBinaryTitle = "二值图";  
const char *pstrWindowsOutLineTitle = "轮廓图";  
CvSeq *g_pcvSeq = NULL;  
  
void on_trackbar(int pos)  
{  
    // 转为二值图  
    IplImage *pBinaryImage = cvCreateImage(cvGetSize(g_pGrayImage), IPL_DEPTH_8U, 1);  
    cvThreshold(g_pGrayImage, pBinaryImage, pos, 255, CV_THRESH_BINARY);  
    // 显示二值图  
    cvShowImage(pstrWindowsBinaryTitle, pBinaryImage);  
  
    CvMemStorage* cvMStorage = cvCreateMemStorage();  
    // 检索轮廓并返回检测到的轮廓的个数  
    cvFindContours(pBinaryImage,cvMStorage, &g_pcvSeq);  
  
    IplImage *pOutlineImage = cvCreateImage(cvGetSize(g_pGrayImage), IPL_DEPTH_8U, 3);  
	//轮廓最大层数
    int _levels = 5;  
    cvZero(pOutlineImage);  
    cvDrawContours(pOutlineImage, g_pcvSeq, CV_RGB(255,0,0), CV_RGB(0,255,0), _levels);  
    cvShowImage(pstrWindowsOutLineTitle, pOutlineImage);  
  
    cvReleaseMemStorage(&cvMStorage);  
    cvReleaseImage(&pBinaryImage);  
    cvReleaseImage(&pOutlineImage);  
}  
  
int main( int argc, char** argv )  
{     
    const char *pstrWindowsSrcTitle = "原图";  
    const char *pstrWindowsToolBarName = "二值化";  
  
    // 从文件中加载原图  
    IplImage *pSrcImage = cvLoadImage("beautiful.jpg", CV_LOAD_IMAGE_UNCHANGED);  
    // 显示原图  
    cvNamedWindow(pstrWindowsSrcTitle, CV_WINDOW_AUTOSIZE);  
    cvShowImage(pstrWindowsSrcTitle, pSrcImage);  
  
    // 转为灰度图  
    g_pGrayImage =  cvCreateImage(cvGetSize(pSrcImage), IPL_DEPTH_8U, 1);  
    cvCvtColor(pSrcImage, g_pGrayImage, CV_BGR2GRAY);  
  
    // 创建二值图和轮廓图窗口  
    cvNamedWindow(pstrWindowsBinaryTitle, CV_WINDOW_AUTOSIZE);  
    cvNamedWindow(pstrWindowsOutLineTitle, CV_WINDOW_AUTOSIZE);  
  
  
    // 滑动条    
    int nThreshold = 0;  
    cvCreateTrackbar(pstrWindowsToolBarName, pstrWindowsBinaryTitle, &nThreshold, 254, on_trackbar);  
  
    on_trackbar(1);  
  
    cvWaitKey(0);  
  
    cvDestroyWindow(pstrWindowsSrcTitle);  
    cvDestroyWindow(pstrWindowsBinaryTitle);  
    cvDestroyWindow(pstrWindowsOutLineTitle);  
    cvReleaseImage(&pSrcImage);  
    cvReleaseImage(&g_pGrayImage);  
    return 0;  
}  

四 其他轮廓相关

           findContours后会对输入的2值图像改变,所以如果不想改变该2值图像,需创建新mat来存放,findContours后的轮廓信息contours可能过于复杂不平滑,可以用approxPolyDP函数对该多边形曲线做适当近似

           contourArea函数可以得到当前轮廓包含区域的大小,方便轮廓的筛选

         findContours经常与drawContours配合使用,用来将轮廓绘制出来。其中第一个参数image表示目标图像,第二个参数contours表示输入的轮廓组,每一组轮廓由点vector构成,第三个参数contourIdx指明画第几个轮廓,如果该参数为负值,则画全部轮廓,第四个参数color为轮廓的颜色,第五个参数thickness为轮廓的线宽,如果为负值或CV_FILLED表示填充轮廓内部,第六个参数lineType为线型,第七个参数为轮廓结构信息,第八个参数为maxLevel

        得到了复杂轮廓往往不适合特征的检测,这里再介绍一个点集凸包络的提取函数convexHull,输入参数就可以是contours组中的一个轮廓,返回外凸包络的点集

       还可以得到轮廓的外包络矩形,使用函数boundingRect,如果想得到旋转的外包络矩形,使用函数minAreaRect,返回值为RotatedRect;也可以得到轮廓的外包络圆,对应的函数为minEnclosingCircle;想得到轮廓的外包络椭圆,对应的函数为fitEllipse,返回值也是RotatedRect,可以用ellipse函数画出对应的椭圆

       如果想根据多边形的轮廓信息得到多边形的多阶矩,可以使用类moments,这个类可以得到多边形和光栅形状的3阶以内的所有矩,类内有变量m00,m10,m01,m20,m11,m02,m30,m21,m12,m03,比如多边形的质心为 x = m10 / m00,y = m01 / m00。

       如果想获得一点与多边形封闭轮廓的信息,可以调用pointPolygonTest函数,这个函数返回值为该点距离轮廓最近边界的距离,为正值为在轮廓内部,负值为在轮廓外部,0表示在边界上。

五、轮廓匹配

这个可以参考下列链接学习:https://blog.csdn.net/qq_15947787/article/details/72773893?ABstrategy=codes_snippets_optimize_v3

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值