-
filter2D函数
/** @brief Convolves an image with the kernel. 核与图像的卷积操作,这里并不是真正意义上的卷积操作,而是自相关操作
如果想要实现真正的卷积操作,需要将核翻转,并且设置锚点为kernel.cols-anchaor.x-1,kernel.rows-anchor.y-1
The function applies an arbitrary linear filter to an image. In-place operation is supported. When
the aperture is partially outside the image, the function interpolates outlier pixel values
according to the specified border mode.
函数应用任意的线性滤波器对一幅图像滤波,支持原像素上操作,当核的范围部分超出了图像的范围,方程根据指定的方法进行插值
The function does actually compute correlation, not the convolution:
\f[\texttt{dst} (x,y) = \sum _{ \stackrel{0\leq x' < \texttt{kernel.cols},}{0\leq y' < \texttt{kernel.rows}} } \texttt{kernel} (x',y')* \texttt{src} (x+x'- \texttt{anchor.x} ,y+y'- \texttt{anchor.y} )\f]
That is, the kernel is not mirrored around the anchor point. If you need a real convolution, flip
the kernel using #flip and set the new anchor to `(kernel.cols - anchor.x - 1, kernel.rows -
anchor.y - 1)`.
如果卷积核特别大,11*11,或者更大,函数将使用基于离散傅里叶变换的算法,
The function uses the DFT-based algorithm in case of sufficiently large kernels (~`11 x 11` or
larger) and the direct algorithm for small kernels.
@param src input image.图像输入
@param dst output image of the same size and the same number of channels as src.
@param ddepth desired depth of the destination image, see @ref filter_depths "combinations"
@param kernel convolution kernel (or rather a correlation kernel), a single-channel floating point
matrix; if you want to apply different kernels to different channels, split the image into
separate color planes using split and process them individually.
@param anchor anchor of the kernel that indicates the relative position of a filtered point within
the kernel; the anchor should lie within the kernel; default value (-1,-1) means that the anchor
is at the kernel center.
@param delta optional value added to the filtered pixels before storing them in dst.
@param borderType pixel extrapolation method, see #BorderTypes
@sa sepFilter2D, dft, matchTemplate
*/
CV_EXPORTS_W void filter2D( InputArray src, OutputArray dst, int ddepth,
InputArray kernel, Point anchor = Point(-1,-1),
double delta = 0, int borderType = BORDER_DEFAULT );
void cv::filter2D( InputArray _src, OutputArray _dst, int ddepth,
InputArray _kernel, Point anchor0,
double delta, int borderType )
{
CV_INSTRUMENT_REGION()
CV_OCL_RUN(_dst.isUMat() && _src.dims() <= 2,
ocl_filter2D(_src, _dst, ddepth, _kernel, anchor0, delta, borderType))
Mat src = _src.getMat(), kernel = _kernel.getMat();
if( ddepth < 0 )
ddepth = src.depth();
_dst.create( src.size(), CV_MAKETYPE(ddepth, src.channels()) );
Mat dst = _dst.getMat();
Point anchor = normalizeAnchor(anchor0, kernel.size());//规范化锚
Point ofs;
Size wsz(src.cols, src.rows);
if( (borderType & BORDER_ISOLATED) == 0 )
src.locateROI( wsz, ofs );//确定父图像大小,和该图像在父图像的偏移
//调用hal::filter2D hal表示案件,这个函数类型是控制流走向函数,通过这个函数决定由何种实现进行滤波
hal::filter2D(src.type(), dst.type(), kernel.type(),
src.data, src.step, dst.data, dst.step,
dst.cols, dst.rows, wsz.width, wsz.height, ofs.x, ofs.y,
kernel.data, kernel.step, kernel.cols, kernel.rows,
anchor.x, anchor.y,
delta, borderType, src.isSubmatrix());
}
-
hal::filter2D
void filter2D(int stype, int dtype, int kernel_type,
uchar * src_data, size_t src_step,
uchar * dst_data, size_t dst_step,
int width, int height,
int full_width, int full_height,
int offset_x, int offset_y,
uchar * kernel_data, size_t kernel_step,
int kernel_width, int kernel_height,
int anchor_x, int anchor_y,
double delta, int borderType,
bool isSubmatrix)
{//函数主要做的就是控制由哪个实现进行操作,replacementFilter2D表示用户按照opencv要求自定义的实
//现,dftFilter2D表示采用基于离散傅里叶的算法,ocvFilter2D表示普通的算法,一般用户定义了自己的
//实现算法,则按照自己的算法来计算,接着就是看,进入傅里叶算法,最后到平时用的普通算法
bool res;
res = replacementFilter2D(stype, dtype, kernel_type,
src_data, src_step,
dst_data, dst_step,
width, height,
full_width, full_height,
offset_x, offset_y,
kernel_data, kernel_step,
kernel_width, kernel_height,
anchor_x, anchor_y,
delta, borderType, isSubmatrix);
if (res)
return;
CV_IPP_RUN_FAST(ippFilter2D(stype, dtype, kernel_type,
src_data, src_step,
dst_data, dst_step,
width, height,
full_width, full_height,
offset_x, offset_y,
kernel_data, kernel_step,
kernel_width, kernel_height,
anchor_x, anchor_y,
delta, borderType, isSubmatrix))
res = dftFilter2D(stype, dtype, kernel_type,
src_data, src_step,
dst_data, dst_step,
full_width, full_height,
offset_x, offset_y,
kernel_data, kernel_step,
kernel_width, kernel_height,
anchor_x, anchor_y,
delta, borderType);
if (res)
return;
ocvFilter2D(stype, dtype, kernel_type,
src_data, src_step,
dst_data, dst_step,
width, height,
full_width, full_height,
offset_x, offset_y,
kernel_data, kernel_step,
kernel_width, kernel_height,
anchor_x, anchor_y,
delta, borderType);
}
static void ocvFilter2D(int stype, int dtype, int kernel_type,
uchar * src_data, size_t src_step,
uchar * dst_data, size_t dst_step,
int width, int height,
int full_width, int full_height,
int offset_x, int offset_y,
uchar * kernel_data, size_t kernel_step,
int kernel_width, int kernel_height,
int anchor_x, int anchor_y,
double delta, int borderType)
{
int borderTypeValue = borderType & ~BORDER_ISOLATED;//边界类型
Mat kernel = Mat(Size(kernel_width, kernel_height), kernel_type, kernel_data, kernel_step);
Ptr<FilterEngine> f = createLinearFilter(stype, dtype, kernel, Point(anchor_x, anchor_y), delta,
borderTypeValue);//创建线性滤波器,并返回滤波器引擎
Mat src(Size(width, height), stype, src_data, src_step);
Mat dst(Size(width, height), dtype, dst_data, dst_step);
f->apply(src, dst, Size(full_width, full_height), Point(offset_x, offset_y));//调用滤波器引擎调用滤波器滤波
}
这里涉及到的滤波器引擎,参考:https://blog.csdn.net/u014676657/article/details/82970932
cv::Ptr<cv::FilterEngine> cv::createLinearFilter( int _srcType, int _dstType,
InputArray filter_kernel,
Point _anchor, double _delta,
int _rowBorderType, int _columnBorderType,
const Scalar& _borderValue )
{
Mat _kernel = filter_kernel.getMat();
_srcType = CV_MAT_TYPE(_srcType);
_dstType = CV_MAT_TYPE(_dstType);
int cn = CV_MAT_CN(_srcType);
CV_Assert( cn == CV_MAT_CN(_dstType) );
Mat kernel = _kernel;
int bits = 0;
/*int sdepth = CV_MAT_DEPTH(_srcType), ddepth = CV_MAT_DEPTH(_dstType);
int ktype = _kernel.depth() == CV_32S ? KERNEL_INTEGER : getKernelType(_kernel, _anchor);
if( sdepth == CV_8U && (ddepth == CV_8U || ddepth == CV_16S) &&
_kernel.rows*_kernel.cols <= (1 << 10) )
{
bits = (ktype & KERNEL_INTEGER) ? 0 : 11;
_kernel.convertTo(kernel, CV_32S, 1 << bits);
}*/
Ptr<BaseFilter> _filter2D = getLinearFilter(_srcType, _dstType,
kernel, _anchor, _delta, bits); //获取线性滤波器
//初始化滤波器引擎,并返回
return makePtr<FilterEngine>(_filter2D, Ptr<BaseRowFilter>(),
Ptr<BaseColumnFilter>(), _srcType, _dstType, _srcType,
_rowBorderType, _columnBorderType, _borderValue );
}
下面用的线性滤波器参考: https://blog.csdn.net/u014676657/article/details/83022756
cv::Ptr<cv::BaseFilter> cv::getLinearFilter(int srcType, int dstType,
InputArray filter_kernel, Point anchor,
double delta, int bits)
{
Mat _kernel = filter_kernel.getMat();
int sdepth = CV_MAT_DEPTH(srcType), ddepth = CV_MAT_DEPTH(dstType);
int cn = CV_MAT_CN(srcType), kdepth = _kernel.depth();
CV_Assert( cn == CV_MAT_CN(dstType) && ddepth >= sdepth );
anchor = normalizeAnchor(anchor, _kernel.size());//规范化锚
/*if( sdepth == CV_8U && ddepth == CV_8U && kdepth == CV_32S )
return makePtr<Filter2D<uchar, FixedPtCastEx<int, uchar>, FilterVec_8u> >
(_kernel, anchor, delta, FixedPtCastEx<int, uchar>(bits),
FilterVec_8u(_kernel, bits, delta));
if( sdepth == CV_8U && ddepth == CV_16S && kdepth == CV_32S )
return makePtr<Filter2D<uchar, FixedPtCastEx<int, short>, FilterVec_8u16s> >
(_kernel, anchor, delta, FixedPtCastEx<int, short>(bits),
FilterVec_8u16s(_kernel, bits, delta));*/
kdepth = sdepth == CV_64F || ddepth == CV_64F ? CV_64F : CV_32F;
Mat kernel;
if( _kernel.type() == kdepth )
kernel = _kernel;
else
_kernel.convertTo(kernel, kdepth, _kernel.type() == CV_32S ? 1./(1 << bits) : 1.);
if( sdepth == CV_8U && ddepth == CV_8U )
return makePtr<Filter2D<uchar, Cast<float, uchar>, FilterVec_8u> >
(kernel, anchor, delta, Cast<float, uchar>(), FilterVec_8u(kernel, 0, delta));
if( sdepth == CV_8U && ddepth == CV_16U )
return makePtr<Filter2D<uchar,
Cast<float, ushort>, FilterNoVec> >(kernel, anchor, delta);
if( sdepth == CV_8U && ddepth == CV_16S )
return makePtr<Filter2D<uchar, Cast<float, short>, FilterVec_8u16s> >
(kernel, anchor, delta, Cast<float, short>(), FilterVec_8u16s(kernel, 0, delta));
if( sdepth == CV_8U && ddepth == CV_32F )
return makePtr<Filter2D<uchar,
Cast<float, float>, FilterNoVec> >(kernel, anchor, delta);
if( sdepth == CV_8U && ddepth == CV_64F )
return makePtr<Filter2D<uchar,
Cast<double, double>, FilterNoVec> >(kernel, anchor, delta);
if( sdepth == CV_16U && ddepth == CV_16U )
return makePtr<Filter2D<ushort,
Cast<float, ushort>, FilterNoVec> >(kernel, anchor, delta);
if( sdepth == CV_16U && ddepth == CV_32F )
return makePtr<Filter2D<ushort,
Cast<float, float>, FilterNoVec> >(kernel, anchor, delta);
if( sdepth == CV_16U && ddepth == CV_64F )
return makePtr<Filter2D<ushort,
Cast<double, double>, FilterNoVec> >(kernel, anchor, delta);
if( sdepth == CV_16S && ddepth == CV_16S )
return makePtr<Filter2D<short,
Cast<float, short>, FilterNoVec> >(kernel, anchor, delta);
if( sdepth == CV_16S && ddepth == CV_32F )
return makePtr<Filter2D<short,
Cast<float, float>, FilterNoVec> >(kernel, anchor, delta);
if( sdepth == CV_16S && ddepth == CV_64F )
return makePtr<Filter2D<short,
Cast<double, double>, FilterNoVec> >(kernel, anchor, delta);
if( sdepth == CV_32F && ddepth == CV_32F )
return makePtr<Filter2D<float, Cast<float, float>, FilterVec_32f> >
(kernel, anchor, delta, Cast<float, float>(), FilterVec_32f(kernel, 0, delta));
if( sdepth == CV_64F && ddepth == CV_64F )
return makePtr<Filter2D<double,
Cast<double, double>, FilterNoVec> >(kernel, anchor, delta);
CV_Error_( CV_StsNotImplemented,
("Unsupported combination of source format (=%d), and destination format (=%d)",
srcType, dstType));
}