• Opencv边缘检测、轮廓发现、绘制轮廓


    Opencv边缘检测、轮廓发现、绘制轮廓

    提取图像轮廓的2个步骤

    1、 findContours函数找轮廓,

    2、 drawContours函数画轮廓

    轮廓的查找——cv::findContours()

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

    轮廓的层级结构

    下图所示了cv::findCountour()的基本功能,图的上部是一幅测试图像,其背景为白色,并含有数个彩色的的区域(标签A到E)。图中也绘制出了由cv::findContours()所确定的轮廓。这些轮廓被标记为cX或hX,其中c代表“contour(轮廓)”,h代表“洞(hole)”,而X是一些数字。有些轮廓使用虚线表示的,他们表示白色区域(即非零区域)的外部边界。OpenCV和cv::findContour()对这些外部边界和图中的点线,即内部边界或者是洞的外部边界,进行区分的。

    如图的下半部分,OpenCV可以将找到的轮廓组织成轮廓树,表示其轮廓结构的包围关系。对于测试图像中的轮廓,我们将根节点处的轮廓称为c0,而“洞”h00和h01是其子节点。反过来这些子节点又会包含新的子节点以此类推。

    在这里插入图片描述

    表示这种树的方式有很多种,OpenCV中使用数组(尤其是vectors)来表示这种树,其中数组中的每个条目都代表一个特定的轮廓,每个条目包含一个由4个整数组成的集合(通常表示为cv :: Vec4i类型的元素,就像四通道数组中的条目一样)。对于每个节点来说,四个元素所表示的含义分别如下:0号元素表示下一个轮廓(同一层级);1号元素表示前一个轮廓(同一层级);2号元素表示第一个子轮廓(下一层级);3号元素表示父轮廓(上一层级)

    drawContours函数的作用

    主要用于画出图像的轮廓

    函数的调用形式

    void drawContours(InputOutputArray image, InputArrayOfArrays contours, int contourIdx, const Scalar& color, int thickness=1, int lineType=8, InputArray hierarchy=noArray(), int maxLevel=INT_MAX, Point offset=Point() )
    函数参数详解:

    其中第一个参数image表示目标图像,

    第二个参数contours表示输入的轮廓组,每一组轮廓由点vector构成,

    第三个参数contourIdx指明画第几个轮廓,如果该参数为负值,则画全部轮廓,

    第四个参数color为轮廓的颜色,

    第五个参数thickness为轮廓的线宽,如果为负值或CV_FILLED表示填充轮廓内部,

    第六个参数lineType为线型,

    第七个参数为轮廓结构信息,

    第八个参数为maxLevel

    代码演示

    /*
    * 轮廓发现
    * 1:输入图像转为灰度图像
    * 2使用Canny进行边缘提取,得到二值图像
    * 3使用findContours寻找轮廓
    * 4使用drawContours绘制轮廓
    * 
    */
    #include 
    #include
    #include 
    #include
    #include
    using namespace std;
    using namespace cv;
    
    Mat src, dst;
    const char* output_win = "findcontours demo";
    int threshold_value = 100;
    int threshold_max = 255;
    RNG rng;
    void Demo_Contours(int, void*);
    int main()
    {
    	src = imread("E:\\Users\\opencvCoder\\image\\niu.jpg");
    	if (src.empty())
    	{
    		printf("could not load image...\n");
    		return -1;
    	}
    	imshow("input_image", src);
    
    
    	namedWindow("input_image", 0);
    	namedWindow(output_win, 1);
    
    	cvtColor(src, src, COLOR_BGR2GRAY);
    	imshow("gray_image", src);
    
    	const char* trackbar_title = "Threshold Value";
    	createTrackbar(trackbar_title, output_win, &threshold_value, threshold_max, Demo_Contours);
    	Demo_Contours(0, 0);
    	waitKey(0);
    	return 0;
    
    }
    void Demo_Contours(int, void*)
    {
    	Mat canny_output;
    	vector<vector<Point>>contours;
    	vector<Vec4i>hierachy;
    	/*
    	*Canny边缘检测的步骤:
    	*1、去噪。噪声会影响边缘检测的准确性,因此首先要将噪声过滤掉。
    	*2、计算梯度大小和方向。
    	*3、非极大值抑制。就是适当的让边缘'变瘦'。
    	*4、确定边缘。使用双阈值法确定最终的边缘信息。
    	*/
    	Canny(src, canny_output, threshold_value, threshold_value * 2, 3, false);
    
    	findContours(canny_output, contours, hierachy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));
    
    	dst = Mat::zeros(src.size(), CV_8UC3);
    	RNG rng(12345);
    	for (size_t i = 0; i < contours.size(); i++)
    	{
    		Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
    		drawContours(dst, contours, i, color,2, 8, hierachy, 0, Point(0, 0));
    	}
    
    	imshow(output_win, dst);
    
    	//canny_output 为图像掩码,将非零值复制给dst
    	src.copyTo(dst, canny_output);
    	//图像取反输出
    	//imshow(output_win, ~dst);
    	//正常输出
    	imshow("mask image", dst);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
  • 相关阅读:
    Spring如何控制Bean的加载顺序
    Ubuntu下高效Vim的搭建(离线版)
    Tomcat的日志接收文件catalina.out nohup.out说明
    前后端交互—Express
    Element Plus阻止 el-dropdown、el-switch等冒泡事件
    MyBatis完成添加、修改、删除功能
    视屏点播项目
    OPC C#连接OPC C#上位机链接PLC程序源码
    LeetCode 240. 搜索二维矩阵 II
    Linux shell编程学习笔记9:字符串运算 和 if语句
  • 原文地址:https://blog.csdn.net/weixin_44735475/article/details/128111214