opencv(11)--边缘检测算子

11.1 引言-卷积的边缘检测应用

       当图像的某个区域有灰阶变化,对变化率求导,得到变化率最快的位置。

       边缘是像素值发生跃迁的地方,在图像特征提取、对象检测、模式识别等方面都有重要的作用。通过对图像求一阶导数可以捕捉边缘(delta=f(x)-f(x-1)越大,说明像素在x方向变化越大)。

11.2 Sobel算子

       Sobel算子是一种边缘检测算法,常用于图像处理领域。他是一种离散微分算子,用来计算图像灰度的近似梯度。Sobel算子功能集合高斯平滑和微分求导,是一阶微分算子,在水平或垂直方向求导,得到图像X/Y方向的梯度图像。对噪声具有平滑作用,抗噪声能力强,计算量较大,但定位精度不高,得到的边缘比较粗,适用于精度要求不高的场合。

水平梯度:G_{x}=\begin{bmatrix} -1 &0 &1 \\ -2& 0& 2\\ -1& 0 & 1 \end{bmatrix}*I            垂直梯度;G_{}=\begin{bmatrix} -1 &-2 &-1 \\ 0& 0& 0\\ 1&2 & 1 \end{bmatrix}*I  

则最终的图像梯度为:G=\sqrt{G_{x}^{2}+G_{y}^{2}} \approx |G_{x}|+|G_{y}|  

当内核大小为 3时, 用以上的Sobel内核可能产生比较明显的误差(毕竟,Sobel算子只是求取了导数的近似值)。 为解决这一问题,OpenCV提供了 Scharr 函数,但该函数仅作用于大小为3的内核。该函数的运算与Sobel函数一样快,但结果却更加精确,其内核为:

 

 11.2.1 相关API

  • void cv::Sobel(InputArray src, OutputArray dst, int ddepth,int dx,int dy,int ksize=3,double scale=1, double delta=0, int borderType=BORDER_DEFAULT)
参数含义
作用sobel算子求梯度图像
输入src

原图

dst输出图像,大小与输入图像一致
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

dx

x向,几阶导数

dyy向,几阶导数
ksizesobel核大小,有默认值3,表示Sobel核的大小;必须取1,3,5或7。
scale

计算导数值时的缩放因子,默认1

delta表示在结果存入目标图之前可选的delta值,默认0
borderType便捷模式
返回值void
  • void cv::Scharr(InputArray src, OutputArray dst, int ddepth,int dx,int dy,int ksize=3,double scale=1, double delta=0, int borderType=BORDER_DEFAULT)
参数含义
作用sobel算子求梯度图像
输入src

原图

dst输出图像,大小与输入图像一致
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

dx

x向,几阶导数

dyy向,几阶导数
ksizesobel核大小,有默认值3,表示Sobel核的大小;必须取1,3,5或7。
scale

计算导数值时的缩放因子,默认1

delta表示在结果存入目标图之前可选的delta值,默认0
borderType便捷模式
返回值void

11.2.2 代码示例

int main(int argc, char** argv)
{
	Mat src = imread("D:\\testimg\\CSet12\\lena.png");
	if (src.empty())
	{
		printf("Could not load the image...\n");
		return -1;
	}
	else;
	char input_win[] = "srcImg";
	namedWindow(input_win, WINDOW_AUTOSIZE);
	imshow(input_win, src);


	//先平滑-高斯平滑
	Mat blurimg;
	GaussianBlur(src,blurimg,Size(3,3),0,0);

	//转灰度
	Mat grayImg;
	cvtColor(blurimg, grayImg,COLOR_BGR2GRAY);
	imshow("grayImg", grayImg);

	//求梯度x和y
	Mat SobelxImg,SobelyImg;
	//Sobel(grayImg, SobelxImg,-1,1,0,3);
	Sobel(grayImg, SobelxImg, CV_16S, 1, 0, 3);// ddepth选择不同的深度会有不同的效果 CV_16S
	//Scharr(grayImg, SobelxImg, CV_16S, 1, 0, 3);
	Sobel(grayImg, SobelyImg, CV_16S, 0, 1, 3);
	convertScaleAbs(SobelxImg, SobelxImg); //将图像的像素值转换为绝对值并进行缩放操作。
	convertScaleAbs(SobelyImg, SobelyImg);

	imshow("SobelxImg", SobelxImg);
	imshow("SobelyImg", SobelyImg);

	//求振幅图像
	Mat xyGradImg;
	addWeighted(SobelxImg,0.5, SobelyImg,0.5,0, xyGradImg);
	imshow(" xyGradImg", xyGradImg);

	//用像素梯度相加
	Mat xyGradImg1=Mat(SobelxImg.size(), SobelxImg.type());
	int width = SobelxImg.cols;
	int height = SobelxImg.rows;
	for (int i = 0; i < height; i++)
	{
		for (int j = 0; j < width; j++)
		{
			int xg = SobelxImg.at<uchar>(i, j);
			int yg = SobelyImg.at<uchar>(i, j);
			int xy = xg + yg;
			xyGradImg1.at<uchar>(i, j) = saturate_cast<uchar>(xy);
		}
	}
	imshow(" xyGradImg1", xyGradImg1);

	waitKey(0);
	return 0;
}

11.3 Laplance算子

        一阶导数边缘为波峰或波谷,二阶导数时,图像灰阶变化最大处的值为零即边缘是零值。通过二阶导数计算,依据此理论我们可以计算图像的二阶导数,提取边缘。具有旋转不变性,容易受噪声影响,不能检测边缘的方向,一般不直接用于检测边缘,而是判断明暗变化。很少用该算子检测边缘,而是用来判断边缘像素视为与图像的明区还是暗区。

一阶导数:\frac{dy}{dx}=\frac{f(x+1)-f(x)}{(x+1)-x}=f(x+1)-f(x)

二阶导数为一阶导数的导数:\frac{d^{2}y}{dx^{2}}=\frac{(f(x+1)-f(x))-(f(x)-f(x-1))}{x-(x-1)}=f(x+1)+f(x-1)-2f(x)

laplance算子是一种对图像的二阶求导,x和y方向的偏导数之和:

Laplance(f)=\frac{\partial^{2} f}{\partial x^{2}}+\frac{\partial^{2} f}{\partial y^{2}}

11.3.1 相关API

  1. laplance算子的处理流程如下:
  2. 高斯模糊-去噪声;
  3. 转换为灰度图像;
  4. laplance-二阶导数计算;
  5. 灰度取绝对值;
  • void cv::Laplacian(InputArray src, OutputArray dst, int ddepth,int ksize=3,double scale=1, double delta=0, int borderType=BORDER_DEFAULT)
参数含义
作用Laplance算子求梯度图像
输入src

原图

dst输出图像,大小与输入图像一致
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

dx

x向,几阶导数

dyy向,几阶导数
ksize核大小,有默认值3,必须为正奇数。
scale

计算导数值时的缩放因子,默认1

delta表示在结果存入目标图之前可选的delta值,默认0
borderType便捷模式
返回值void

10.3.2 代码示例

int main(int argc, char** argv)
{
	Mat src = imread("D:\\testimg\\CSet12\\lena.png");
	if (src.empty())
	{
		printf("Could not load the image...\n");
		return -1;
	}
	else;
	char input_win[] = "srcImg";
	namedWindow(input_win, WINDOW_AUTOSIZE);
	imshow(input_win, src);


	//先平滑-高斯平滑
	Mat blurimg;
	GaussianBlur(src,blurimg,Size(3,3),0,0);

	//转灰度
	Mat grayImg;
	cvtColor(blurimg, grayImg,COLOR_BGR2GRAY);
	imshow("grayImg", grayImg);

	//Laplance算子
	Mat laplanceImg;
	Laplacian(grayImg,laplanceImg,CV_16S,3);
	convertScaleAbs(laplanceImg, laplanceImg);
	imshow("laplanceImg", laplanceImg);

	waitKey(0);
	return 0;
}

11.4 Canny算子

Canny边缘检测,是一种多即边缘检测的算法。该算法是从不同的视觉对象中提取有用的信息并减少数据量的一种技术。在图像处理中非常常用。使用两种不同的阈值分别检测强边缘和弱边缘,并且当弱边缘和强边缘相连时,才将弱边缘包含在输出图像中。canny 产生的边缘很细,可能就一个像素那么细,没有强弱之分。

11.4.1 canny实现步骤

  1. 高斯模糊--降噪、平滑,减少误检测;
  2. 灰度转换--得到灰度图像;
  3. 计算梯度强度和方向--Sobel/Scharr;
  4. 非极大值抑制--边缘细化,消除边缘杂散影响;利用梯度方向像素判断是否为边界点
  5. 高低阈值输出二值图像--双阈值法。高低阈值的推荐比值为3:1/2:1.

11.4.2 相关API

  • void cv::Canny(InputArray src, OutputArray dst, double threshold1, double threshold2, int aptertureSize=3,bool L2gradient=false)
参数含义
作用Laplance算子求梯度图像
输入src

原图,8bit的输入图像

dst输出图像,边缘图像
threshold1

低阈值。值越大,找到的边缘越少

threshold2

高阈值

aptertureSizeSobel算子的孔径大小,默认3
L2gradient

是否选择用L2归一化,默认false

返回值void

11.4.3 代码示例

int main(int argc, char** argv)
{
	Mat src = imread("D:\\testimg\\CSet12\\lena.png");
	if (src.empty())
	{
		printf("Could not load the image...\n");
		return -1;
	}
	else;
	char input_win[] = "srcImg";
	namedWindow(input_win, WINDOW_AUTOSIZE);
	imshow(input_win, src);


	//先平滑-高斯平滑
	Mat blurimg;
	GaussianBlur(src,blurimg,Size(3,3),0,0);

	//转灰度
	Mat grayImg;
	cvtColor(blurimg, grayImg,COLOR_BGR2GRAY);
	imshow("grayImg", grayImg);

	//canny算子
	Mat CannyImg;
	Canny(grayImg, CannyImg, 100,175);
	imshow("CannyImg", CannyImg);
	//彩色显示线条
	Mat CannyColor=Mat(src.size(),src.type());
	src.copyTo(CannyColor, CannyImg);
	imshow(" CannyColor", CannyColor);

	waitKey(0);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值