【OpenCV图像处理】二十二、图像边缘检测(上)

→图像边缘检测的目的是检测邻域内灰度明显变化的像素,常用一阶差分和二阶差分来进行边缘检测

→数字图像中的边缘是由邻域内灰度值明显变化的像素构成,边缘检测主要是图像灰度的度量检测和定位

→图像的边缘有方向幅值两个属性,沿边缘方向像素灰度值变化平缓或不发生变化,而垂直于边缘方向像素灰度值变化剧烈

→需要理解的是,边缘是灰度值变化的产物,可以利用差分来检测这种不连续性,边缘检测方法大致可以分为两类:

(1)基于一阶差分的方法

(2)基于二阶差分的方法

→一阶差分算子通过寻找一阶差分中的最大值来检测边缘,将边缘定位在一阶差分最大的方向

→二阶差分算子通过寻找二阶差分过零点来定位边缘,常用的有Laplace过零点等


在实际图像中,图像的边缘部分通常具有一定的斜坡面,斜坡部分与边缘模糊程度成比例

→边缘的宽度取决于其是灰度值到终止灰度值的斜面长度,而斜面长度取决于模糊程度


灰度不连续检测(间断检测)是最普遍的边缘检测方法:

在边缘检测中,梯度算子是常用的一阶差分算子,用于检测图像中边缘的存在和强度,Laplace算子是常用的二阶差分算子,二阶差分在边缘亮的一边符号为负,在边缘暗的一边符号为正。而在边缘处,二阶差分穿过零点


应该注意的是,差分操作对噪声十分敏感

→对于有噪边缘,利用差分检测图像边缘将放大噪声的影响,因此在利用差分进行边缘检测时,应该谨慎的考虑噪声的影响,通常在进行边缘检测之前对图像进行去噪或降噪处理

→利用一阶差分模板检测图像边缘实际上是利用一种局部处理的方法,当某一像素邻域内的灰度值的一阶差分大于阈设值时,则判定该像素为边缘像素。

→利用一阶差分模板提取的边缘图像是由许多不连续的边缘组成,这些边缘像素勾画出各个物体的轮廓,但是不能形成图像分割所需的闭合且连通的边界。

边缘连接:

是指将邻近的边缘像素连接起来,从而产生一条闭合且连通边缘的过程。根据事先定义的链接准则,对这样的边缘像素进行边缘连接处理,天不由于噪声和阴影造成的间断。

→利用二阶差分模板检测图像边缘实际上是寻找二阶差分过零点,二阶差分模板产生连续的边缘,但是不能保证检测的边缘是准确的,只能检测边缘的大致形状。


下面首先介绍一阶差分算子,大致可以分为两类,分别是梯度算子方向算子

(1)梯度算子

梯度算子定义在二维一阶导数的基础上,在数字图像中,由于像素是离散的,因此常用差分来近似偏导数

→对于一幅数字图像f(x,y),在像素(x,y)处梯度定义为:

向量


其中,Gx(x, y)和Gy(x, y)分别表示x(垂直)和y(水平)方向上的一阶差分

在边缘检测中,一个重要的量是梯度的幅度,用公式可以表示为


上式中,mag{·}表示求幅度的函数,但是为了降低复杂度,避免进行平方和开放运算,所以求幅度的公式通常写为如下形式:


使用上面这种绝对和计算简单而且保持了灰度的相对变化

→但是,也导致了梯度算子不具备各向同性→也就是不具备旋转不变性,梯度的方向指向像素值f(x, y)在(x,y)处增加最快的方向。

梯度关于x轴的角度为:


上式表示的是像素(x,y)处梯度关于x轴的方向角,这一点的梯度方向和该点边缘方向垂直


→梯度算子检测灰度值变化的两个属性是灰度值的变化率和方向,分别用幅度和方向来表示

→梯度的计算需要在每一个像素位置计算两个方向的一阶差分,常用的一阶差分算子有Robberts,Prewitt和Sobel算子等

在介绍各个算子之前,先给出一个3x3像素领域的定义,如下图所示:



首先简单介绍一下Robberts交叉算子,这是最简单的梯度算子,

在中心像素x(垂直)方向上,一阶差分计算式为

Gx = z9 - z5

在中心像素y(水平)方向上,一阶差分计算式为

Gy = z8 - z6

需要说明的是,Robbert交叉算子没有固定的中心点,因此不能使用2x2的模板卷积来实现

对于原始图像f(x,y),Roberts边缘检测输出图像为g(x,y),图像的Roberts边缘检测可以用下式来表示:


具体实现程序如下所示:

//实现Roberts边缘检测
#include <iostream>
#include <opencv2\core\core.hpp>
#include <opencv2\highgui\highgui.hpp>
#include <opencv2\imgproc\imgproc.hpp>

using namespace cv;
using namespace std;

//函数:Roberts算子实现
Mat Roberts(Mat srcImage);

int main()
{
	Mat srcImage = imread("2345.jpg",0);
	if (!srcImage.data)
	{
		cout << "读入图片错误!" << endl;
		system("pause");
		return -1;
	}
	imshow("原图像", srcImage);
	Mat dstImage = Roberts(srcImage);
	imshow("Roberts边缘检测图像", dstImage);
	waitKey();
	return 0;
}

//函数:Roberts算子实现
Mat Roberts(Mat srcImage)
{
	Mat dstImage = srcImage.clone();
	int rowsNum = srcImage.rows;
	int colsNum = srcImage.cols;
	for (int i = 0; i < rowsNum - 1; i++)
	{
		for (int j = 0; j < colsNum - 1; j++)
		{
			//根据公式进行计算
			int t1 = (srcImage.at<uchar>(i, j) -
				srcImage.at<uchar>(i + 1, j + 1))*
				(srcImage.at<uchar>(i, j) -
				srcImage.at<uchar>(i + 1, j + 1));
			int t2 = (srcImage.at<uchar>(i + 1, j) -
				srcImage.at<uchar>(i, j + 1))*
				(srcImage.at<uchar>(i + 1, j) -
				srcImage.at<uchar>(i, j + 1));
			//计算对角线像素差
			dstImage.at<uchar>(i, j) = (uchar)sqrt(t1 + t2);
		}
	}
	return dstImage;
}

程序执行后的结果如下所示:



→在实际使用中,常常使用Prewitt算子和Sobel算子来当做梯度算子。


下面首先介绍利用图像差分运算进行边缘检测,然后再分别介绍各种边缘检测算子,包括一阶算子和二阶算子


(1)图像差分运算:

对于原函数f(u),积分运算使计算f(u)映射到 f(u+a) - f(u+b)的值,差分运算分为前向差分和后向差分,一阶前向差分是指Δf = f(u+1) - f(u),一阶逆向差分是指Δf = f(u) - f(u-1)

二维离散图像f(x,y)在x方向的一阶差分定义为Δfx = f(x+1, y) - f(x, y),y方向的一阶差分定义为Δfy = f(x, y+1) - f(x, y)

差分运算通过求图像灰度变化剧烈处的一阶微分算子的极值来检测奇异点,通过奇异点的值进一步设定阈值就可以得到边缘二值化图像。

差分边缘检测中差分的水平或垂直方向都与边缘方向正交,因此在实际应用场景中,常常将边缘检测分为水平边缘,垂直边缘和对角线边缘,差分边缘检测定义方向模板如下所示:

                

垂直边缘 水平边缘 对角线边缘


利用OpenCV实现差分边缘检测实例如下所示:

//实现差分边缘检测
#include <iostream>
#include <opencv2\core\core.hpp>
#include <opencv2\highgui\highgui.hpp>
#include <opencv2\imgproc\imgproc.hpp>

using namespace cv;
using namespace std;

//图像差分函数
void diffOperation(const Mat srcImage, Mat &edgeXImage, Mat &edgeYImage);

int main()
{
	Mat srcImage = imread("2345.jpg", 0);
	if (!srcImage.data)
	{
		cout << "读入图片错误!" << endl;
		system("pause");
		return -1;
	}
	imshow("原图像", srcImage);
	Mat edgeXImage(srcImage.size(), srcImage.type());
	Mat edgeYImage(srcImage.size(), srcImage.type());

	//计算差分图像
	diffOperation(srcImage, edgeXImage, edgeYImage);
	imshow("垂直方向差分图像", edgeXImage);
	imshow("水平方向差分图像", edgeYImage);
	Mat edgeImage(srcImage.size(), srcImage.type());
	//将水平与垂直边缘进行叠加
	addWeighted(edgeXImage, 0.5, edgeYImage, 0.5, 0.0, edgeImage);
	imshow("水平和垂直方向边缘", edgeImage);
	waitKey();
	return 0;
}

void diffOperation(const Mat srcImage, Mat &edgeXImage, Mat &edgeYImage)
{ 
	Mat tempImage = srcImage.clone();
	int rowsNum = tempImage.rows;
	int colsNum = tempImage.cols;
	for (int i = 0; i < rowsNum - 1; i++)
	{
		for (int j = 0; j < colsNum - 1; j++)
		{
			//计算垂直边缘
			edgeXImage.at<uchar>(i, j) =
				abs(tempImage.at<uchar>(i + 1, j) - tempImage.at<uchar>(i, j));
			//计算水平边缘
			edgeYImage.at<uchar>(i, j) =
				abs(tempImage.at<uchar>(i, j + 1) - tempImage.at<uchar>(i, j));
		}
	}
}

执行程序后,效果如下图所示:




(2)非极大值抑制

在介绍其余的边缘检测算子之前,首先简单介绍一下图像中的非极大值抑制。

图像梯度矩阵中的元素值越大,说明图像中该点的梯度值越大,但是这并不能将它判断为该点处的边缘。

非极大值抑制操作可以提出为伪边缘信息,被广泛应用于图像边缘检测中,其原理是通过像素邻域的局部最优值,将非极大值点所对应的灰度值设置为背景像素点,如像素邻域区域满足梯度值局部最优值则判断为该像素的边缘,对其余非极大值的相关信息进行抑制,利用这个准则可以剔除大部分非边缘点。


(3)Sobel边缘检测算子

Sobel算子是应用广泛的离散微分算子之一,常常用于图像处理中的边缘检测,计算图像灰度函数的近似梯度。利用图像像素点Sobel算子计算出相应的地图向量及向量的范数,基于图像卷积来实现在水平方向与垂直方向检测对应方向的边缘。对于原图像与奇数Sobel水平核Gx,垂直核Gy进行卷积可计算水平与垂直变换,当内核大小为3x3时,Gx与Gy为下式:


对图像中没一点结合卷积后的结果求出近似梯度幅度G:

G= √(Gx^2 + Gy^2)

Sobel算子在进行边缘检测时效率较高,当对精度要求不是很高时,是一种比较常用的边缘检测方法。Sobel算子对于沿着x轴和y轴的排列的边缘表示的较好,但是对与其他角度的表示取不够精确,这时候可以使用Scharr滤波器。这种滤波器的水平与垂直的核因子如下:


首先给出使用OpenCV中的自带函数库实现Sobel边缘检测,

在OpenCV中实现相关功能使用函数Sobel(),函数的声明和说明如下所示:

void Sobel( InputArray src, OutputArray dst, int ddepth,int dx, int dy, int ksize=3,
                         double scale=1, double delta=0, int borderType=BORDER_DEFAULT );

第一个和第二个参数分别为源图像和输出图像

第三个参数为int类型的ddepth,为输出图像的深度,支持src.depth()和ddepth的组合:

(·若src.depth() = CV_8U,则取ddepth = -1 / CV_16S / CV_32F / CV_64F

(·若src.depth() = CV_16U / CV_16S ,则ddepth = -1 /CV_32F / CV_64F

(·若src.depth() = CV_32F,取ddepth = -1 /CV_32F / CV_64F

(·若src.depth() = CV_64F,取ddepth = -1 / CV_64F

第四个参数为int类型的dx,为x方向上的差分阶数

第五个参数为int类型的dy,为y方向上的差分阶数

第六个参数为int类型的ksize,有默认值3,表示Sobel核的大小,需要注意的是,Sobel算子的内核大小必须取 1,3,5,7。

第七个参数是double类型的scale,计算导数值是可选的缩放因子,默认值为1,表示默认的情况下不进行放缩操作。可以查阅getDeriveKernels查看相关内容

第八个参数是double类型的delta,表示在结果存入目标图(dst)之前可选的delta值,有默认值0

第九个参数是int类型的bordertype,有默认值BORDER_DEFAULT,在之前的文章中有过这个参数的相关介绍,在这里不再赘述。



具体程序如下:

//使用OpenCV自带函数实现Sobel边缘检测
#include <iostream>
#include <opencv2\core\core.hpp>
#include <opencv2\highgui\highgui.hpp>
#include <opencv2\imgproc\imgproc.hpp>

using namespace cv;
using namespace std;

int main()
{
	Mat srcImage = imread("2345.jpg");
	if (!srcImage.data)
	{
		cout << "读入图片错误!" << endl;
		system("pause");
		return -1;
	}
	Mat srcGray;
	cvtColor(srcImage, srcGray, CV_BGR2GRAY);
	imshow("原图像灰度图", srcGray);
	//定义边缘图,水平和垂直
	Mat edgeImage, edgeImageX, edgeImageY;
	//求x方向Sobel边缘
	Sobel(srcGray, edgeImageX, CV_16S, 1, 0, 3, 1, 0);
	//求y方向的Sobel算子
	Sobel(srcGray, edgeImageY, CV_16S, 0, 1, 3, 1);
	//线性变换,转换输入数组元素为8位无符号整型
	convertScaleAbs(edgeImageX, edgeImageX);
	convertScaleAbs(edgeImageY, edgeImageY);
	//x与y方向进行叠加
	addWeighted(edgeImageX, 0.5, edgeImageY, 0.5, 0, edgeImage);
	imshow("Sobel边缘图像", edgeImage);

	//定义scharr边缘图像
	Mat edgeXImageS, edgeYImageS, edgeImageS;
	//计算X方向的Scharr边缘
	Scharr(srcGray, edgeXImageS, CV_16S, 1, 0, 1, 0);
	convertScaleAbs(edgeXImageS, edgeXImageS);
	//计算Y方向的Scharr边缘
	Scharr(srcGray, edgeYImageS, CV_16S, 0, 1, 1, 0);
	convertScaleAbs(edgeYImageS, edgeYImageS);
	//x与y方向进行边缘叠加
	addWeighted(edgeXImageS, 0.5, edgeYImageS, 0.5,0,edgeImageS);
	imshow("Scharr边缘图像", edgeImageS);
	waitKey();
	return 0;
}

执行后的结果如下所示:

可以看出,Scharr能够保持更多更好的图像边缘部分。

                                                                                                                                                                

下面介绍不使用OpenCV中的函数库实现Sobel边缘检测

(a.非极大值抑制Sobel边缘检测

→非极大值抑制Sobel边缘检测实现步骤主要如下:

(①.将图像转换为32位浮点型数据,定义水平或垂直方向的Sobel算子

(②.利用filter2D完成图像与算子的卷积操作,计算卷积结果的梯度幅值

(③.自适应计算出梯度幅度阈值,阈值设置不大于梯度幅值的均值乘以4,根据与之对水平或垂直的邻域区域梯度进行比较。

(④.判断当前邻域梯度是否大于水平或垂直邻域梯度,自适应完成边缘检测处二值图像的操作。

对上面这个过程进行程序实现如下所示:

//图像非极大值抑制实现Sobel竖直细化边缘
bool SobelVerEdge(Mat srcImage, Mat &dstImage)
{
	CV_Assert(srcImage.channels() == 1);
	srcImage.convertTo(srcImage, CV_32FC1);
	//水平方向的Sobel算子
	Mat sobelX = (Mat_<float>(3, 3) << -0.125, 0, 0.125,
		-0.25, 0, 0.25,
		-0.125, 0, 0.125);
	Mat ConResMat;
	//卷积运算
	filter2D(srcImage, ConResMat, srcImage.type(), sobelX);
	//计算梯度的幅度
	Mat gradMagMat;
	multiply(ConResMat, ConResMat, gradMagMat);
	//根据梯度幅度及参数设置阈值
	int scaleVal = 4;
	double thresh = scaleVal*mean(gradMagMat).val[0];
	Mat resultTempMat = Mat::zeros(gradMagMat.size(), gradMagMat.type());
	float *pDataMag = (float*)gradMagMat.data;
	float *pDataRes = (float*)resultTempMat.data;
	const int rowsNum = ConResMat.rows;
	const int colsNum = ConResMat.cols;
	for (int i = 1; i != rowsNum - 1; ++i)
	{
		for (int j = 1; j != colsNum - 1; ++j)
		{
			//计算这一点的梯度与水平或垂直梯度值的大小并比较结果
			bool b1 = (pDataMag[i*colsNum + j] > pDataMag[i*colsNum + j - 1]);
			bool b2 = (pDataMag[i*colsNum + j] > pDataMag[i*colsNum + j + 1]);
			bool b3 = (pDataMag[i*colsNum + j] > pDataMag[(i - 1)*colsNum + j]);
			bool b4 = (pDataMag[i*colsNum + j] > pDataMag[(i + 1)*colsNum + j]);
			//判断邻域梯度是否满足大于水平或垂直梯度的条件
			//并根据自适应阈值参数进行二值化
			pDataRes[i*colsNum + j] = 255 * ((pDataMag[i*colsNum + j] > thresh)
				&& ((b1 && b2) || (b3 && b4)));
		}
	}
	resultTempMat.convertTo(resultTempMat, CV_8UC1);
	dstImage = resultTempMat.clone();
	return true;
}
(b.图像直接卷积实现Sobel

图像直接卷积Sobel边缘检测实现比较简单,首先定义水平或垂直方向的Sobel核因子,直接对源图像进行窗遍历,计算窗口内的邻域梯度幅值;然后根据梯度模长进行二值化操作,完成图像水平或垂直方向的边缘检测

图像直接卷积Sobel边缘实现代码如下所示:

//图像直接卷积实现Sobel
bool SobelEdge(const Mat &srcImage, Mat &dstImage, uchar threshold)
{
	CV_Assert(srcImage.channels() == 1);
	//初始化水平核因子
	Mat sobelX = (Mat_<double>(3, 3) << 1, 0, -1,
		2, 0, -2,
		1, 0, -1);
	//初始化垂直核因子
	Mat sobelY = (Mat_<double>(3, 3) << 1, 2, 1,
		0, 0, 0,
		-1, -2, -1);
	dstImage = Mat::zeros(srcImage.rows - 2, srcImage.cols - 2, srcImage.type());
	double edgeX = 0;
	double edgeY = 0;
	double graMag = 0;
	for (int k = 1; k < srcImage.rows - 1; ++k)
	{
		for (int n = 1; n < srcImage.cols - 1; ++n)
		{
			edgeX = 0;
			edgeY = 0;
			//遍历计算水平与垂直梯度
			for (int i = -1; i <= 1; i++)
			{
				for (int j = -1; j <= 1; j++)
				{
					edgeX += srcImage.at<uchar>(k + i, n + j)*
						sobelX.at<double>(1 + i, 1 + j);
					edgeY += srcImage.at<uchar>(k + i, n + j)*
						sobelY.at<double>(1 + i, 1 + j);
				}
			}
			//计算梯度模长
			graMag = sqrt(pow(edgeY, 2) + pow(edgeX, 2));
			//进行二值化
			dstImage.at<uchar>(k - 1, n - 1) =
				((graMag > threshold) ? 255 : 0);
		}
	}
	return true;
}


(c.图像卷积下非极大值抑制Sobel

图像卷积下非极大值抑制Sobel边缘检测的实现过程与之前的a部分比较类似。但是需要说明的是,非极大值抑制虽然能够较好的剔除虚假边缘点,但是对于某些特定场景下的边缘检测并不起作用,例如无损文本字符识别

相关的实现代码如下所示:


//图像卷积实现Sobel非极大值抑制
bool sobelOptaEdge(const Mat &srcImage, Mat &dstImage, int flag)
{
	CV_Assert(srcImage.channels() == 1);
	//初始化Sobel水平核因子
	Mat sobelX = (Mat_<double>(3, 3) << 1, 0, -1,
		2, 0, -2,
		1, 0, -1);
	//初始化Sobel垂直核因子
	Mat sobelY = (Mat_<double>(3, 3) << 1, 2, 1,
		0, 0, 0,
		-1, -2, -1);
	//计算水平与垂直卷积
	Mat edgeX, edgeY;
	filter2D(srcImage, edgeX, CV_32F, sobelX);
	filter2D(srcImage, edgeY, CV_32F, sobelY);
	//根据传入的参数确定计算水平或垂直方向的边缘
	int paraX = 0;
	int paraY = 0;
	switch (flag)
	{
	case 0:	
		paraX = 1;
		paraY = 0;
		break;
	case 1:
		paraX = 0;
		paraY = 1;
		break;
	case 2:
		paraX = 1;
		paraY = 1;
		break;
	default:
		break;
	}
	edgeX = abs(edgeX);
	edgeY = abs(edgeY);
	Mat graMagMat = paraX*edgeX.mul(edgeX) +
		paraY*edgeY.mul(edgeY);
	//计算阈值
	int scaleVal = 4;
	double thresh = scaleVal*mean(graMagMat).val[0];
	dstImage = Mat::zeros(srcImage.size(), srcImage.type());
	for (int i = 1; i < srcImage.rows - 1; i++)
	{
		float *pDataEdgeX = edgeX.ptr<float>(i);
		float *pDataEdgeY = edgeY.ptr<float>(i);
		float *pDataGraMag = graMagMat.ptr<float>(i);
		//阈值化和极大值抑制
		for (int j = 1; j < srcImage.cols - 1; j++)
		{
			//判断当前邻域梯度是否大于阈值与大于水平或垂直梯度
			if (pDataGraMag[j]>thresh &&
				(pDataEdgeX[j]>paraX*pDataEdgeY[j] &&
				pDataGraMag[j] > pDataGraMag[j - 1] &&
				pDataGraMag[j] > pDataGraMag[j + 1] ||
				(pDataEdgeY[j] > paraY*pDataEdgeX[j] &&
				pDataGraMag[j] > pDataGraMag[j - 1] &&
				pDataGraMag[j] > pDataGraMag[j + 1])))
				dstImage.at<uchar> = 255;
		}
	}
	return true;
}

  • 5
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
图像边缘提取实验报告 一、实验目的 通过课堂的学习,已经对图像分割的相关理论知识已经有了全面的了解,知道了许 多图像分割的算法及算子,了解到不同的算子算法有着不同的优缺点,为了更好更直观 地对图像分割进行深入理解,达到理论联系实际的目的,特制定如下的实验。 实验原理 检测图像边缘信息,可以把图像看做曲面,边缘就是图像的变化最剧烈的位置。这里 所讲的边缘信息包含两个方面:一是边缘的具体位置,即像素的坐标;而是边缘的方向 。微分算子有两个重要性质:定域性(或局部性)、敏感性(或无界性)。敏感性就是说, 它对局部的函数值变化很敏感,但是因其对变化过于敏感又有了天然的缺陷——不能抵抗 噪声。局部性意思是指,每一点的导数只与函数在该点邻近的信息有关。 主要有两大类基于微分算子的边缘检测技术:一阶微分算子边缘检测与二阶微分算子 边缘检测。这些检测技术采用以下的基本步骤: 1) 将相应的微分算子简化为离散的差分格式,进而简化为模板(记为T)。 2) 利用模板对图像f(m,n)进行运算,获得模板作用后的结果Tf(m,n)。 3) 提出阈值h,在采用一阶微分算子情形记录下高于某个阈值h的位置坐标 (而采用二阶微分算子情形,一般是对某个阈值确立 ) 4) 对集合进行整理,同时调整阈值h。 Roberts算子 Roberts算子是一种利用局部差分算子寻找边缘的算子,两个模板分别为 则,= = 算法的步骤为: 1) 首先用两个模板分别对图像作用得到和; 2) 对,进行阈值判决,若大于阈值则相应的点 位于便于边缘处。 对于阈值选取的说明:由于微分算子的检测性能受阈值的影响较大,为此,针对具体图 像我们采用以下阈值的选取方法,对处理后的图像统计大于某一阈值的点,对这些数据 求平均值,以下每个程序均采用此方法,不再做说明。 Sobel算子 Sobel算子采用中心差分,但对中间水平线和垂直线上的四个邻近点赋予略高的权重 。两个模板分别如下: Prewitt算子 Prewitt算子也属于中心差分类型,但没有给最邻近点较高的权重,两个模板如下: 采用一阶微分算子很难找到一个一致的阈值选择办法,保证检测出的图像有相对均匀 的宽度,克服这个障碍的办法是改用二阶微分算子进行边缘检测定位。 Laplace 采用一阶微分算子很难找到一个一致的阈值选择办法,保证检测出的图像有相对均匀 的宽度,克服这个障碍的办法是改用二阶微分算子进行边缘检测定位。 经常采用如下Laplace微分算子: 并进而寻找的跨零点的位置(零点的局部正和负的取值都有)。 当然实践中可以通过模板来实现,本程序采用如下模板: 无论什么样的微分算子,直接用来进行边缘检测,会受到噪声很大的干扰。即使是二 阶微分算子也不能克服噪声干扰。但是如果采用高斯低通滤波,所得的结果则比较好地 保留了图像的边缘特征。 Marr-Hildrech的LOG边缘检测算法: Canny检测子 Canny算子采用和数据内容相关的滤波技术。 Canny算子求边缘点具体算法步骤如下: 1. 用高斯滤波器平滑图像. 2. 用一阶偏导有限差分计算梯度幅值和方向. 3. 对梯度幅值进行非极大值抑制 . 4. 用双阈值算法检测和连接边缘. 步1. 图像与高斯平滑滤波器卷积: 步3. 对梯度幅值进行非极大值抑 制(non_maxima suppression,NMS): 仅仅得到全局的梯度并不足以确定边缘,因此为确定边缘,必须保留局部梯度最大的 点,而抑制非极大值。 解决方法:利用梯度的方向: 步4. 用 双阈值算法检测和连接边缘: 对非极大值抑制图像作用两个阈值th1和th2,两者关系th1=0.4th2。我们把梯度值小 于th1的像素的灰度值设为0,得到图像1。然后把梯度值小于th2的 像素的灰度值设为0,得到图像2。由于图像2的阈值较高,去除大部分噪音,但同时也损 失了有用的边缘信息。而图像1的阈值较低,保留了较多的信息,我们可以以图像2为基 础,以图像1为补充来连结图像的边缘。 链接边缘的具体步骤如下: 对图像2进行扫描,当遇到一个非零灰度的像素p(x,y)时,跟踪以p(x,y)为开始点的 轮廓线,直到轮廓 线的终点q(x,y)。 考察图像1中 与图像2中q(x,y)点位置对应的点s(x,y)的8邻 近区域。如果在s(x,y)点的8邻近区域中有非零像素s(x,y)存 在,则将其包括到图像2中,作为r(x,y)点。从r(x,y)开始, 重复第一步,直到我们在图像1和图像2中都无法继续为止。 当完成对包含p(x,y)的 轮廓线的连结之后,将这条轮廓线标记为已经访问。回到第一步,寻找下一条轮廓线。 重复第一步、第二步、第三步,直到图像2中找 不到新轮廓线为止。 至此,完成canny算 子的边缘检测。 具体过程 Log算子阈值取0.01 Canny
OpenCV是一个开源的计算机视觉库,提供了丰富的图像处理和计算机视觉算法。其中,图像边缘检测OpenCV中的一个重要功能,用于检测图像中物体的边缘。 在OpenCV中,常用的图像边缘检测算法有以下几种: 1. Canny边缘检测算法:Canny算法是一种经典的边缘检测算法,它通过多阶段的处理来提取图像中的边缘。首先,对图像进行高斯滤波以降低噪声;然后,计算图像的梯度,并根据梯度的方向和幅值来确定边缘;最后,使用非极大值抑制和双阈值处理来提取最终的边缘。 2. Sobel算子:Sobel算子是一种基于梯度的边缘检测算子,它通过计算图像的一阶或二阶导数来检测边缘。Sobel算子可以分别计算图像在水平和垂直方向上的梯度,并将两个方向上的梯度合并得到最终的边缘。 3. Laplacian算子:Laplacian算子是一种基于二阶导数的边缘检测算子,它可以检测出图像中的高频变化区域,即边缘。Laplacian算子对图像进行二阶导数计算,并通过零交叉点来确定边缘。 使用OpenCV进行图像边缘检测的步骤如下: 1. 读取图像:使用OpenCV的函数读取图像文件。 2. 灰度化:将彩色图像转换为灰度图像,可以使用OpenCV的函数将图像转换为灰度模式。 3. 滤波处理:对灰度图像进行滤波处理,常用的滤波方法有高斯滤波。 4. 边缘检测:使用OpenCV提供的边缘检测函数,如Canny、Sobel或Laplacian等。 5. 显示结果:将检测到的边缘结果显示出来,可以使用OpenCV的函数将图像显示在窗口中。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值