OpenCV边缘提取算法流程的实现(附DEMO)

 更新时间:2022年08月03日 14:41:39   作者:颜丑文良777  
本文主要介绍了OpenCV边缘提取算法流程的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

在传统的计算机视觉领域,经常需要使用一些传统的图像处理算法完成对图像的边缘提取功能,通过对图像的边缘进行提取完成对目标对象的分割,目标分割技术又包括语义分割与实例分割,比较高端的鲁棒性较强的还是需要卷积神经网络算法进行相关的训练,如fcn全连接网络,mask-rcnn实例分割网络。本案例旨在采用传统的图像处理技术完成对图像的边缘检测任务,并通过膨胀腐蚀操作进行连通域的提取,之后通过连通域的填充以及掩膜操作完成目标对象的分割。

具体需要达到的目标如下:

 上图所示,可以很好的将河道信息进行提取。

1. 具体算法流程

首先对采集的图片进行灰度化处理(方便进行数据处理),然后对灰度图像进行中值滤波操作去除湖面上的细小杂质,之后通过x方向和y方向上的Sobel梯度算子分别获取梯度图像,并将梯度图像转换成CV_8UC1类型,并对转换后的x,y方向上的梯度图像进行OTSU二值化操作获取二值图像,并对两幅二值图像按对应像素位置进行与运算,目的是为了去除河道上的波纹干扰。(可以继续对与运算之后的结果图进行中值滤波去除湖面上的细小杂质)。最后对二值图进行多次迭代的膨胀腐蚀操作以及小区域块的填充操作(用到findContours与drawContours接口进行轮廓查找与填充)获取河道连通区域。

2.流程图

可以通过如下流程图进行展示。                     

3. 涉及到的代码

int main() {
	Mat srcImage, srcImage2, srcImage3;
	for (int j = 1; j <= 172; j++)
	{
		//白天总共172张图片。1-172;验证:1,162,146;
		//(挑选最好的效果作为模板。对比108与117进行分析)。
		//if (j == 108 || j == 117)
		//{//对比分析之后选择第108张图片作为模板图片
		char ch[4096] = { 0 };
		sprintf(ch, "..\\findriveredge\\day\\2 (%d).jpg", j);
		srcImage = imread(ch, IMREAD_ANYCOLOR);
		srcImage2 = srcImage.clone();
		srcImage3 = srcImage.clone();
		if (srcImage.empty())
		{
			return -1;
		}
		if (srcImage.channels() == 3)
		{
			cvtColor(srcImage, srcImage, COLOR_BGR2GRAY);
		}
 
		Mat outImage;
		medianBlur(srcImage, outImage, g_nKrenel);//首先对灰度图进行中值滤波操作,去除一些杂质。
 
		Mat grad_x, abs_grad_x, grayImage_x;
		Sobel(outImage, grad_x, CV_16S, 1, 0, 3, 1, 1, BORDER_DEFAULT);
		convertScaleAbs(grad_x, abs_grad_x);
		abs_grad_x.convertTo(grayImage_x, CV_8U);
 
 
		Mat grad_y, abs_grad_y, grayImage_y;
		Sobel(outImage, grad_y, CV_16S, 0, 1, 3, 1, 1, BORDER_DEFAULT);
		convertScaleAbs(grad_y, abs_grad_y);
		abs_grad_y.convertTo(grayImage_y, CV_8U);
 
 
		Mat XBin, YBin;
		int n_thresh_x = myOtsu(grayImage_x);
		threshold(grayImage_x, XBin, n_thresh_x, 255, THRESH_BINARY);
 
 
		int n_thresh_y = myOtsu(grayImage_y);
		threshold(grayImage_y, YBin, n_thresh_y, 255, THRESH_BINARY);
 
 
		Mat Bin;
		bitwise_and(XBin, YBin, Bin);
 
 
		Mat outBin;
		medianBlur(Bin, outBin, 3);//去除一些杂质点。
 
 
		Mat outBin2 = outBin.clone();
		int n_iterations = 5;
		Mat element = getStructuringElement(MORPH_ELLIPSE, Size(15, 15));//膨胀变亮形成连通域。
		Mat element2 = getStructuringElement(MORPH_ELLIPSE, Size(5, 5));//腐蚀操作断开一些连通域。
		dilate(outBin2, outBin2, element, Point(-1, -1), n_iterations);
		erode(outBin2, outBin2, element2, Point(-1, -1), 3);//腐蚀操作,断开河流区域内部的连接区域,方便后续的填充处理。
 
 
		//将河流ROI区域小块连通域填黑。
		Mat outBin3 = outBin2.clone();
		vector<vector<Point>> contours;
		vector<Vec4i> hie;
		findContours(outBin3, contours, hie, RETR_LIST, CHAIN_APPROX_SIMPLE);
		float f_area = 0.0;
		for (int i = 0; i < contours.size(); i++)
		{
			f_area = contourArea(contours[i]);
			if (f_area < 250000)
			{
				drawContours(outBin3, contours, i, Scalar(0), -1);
			}
		}
 
 
		//由于final bin2在腐蚀过程中存在部分背景区域为黑色空洞,需要将其填白。
		Mat outBin4_tmp = ~outBin3;
		Mat outBin4;
		contours.clear();
		hie.clear();
		findContours(outBin4_tmp, contours, hie, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
		for (unsigned int i = 0; i < contours.size(); i++)
		{
			f_area = contourArea(contours[i]);
			if (f_area < 250000)
			{
				drawContours(outBin4_tmp, contours, i, Scalar(0), -1);
			}
		}
		outBin4 = ~outBin4_tmp;
 
		//迭代腐蚀突出河流边界区域。
		erode(outBin4, outBin4, element, Point(-1, -1), 10);
 
 
		//(可以对腐蚀图在进行一次外轮廓填充)。
		Mat outBin5_tmp = ~outBin4.clone();
		Mat outBin5;
		contours.clear();
		hie.clear();
		findContours(outBin5_tmp, contours, hie, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE);
		for (unsigned int i = 0; i < contours.size(); i++)
		{
			f_area = contourArea(contours[i]);
			if (f_area < 100000)
			{
				drawContours(outBin5_tmp, contours, i, Scalar(0), -1);
			}
		}
		outBin5 = ~outBin5_tmp;
 
 
		//根据outBin4,对原rgb图取感兴趣区域(即河流区域)
		for (int i = 0; i < outBin5.rows; i++)
		{
			for (int j = 0; j < outBin5.cols; j++)
			{
				if (outBin5.at<uchar>(i, j) == 255)
				{
					srcImage2.at<Vec3b>(i, j)[0] = 0;
					srcImage2.at<Vec3b>(i, j)[1] = 0;
					srcImage2.at<Vec3b>(i, j)[2] = 0;
				}
			}
		}
		namedWindow("finalImage", 0);
		imshow("finalImage", srcImage2);//这里的srcImage2表示最后所需效果图
 
 
		cout << j << endl;
		waitKey(30);
	}
	return 0;
}

到此这篇关于OpenCV边缘提取算法流程的实现(附DEMO)的文章就介绍到这了,更多相关OpenCV 边缘提取内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 最新C/C++中的new和delete的实现过程小结

    最新C/C++中的new和delete的实现过程小结

    这篇文章主要介绍了C/C++中的new和delete的实现过程,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-06-06
  • C++中的struct和class的区别详解

    C++中的struct和class的区别详解

    这篇文章主要介绍了C++中的struct和class的区别详解,文章围绕主题展开详细的内容介绍,具有一定的参考价值,需要的朋友可以参考一下
    2022-08-08
  • C语言深入讲解函数的使用

    C语言深入讲解函数的使用

    各位小伙伴们,今天YU同学给大家带来的是与函数相关的知识,本篇将会带着大家初步认识和调用函数来解决一些简单的问题
    2022-04-04
  • C++自定义数据类型方法详情

    C++自定义数据类型方法详情

    这篇文章主要介绍了C++自定义数据类型方法详情,总结了两种方法,分别是typedef声明和枚举类型enum,相关内容需要的小伙伴可以参考下面文章内容,希望对你的学习有所帮助
    2022-03-03
  • Matlab实现三维投影绘制的示例代码

    Matlab实现三维投影绘制的示例代码

    这篇文章系小编为大家带来了一个三维投影绘制函数(三视图绘制),函数支持三维曲线、曲面、三维多边形、参数方程曲线、参数方程曲面的投影绘制,需要的可以参考一下
    2022-08-08
  • Visual Studio 2022 激活码(亲测可用)

    Visual Studio 2022 激活码(亲测可用)

    在 Visual Studio 2019 的基础上,新版集成开发坏境提供了非常多的改进,包括对 64 位、.NET 6 的支持,为核心调试器提供更好的性能。本文给大家分享Visual Studio 2022 激活码,需要的朋友参考下吧
    2021-12-12
  • C++异常使用详解(看这一篇就够了)

    C++异常使用详解(看这一篇就够了)

    C++中的异常是指在程序执行过程中发生错误,导致程序无法正常运行的情况,下面这篇文章主要给大家介绍了关于C++异常使用的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2023-10-10
  • 数据结构之伸展树详解

    数据结构之伸展树详解

    这篇文章主要介绍了数据结构之伸展树详解,本文对伸展树(Splay Tree)的单旋转操作、一字型旋转、之字形旋转区间操作等理论知识做了讲解,并给出实现代码,需要的朋友可以参考下
    2014-08-08
  • 基于Matlab实现有雪花飘落的圣诞树的绘制

    基于Matlab实现有雪花飘落的圣诞树的绘制

    圣诞节快到了(虽然还有十天),一起来用MATLAB画个简单圣诞树叭~代码几乎取消了全部的循环,因此至少需要17b之后的版本,仅存的循环用来让树旋转起来,让雪花飘落起来,让树顶上的星光摇曳起来~感兴趣的可以试一试
    2022-12-12
  • 利用Matlab制作抖音同款含褶皱面料图

    利用Matlab制作抖音同款含褶皱面料图

    这篇文章主要介绍了如何利用Matlab制作抖音的同款含褶皱面料图,文中的示例代码讲解详细,对我们学习Matlab有一定帮助,需要的可以参考一下
    2022-03-03

最新评论