非线性滤波:中值滤波,双边滤波
线性滤波:两个信号之和的响应和它们各自响应之和相等(即每个像素的输出值是一些输入像素的加权和)。
非线性滤波:
中值滤波:用像素点领域灰度值的中值来代替该像素点的灰度值,该方法在去除脉冲噪声,椒盐噪声的同时又能保留图像的边缘细节。
优点:由于噪声很难选上,所以几乎不会影响到输出,克服线性滤波器所带来的图像细节模糊,对滤波脉冲干扰即图像扫描噪声最为有效。
缺点:中值滤波花费的时间是均值滤波的5倍以上,对细节(细,尖顶)的图形不合适。
双边滤波:结合图像的空间邻近度和像素值相似度的一种折中处理,同时考虑空域信息和灰度相似性,达到保边去噪的目的。
优点:做边缘保存
缺点:保存过多的高频信息,对于彩色图像里的高频噪声,不能干净的滤掉。
相关核心API函数
中值滤波:
声明:
CV_EXPORTS_W void medianBlur( InputArray src, OutputArray dst, int ksize );
定义:
void cv::medianBlur( InputArray _src0, OutputArray _dst, int ksize )
{
CV_Assert( (ksize % 2 == 1) && (_src0.dims() <= 2 ));
if( ksize <= 1 )
{
_src0.copyTo(_dst);
return;
}
CV_OCL_RUN(_dst.isUMat(),
ocl_medianFilter(_src0,_dst, ksize))
Mat src0 = _src0.getMat();
_dst.create( src0.size(), src0.type() );
Mat dst = _dst.getMat();
#if IPP_VERSION_X100 >= 801
CV_IPP_CHECK()
{
#define IPP_FILTER_MEDIAN_BORDER(ippType, ippDataType, flavor) \
do \
{ \
if (ippiFilterMedianBorderGetBufferSize(dstRoiSize, maskSize, \
ippDataType, CV_MAT_CN(type), &bufSize) >= 0) \
{ \
Ipp8u * buffer = ippsMalloc_8u(bufSize); \
IppStatus status = ippiFilterMedianBorder_##flavor(src.ptr<ippType>(), (int)src.step, \
dst.ptr<ippType>(), (int)dst.step, dstRoiSize, maskSize, \
ippBorderRepl, (ippType)0, buffer); \
ippsFree(buffer); \
if (status >= 0) \
{ \
CV_IMPL_ADD(CV_IMPL_IPP); \
return; \
} \
} \
setIppErrorStatus(); \
} \
while ((void)0, 0)
if( ksize <= 5 )
{
Ipp32s bufSize;
IppiSize dstRoiSize = ippiSize(dst.cols, dst.rows), maskSize = ippiSize(ksize, ksize);
Mat src;
if( dst.data != src0.data )
src = src0;
else
src0.copyTo(src);
int type = src0.type();
if (type == CV_8UC1)
IPP_FILTER_MEDIAN_BORDER(Ipp8u, ipp8u, 8u_C1R);
else if (type == CV_16UC1)
IPP_FILTER_MEDIAN_BORDER(Ipp16u, ipp16u, 16u_C1R);
else if (type == CV_16SC1)
IPP_FILTER_MEDIAN_BORDER(Ipp16s, ipp16s, 16s_C1R);
else if (type == CV_32FC1)
IPP_FILTER_MEDIAN_BORDER(Ipp32f, ipp32f, 32f_C1R);
}
#undef IPP_FILTER_MEDIAN_BORDER
}
#endif
#ifdef HAVE_TEGRA_OPTIMIZATION
if (tegra::useTegra() && tegra::medianBlur(src0, dst, ksize))
return;
#endif
bool useSortNet = ksize == 3 || (ksize == 5
#if !(CV_SSE2 || CV_NEON)
&& src0.depth() > CV_8U
#endif
);
Mat src;
if( useSortNet )
{
if( dst.data != src0.data )
src = src0;
else
src0.copyTo(src);
if( src.depth() == CV_8U )
medianBlur_SortNet<MinMax8u, MinMaxVec8u>( src, dst, ksize );
else if( src.depth() == CV_16U )
medianBlur_SortNet<MinMax16u, MinMaxVec16u>( src, dst, ksize );
else if( src.depth() == CV_16S )
medianBlur_SortNet<MinMax16s, MinMaxVec16s>( src, dst, ksize );
else if( src.depth() == CV_32F )
medianBlur_SortNet<MinMax32f, MinMaxVec32f>( src, dst, ksize );
else
CV_Error(CV_StsUnsupportedFormat, "");
return;
}
else
{
cv::copyMakeBorder( src0, src, 0, 0, ksize/2, ksize/2, BORDER_REPLICATE );
int cn = src0.channels();
CV_Assert( src.depth() == CV_8U && (cn == 1 || cn == 3 || cn == 4) );
double img_size_mp = (double)(src0.total())/(1 << 20);
if( ksize <= 3 + (img_size_mp < 1 ? 12 : img_size_mp < 4 ? 6 : 2)*
(MEDIAN_HAVE_SIMD && (checkHardwareSupport(CV_CPU_SSE2) || checkHardwareSupport(CV_CPU_NEON)) ? 1 : 3))
medianBlur_8u_Om( src, dst, ksize );
else
medianBlur_8u_O1( src, dst, ksize );
}
}
双边滤波;
声明:
void cv::bilateralFilter( InputArray _src, OutputArray _dst, int d,
Line 3416: ocl_bilateralFilter_8u(_src, _dst, d, sigmaColor, sigmaSpace, borderType))
定义:
void cv::bilateralFilter( InputArray _src, OutputArray _dst, int d,
double sigmaColor, double sigmaSpace,
int borderType )
{
_dst.create( _src.size(), _src.type() );
CV_OCL_RUN(_src.dims() <= 2 && _dst.isUMat(),
ocl_bilateralFilter_8u(_src, _dst, d, sigmaColor, sigmaSpace, borderType))
Mat src = _src.getMat(), dst = _dst.getMat();
if( src.depth() == CV_8U )
bilateralFilter_8u( src, dst, d, sigmaColor, sigmaSpace, borderType );
else if( src.depth() == CV_32F )
bilateralFilter_32f( src, dst, d, sigmaColor, sigmaSpace, borderType );
else
CV_Error( CV_StsUnsupportedFormat,
"Bilateral filtering is only implemented for 8u and 32f images" );
}