一、概述
该函数对图像应用可分离的线性滤波器。也就是说,首先,每一行 src 都用一维内核 kernelX 过滤。 然后,结果的每一列都用一维内核 kernelY 过滤。 由 delta 移位的最终结果存储在 dst 中。
假设图像大小正在通过一个大小可分离的过滤器. 图像本身是不可分离的。如果使用直接卷积方法计算结果而不利用滤波器的可分离性,这将需要大约乘法和加法。如果考虑到过滤器的可分离性,过滤可以分两步进行。第一步将有乘法和加法,第二步将有, 总共有或者乘法和加法。下图给出了直接卷积和可分离卷积的计算复杂度比较:
二、sepFilter2D函数
1、函数原型
cv::sepFilter2D (InputArray src, OutputArray dst, int ddepth, InputArray kernelX, InputArray kernelY, Point anchor=Point(-1,-1), double delta=0, int borderType=BORDER_DEFAULT)
2、参数详解
src | 源图像。 |
dst | 与 src 大小和通道数相同的目标图像。 |
ddepth | 目标图像深度,请参阅组合 |
kernelX | 过滤每一行的系数。 |
kernelY | 过滤每一列的系数。 |
anchor | 内核中的锚点位置。 默认值 (-1,-1) 表示锚点位于内核中心。 |
delta | 在存储过滤结果之前添加到过滤结果中的值。 |
borderType | 像素外推法,请参阅 BorderTypes。 不支持 BORDER_WRAP。 |
三、OpenCV源码
1、源码路径
opencv\modules\imgproc\src\filter.dispatch.cpp
2、源码代码
void sepFilter2D(InputArray _src, OutputArray _dst, int ddepth,
InputArray _kernelX, InputArray _kernelY, Point anchor,
double delta, int borderType)
{
CV_INSTRUMENT_REGION();
CV_Assert(!_src.empty());
CV_Assert(!_kernelX.empty());
CV_Assert(!_kernelY.empty());
CV_OCL_RUN(_dst.isUMat() && _src.dims() <= 2 && (size_t)_src.rows() >= _kernelY.total() && (size_t)_src.cols() >= _kernelX.total(),
ocl_sepFilter2D(_src, _dst, ddepth, _kernelX, _kernelY, anchor, delta, borderType))
Mat src = _src.getMat(), kernelX = _kernelX.getMat(), kernelY = _kernelY.getMat();
if( ddepth < 0 )
ddepth = src.depth();
_dst.create( src.size(), CV_MAKETYPE(ddepth, src.channels()) );
Mat dst = _dst.getMat();
Point ofs;
Size wsz(src.cols, src.rows);
if( (borderType & BORDER_ISOLATED) == 0 )
src.locateROI( wsz, ofs );
CV_Assert( kernelX.type() == kernelY.type() &&
(kernelX.cols == 1 || kernelX.rows == 1) &&
(kernelY.cols == 1 || kernelY.rows == 1) );
Mat contKernelX = kernelX.isContinuous() ? kernelX : kernelX.clone();
Mat contKernelY = kernelY.isContinuous() ? kernelY : kernelY.clone();
hal::sepFilter2D(src.type(), dst.type(), kernelX.type(),
src.data, src.step, dst.data, dst.step,
dst.cols, dst.rows, wsz.width, wsz.height, ofs.x, ofs.y,
contKernelX.data, kernelX.cols + kernelX.rows - 1,
contKernelY.data, kernelY.cols + kernelY.rows - 1,
anchor.x, anchor.y, delta, borderType & ~BORDER_ISOLATED);
}