Sobel算子是高斯平滑加微分运算的联合运算,因此它更抗噪声。你可以指定要采用的导数方向,垂直或水平(分别通过参数yorder和xorder)。你还可以通过参数ksize指定内核的大小。如果ksize = -1,则使用3x3 Scharr滤波器,比3x3 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=⎣⎡−1−2−1000121⎦⎤
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=⎣⎡−101−202−101⎦⎤
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=⎣⎡−3−10−30003103⎦⎤
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=⎣⎡−303−10010−303⎦⎤
和Sobel算子相比,scharr算子临近像素的权重更大,所以精确度更高,能计算出更小的梯度变化
如果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=∂x2∂2src+∂y2∂2src
如果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=⎣⎡0101−41010⎦⎤
注意:当输出数据类型为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*/
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);
}
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
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);
}
注意: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
*/
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);
}
/*函数convertScaleAbs按顺序执行三个操作:缩放,绝对值,转换为无符号的8位类型*/
CV_EXPORTS_W void convertScaleAbs(InputArray src, OutputArray dst,
double alpha = 1, double beta = 0);
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 |