一、概述
使用扩展的 Sobel 算子计算第一、第二、第三或混合图像导数。除一种情况外,在所有情况下,都使用 ksize×ksize 可分离核来计算导数。 当 ksize = 1 时,使用 3×1 或 1×3 内核(即不做高斯平滑)。 ksize = 1 只能用于第一个或第二个 x 或 y 导数。
还有一个特殊的值 ksize = FILTER_SCHARR (-1) 对应于 3×3 Scharr 过滤器,它可能给出比 3×3 Sobel 更准确的结果。 Scharr 算子用于 x 导数,或转置用于 y 导数。
该函数通过将图像与适当的内核卷积来计算图像导数:
Sobel 算子结合了高斯平滑和微分,因此结果或多或少能抵抗噪声。 大多数情况下,使用 (xorder = 1, yorder = 0, ksize = 3) 或 (xorder = 0, yorder = 1, ksize = 3) 调用该函数来计算第一个 x 或 y 图像导数。
第一种情况对应于一个内核:
第二种情况对应于一个内核:
二、Sobel函数
1、函数原型
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)
2、参数详解
src | 输入图像。 |
dst | 输出与 src 大小和通道数相同的图像。 |
ddepth | 输出图像深度,见组合; 在 8 位输入图像的情况下,它将导致截断导数。 |
dx | 导数 x 的阶数。 |
dy | 导数 y 的阶数。 |
ksize | 扩展 Sobel 核的大小; 它必须是 1、3、5 或 7。 |
scale | 计算导数值的可选比例因子; 默认情况下,不应用缩放(有关详细信息,请参阅 getDerivKernels)。 |
delta | 在将结果存储到 dst 之前添加到结果中的可选增量值。 |
borderType | 像素外推法,请参阅 BorderTypes。 不支持 BORDER_WRAP。 |
三、OpenCV源码
1、源码路径
opencv\modules\imgproc\src\deriv.cpp
2、源码代码
void cv::Sobel( InputArray _src, OutputArray _dst, int ddepth, int dx, int dy,
int ksize, double scale, double delta, int borderType )
{
CV_INSTRUMENT_REGION();
CV_Assert(!_src.empty());
int stype = _src.type(), sdepth = CV_MAT_DEPTH(stype), cn = CV_MAT_CN(stype);
if (ddepth < 0)
ddepth = sdepth;
int dtype = CV_MAKE_TYPE(ddepth, cn);
_dst.create( _src.size(), dtype );
int ktype = std::max(CV_32F, std::max(ddepth, sdepth));
Mat kx, ky;
getDerivKernels( kx, ky, dx, dy, ksize, false, ktype );
if( scale != 1 )
{
// usually the smoothing part is the slowest to compute,
// so try to scale it instead of the faster differentiating part
if( dx == 0 )
kx *= scale;
else
ky *= scale;
}
CV_OCL_RUN(ocl::isOpenCLActivated() && _dst.isUMat() && _src.dims() <= 2 && ksize == 3 &&
(size_t)_src.rows() > ky.total() && (size_t)_src.cols() > kx.total(),
ocl_sepFilter3x3_8UC1(_src, _dst, ddepth, kx, ky, delta, borderType));
CV_OCL_RUN(ocl::isOpenCLActivated() && _dst.isUMat() && _src.dims() <= 2 && (size_t)_src.rows() > kx.total() && (size_t)_src.cols() > kx.total(),
ocl_sepFilter2D(_src, _dst, ddepth, kx, ky, Point(-1, -1), delta, borderType))
Mat src = _src.getMat();
Mat dst = _dst.getMat();
Point ofs;
Size wsz(src.cols, src.rows);
if(!(borderType & BORDER_ISOLATED))
src.locateROI( wsz, ofs );
CALL_HAL(sobel, cv_hal_sobel, src.ptr(), src.step, dst.ptr(), dst.step, src.cols, src.rows, sdepth, ddepth, cn,
ofs.x, ofs.y, wsz.width - src.cols - ofs.x, wsz.height - src.rows - ofs.y, dx, dy, ksize, scale, delta, borderType&~BORDER_ISOLATED);
CV_OVX_RUN(true,
openvx_sobel(src, dst, dx, dy, ksize, scale, delta, borderType))
//CV_IPP_RUN_FAST(ipp_Deriv(src, dst, dx, dy, ksize, scale, delta, borderType));
sepFilter2D(src, dst, ddepth, kx, ky, Point(-1, -1), delta, borderType );
}