Opencv实现边缘检测与轮廓发现及绘制轮廓方法详解

 更新时间:2022年12月14日 08:32:31   作者:以后的事,以后再说  
这篇文章主要介绍了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 <opencv.hpp>
#include<iostream>
#include <string>
#include<conio.h>
#include<time.h>
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);
}

到此这篇关于Opencv实现边缘检测与轮廓发现及绘制轮廓方法详解的文章就介绍到这了,更多相关Opencv边缘检测 内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 利用C语言将点分十进制的IP字符串转成4个整数

    利用C语言将点分十进制的IP字符串转成4个整数

    这篇文章主要为大家详细介绍了如何利用C语言实现将点分十进制的IP字符串转成4个整数,文中的示例代码简洁易懂,感兴趣的小伙伴可以跟随小编一起学习一下
    2025-01-01
  • 数组指针、指针数组以及二位数组的深入解析

    数组指针、指针数组以及二位数组的深入解析

    下面来讲讲多维数组与指针的关系。与普通数组一样,使用多维数组时,实际上将其自动转换为指向该数组第一个元素的指针
    2013-09-09
  • C程序读取键盘码的方法

    C程序读取键盘码的方法

    这篇文章主要介绍了C程序读取键盘码的方法,运行时可通过键盘按键获取其对应的键盘码,文章最后附带了键盘码与按键的对照表,需要的朋友可以参考下
    2014-09-09
  • C++实现二进制字符串与十六进制字符串相互转换

    C++实现二进制字符串与十六进制字符串相互转换

    这篇文章主要为大家详细介绍了如何使用C++实现二进制字符串与十六进制字符串相互转换,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2025-11-11
  • C语言如何计算一个整数的位数

    C语言如何计算一个整数的位数

    这篇文章主要介绍了C语言如何计算一个整数的位数,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-11-11
  • Linux c 运行时获取动态库所在路径的操作方法

    Linux c 运行时获取动态库所在路径的操作方法

    运行时获取动态库地址除了dladdr和解析/proc/<pid>/maps还可以有一些别的做法,比如可以用nm获取库文件的符号表进行对比,但如果库文件被strip处理过就不能这么用了,本文介绍的两种方案是泛用性最高的,感兴趣的朋友一起看看吧
    2025-06-06
  • Qt中QMessageBox使用小结

    Qt中QMessageBox使用小结

    本文主要介绍了Qt中QMessageBox使用小结,包括基本消息框、带按钮的消息框、自定义消息框、按钮类型、图标设置以及长文本显示,具有一定的参考价值,感兴趣的可以了解一下
    2025-12-12
  • C语言实现桶排序的方法示例

    C语言实现桶排序的方法示例

    这篇文章主要介绍了C语言实现桶排序的方法,简单描述了桶排序的概念、原理并结合实例形式分析了C语言实现桶排序算法的具体操作技巧,需要的朋友可以参考下
    2018-01-01
  • 使用VS Code通过SSH编译Linux上的C++程序的详细步骤

    使用VS Code通过SSH编译Linux上的C++程序的详细步骤

    在软件开发领域,跨平台开发是一项常见需求,特别是对于C++开发者来说,有时需要在Windows环境下编写代码,但却需要在Linux环境中编译和运行,VS Code提供了强大的远程开发功能,本文将详细介绍如何配置和使用VS Code的SSH远程开发功能,实现无缝的跨平台C++开发体验
    2025-05-05
  • C++实现LeetCode(127.词语阶梯)

    C++实现LeetCode(127.词语阶梯)

    这篇文章主要介绍了C++实现LeetCode(127.词语阶梯),本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-07-07

最新评论