opencv 边缘检测 Sobel算子 Scharr算子 Laplacian算子 (c++)

简述:Sobel Scharr Laplacian

Sobel算子是高斯平滑加微分运算的联合运算,因此它更抗噪声。你可以指定要采用的导数方向,垂直或水平(分别通过参数yorder和xorder)。你还可以通过参数ksize指定内核的大小。如果ksize = -1,则使用3x3 Scharr滤波器,比3x3 Sobel滤波器具有更好的结果。

Sobel算子

k e r n e l = [ − 1 0 1 − 2 0 2 − 1 0 1 ] kernel = \left[ \begin{matrix} -1 & 0 & 1 \\-2 & 0 & 2 \\ -1 & 0 & 1 \end{matrix} \right] kernel=121000121
k e r n e l = [ − 1 − 2 − 1 0 0 0 1 2 1 ] kernel = \left[ \begin{matrix} -1 & -2 & -1 \\0 & 0 & 0 \\ 1 & 2 & 1 \end{matrix} \right] kernel=101202101

Scharr算子

k e r n e l = [ − 3 0 3 − 10 0 10 − 3 0 3 ] kernel = \left[ \begin{matrix} -3 & 0 & 3 \\-10 & 0 & 10 \\ -3 & 0 & 3 \end{matrix} \right] kernel=31030003103
k e r n e l = [ − 3 − 10 − 3 0 0 0 3 10 3 ] kernel = \left[ \begin{matrix} -3 & -10 & -3 \\0 & 0 & 0 \\ 3 & 10 & 3\end{matrix} \right] kernel=30310010303
和Sobel算子相比,scharr算子临近像素的权重更大,所以精确度更高,能计算出更小的梯度变化

Laplacian 算子

如果ksize > 1 (ksize必须为正奇数) ,该函数通过Sobel算子计算出图像X方向和Y方向的二阶导数,将两个方向的导数求和得到Laplacian算子:
Δ s r c = ∂ 2 s r c ∂ x 2 + ∂ 2 s r c ∂ y 2 Δsrc=\frac{∂^{2}src}{∂x^{2}} + \frac{∂^{2}src}{∂y^{2}} Δsrc=x22src+y22src
如果ksize = 1,则使用以下内核用于过滤:

k e r n e l = [ 0 1 0 1 − 4 1 0 1 0 ] kernel=\left[ \begin{matrix} 0 & 1 & 0 \\1 & -4 & 1 \\ 0 & 1 & 0 \end{matrix} \right] kernel=010141010

1. Sobel()

注意:当输出数据类型为cv::CV_8U时有一个小问题。黑色到白色的过渡被视为正斜率(具有正值),而白色到黑色的过渡被视为负斜率(具有负值)。因此,将数据转换为CV_8U时,所有负斜率均​​设为零。简而言之,就是会错过这一边缘信息。如果要检测两个边缘,更好的选择是将输出数据类型保留为更高的形式,例如cv::CV_16S,cv::CV_64F等,取其绝对值,然后转换回cv::CV_8U。

CV_EXPORTS_W 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 );
                         
/*Sobel算子将高斯平滑和微分相结合,因此结果或多或少具有抗噪性。
通常,使用(xorder = 1,yorder = 0,ksize = 3)或(xorder = 0,yorder = 1,ksize = 3)来对x求导或对y求导。
第一种情况对应于一个内核:
-1  0  1
-2  0  2
-1  0  1
第二种情况对应于以下内核:
-1 -2 -1
 0  0  0 
 1  2  1

@param src 			//输入图像。
@param dst 			//输出与src相同大小和相同通道数的图像。
@param ddepth 		//输出图像深度,请参见 Depth combinations;对于8位输入图像,将导致截断的导数。
@param dx 			//导数x的阶数
@para dy 			//导数y的阶数。
@param ksize 		//扩展的Sobel内核的大小;它必须是1、3、5或7。
@param scale 		//计算出的导数值的可选比例因子;默认情况下,不应用缩放(有关详细信息,请参见#getDerivKernels)。
@param delta 		//在将结果存储在dst中之前将其添加到结果中的可选delta值。
@param borderType	//像素外推方法,请参见#BorderTypes*/

DEMO

int main() {
	cv::namedWindow("src", 0);
	cv::namedWindow("dst", 0);
	cv::Mat src = cv::imread("./img/test1.jpg", 1);
	cv::Mat dst, dst_x, dst_y;
	cv::cvtColor(src, src, cv::COLOR_BGR2GRAY);
	cv::Sobel(src, dst_x, CV_16S, 1, 0, 3);
	cv::Sobel(src, dst_y, CV_16S, 0, 1, 3);
	cv::convertScaleAbs(dst_x, dst_x);
	cv::convertScaleAbs(dst_y, dst_y);
	cv::addWeighted(dst_x, 0.5, dst_y, 0.5, 0, dst);
	cv::imshow("dst_x", dst_x);
	cv::imshow("dst_y", dst_y);
	cv::imshow("src", src);
	cv::imshow("dst", dst);
	cv::waitKey(0);
}

效果

原图:
在这里插入图片描述

x方向边缘检测:
在这里插入图片描述

y方向边缘检测:
在这里插入图片描述

x和y方向边缘检测:
在这里插入图片描述

2.Scharr()

CV_EXPORTS_W void Scharr( InputArray src, OutputArray dst, int ddepth,
                          int dx, int dy, double scale = 1, double delta = 0,
                          int borderType = BORDER_DEFAULT );
@param src 			//输入图像。
@param dst 			//输出与src相同大小和相同通道数的图像。
@param ddepth 		//输出图像深度,请参阅 Depth combinations
@param dx 			//导数x的阶数
@para dy 			//导数y的阶数。
@param scale 		//计算得出的导数值的可选比例因子; 默认情况下,不应用缩放(有关详细信息,请参见#getDerivKernels)。
@param delta 		//在将结果存储到dst之前将其添加到结果中的可选增量值。
@param borderType 	//像素外推方法,请参见#BorderTypes

DEMO

int main() {
	cv::namedWindow("src", 0);
	cv::namedWindow("dst", 0);
	cv::Mat src = cv::imread("./img/test1.jpg", 1);
	cv::Mat dst, dst_x, dst_y;
	cv::cvtColor(src, src, cv::COLOR_BGR2GRAY);
	cv::Scharr(src, dst_x, CV_16S, 1, 0, 3);
	cv::Scharr(src, dst_y, CV_16S, 0, 1, 3);
	cv::convertScaleAbs(dst_x, dst_x);
	cv::convertScaleAbs(dst_y, dst_y);
	cv::addWeighted(dst_x, 0.5, dst_y, 0.5, 0, dst);
	cv::imshow("dst_x", dst_x);
	cv::imshow("dst_y", dst_y);
	cv::imshow("src", src);
	cv::imshow("dst", dst);
	cv::waitKey(0);
}

效果

原图:
在这里插入图片描述

x反向边缘检测:
在这里插入图片描述

y方向边缘检测:
在这里插入图片描述

x和y方向边缘检测:
在这里插入图片描述

3. Laplacian()

注意:Laplacian算子具有各方向同性的特点,能够对任意方向的边缘进行提取,具有无方向性的优点,因此使用Laplacian算子提取边缘不需要分别检测X方向的边缘和Y方向的边缘,只需要一次边缘检测即可。Laplacian算子是一种二阶导数算子,对噪声比较敏感,因此常需要配合高斯滤波一起使用。

CV_EXPORTS_W void Laplacian( InputArray src, OutputArray dst, int ddepth,
                             int ksize = 1, double scale = 1, double delta = 0,
                             int borderType = BORDER_DEFAULT );
/*
@param src 			//源图像。
@param dst 			//与src具有相同大小和相同通道数的目标图像。
@param ddepth 		//所需目标图像的深度。
@param ksize 		//用于计算二阶导数滤波器的孔径大小。 有关详细信息,请参见#getDerivKernels。 大小必须为正数和奇数。
@param scale 		//计算的Laplacian值的可选比例因子。 默认情况下,不应用缩放。 有关详细信息,请参见#getDerivKernels。
@param delta 		//在将结果存储到dst之前将其添加到结果中的可选增量值。
@param borderType 	//像素外推方法,请参见#BorderTypes
*/

DEMO

int main() {
	cv::namedWindow("src", 0);
	cv::namedWindow("dst", 0);
	cv::Mat src = cv::imread("./img/test1.jpg", 1);
	cv::Mat dst, dst_x, dst_y, src_gs;
	cv::cvtColor(src, src, cv::COLOR_BGR2GRAY);
	cv::GaussianBlur(src, src_gs, cv::Size(3, 3), 5, 0);  //高斯滤波
	cv::Laplacian(src_gs, dst, CV_16S, 1, 3);
	cv::convertScaleAbs(dst, dst);
	cv::imshow("src", src);
	cv::imshow("dst", dst);
	cv::waitKey(0);
	cv::imwrite("./img/dst.jpg", dst);
	cv::imwrite("./img/src.jpg", src);
}

效果

原图:
在这里插入图片描述

结果:
在这里插入图片描述

缩放,绝对值,转换为无符号的8位类型 convertScaleAbs

/*函数convertScaleAbs按顺序执行三个操作:缩放,绝对值,转换为无符号的8位类型*/
CV_EXPORTS_W void convertScaleAbs(InputArray src, OutputArray dst,
                                  double alpha = 1, double beta = 0);

Depth combinations

Input depth (src.depth())Output depth (ddepth)
CV_8U-1/CV_16S/CV_32F/CV_64F
CV_16U/CV_16S-1/CV_32F/CV_64F
CV_32F-1/CV_32F/CV_64F
CV_64F-1/CV_64F
  • 6
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值