【OpenCV】邻域滤波:方框、高斯、中值、双边滤波
原文:http://blog.csdn.net/xiaowei_cqu/article/details/7785365
邻域滤波(卷积)
邻域算子值利用给定像素周围像素的值决定此像素的最终输出。如图左边图像与中间图像卷积禅城右边图像。目标图像中绿色的像素由原图像中蓝色标记的像素计算得到。

通用线性邻域滤波是一种常用的邻域算子,输入像素加权得到输出像素:

其中权重核
为“滤波系数”。上面的式子可以简记为:

【方框滤波】
窗口中的像素值平均后输出,核函数为:
代码
void cv::blur( InputArray src, OutputArray dst,
Size ksize, Point anchor, int borderType )
{
boxFilter( src, dst, -, ksize, anchor, true, borderType );
}
而boxFilter函数源码如下:
cv::Ptr<cv::FilterEngine> cv::createBoxFilter( int srcType, int dstType, Size ksize,
Point anchor, bool normalize, int borderType )
{
int sdepth = CV_MAT_DEPTH(srcType);
int cn = CV_MAT_CN(srcType), sumType = CV_64F;
if( sdepth <= CV_32S && (!normalize ||
ksize.width*ksize.height <= (sdepth == CV_8U ? (<<) :
sdepth == CV_16U ? ( << ) : ( << ))) )
sumType = CV_32S;
sumType = CV_MAKETYPE( sumType, cn ); Ptr<BaseRowFilter> rowFilter = getRowSumFilter(srcType, sumType, ksize.width, anchor.x );
Ptr<BaseColumnFilter> columnFilter = getColumnSumFilter(sumType,
dstType, ksize.height, anchor.y, normalize ? ./(ksize.width*ksize.height) : ); return Ptr<FilterEngine>(new FilterEngine(Ptr<BaseFilter>(), rowFilter, columnFilter,
srcType, dstType, sumType, borderType ));
}


blur( src, dst, Size( , ), Point(-,-));
blur( src, dst, Size( , ), Point(-,-));
blur( src, dst, Size( , ), Point(-,-));
blur( src, dst, Size( , ), Point(-,-));
实验结果

【高斯滤波】
常用的零均值离散高斯滤波器函数:

代码
/****************************************************************************************\
Gaussian Blur
\****************************************************************************************/ cv::Mat cv::getGaussianKernel( int n, double sigma, int ktype )
{
const int SMALL_GAUSSIAN_SIZE = ;
static const float small_gaussian_tab[][SMALL_GAUSSIAN_SIZE] =
{
{.f},
{0.25f, 0.5f, 0.25f},
{0.0625f, 0.25f, 0.375f, 0.25f, 0.0625f},
{0.03125f, 0.109375f, 0.21875f, 0.28125f, 0.21875f, 0.109375f, 0.03125f}
}; const float* fixed_kernel = n % == && n <= SMALL_GAUSSIAN_SIZE && sigma <= ?
small_gaussian_tab[n>>] : ; CV_Assert( ktype == CV_32F || ktype == CV_64F );
Mat kernel(n, , ktype);
float* cf = (float*)kernel.data;
double* cd = (double*)kernel.data; double sigmaX = sigma > ? sigma : ((n-)*0.5 - )*0.3 + 0.8;
double scale2X = -0.5/(sigmaX*sigmaX);
double sum = ; int i;
for( i = ; i < n; i++ )
{
double x = i - (n-)*0.5;
double t = fixed_kernel ? (double)fixed_kernel[i] : std::exp(scale2X*x*x);
if( ktype == CV_32F )
{
cf[i] = (float)t;
sum += cf[i];
}
else
{
cd[i] = t;
sum += cd[i];
}
} sum = ./sum;
for( i = ; i < n; i++ )
{
if( ktype == CV_32F )
cf[i] = (float)(cf[i]*sum);
else
cd[i] *= sum;
} return kernel;
} cv::Ptr<cv::FilterEngine> cv::createGaussianFilter( int type, Size ksize,
double sigma1, double sigma2,
int borderType )
{
int depth = CV_MAT_DEPTH(type);
if( sigma2 <= )
sigma2 = sigma1; // automatic detection of kernel size from sigma
if( ksize.width <= && sigma1 > )
ksize.width = cvRound(sigma1*(depth == CV_8U ? : )* + )|;
if( ksize.height <= && sigma2 > )
ksize.height = cvRound(sigma2*(depth == CV_8U ? : )* + )|; CV_Assert( ksize.width > && ksize.width % == &&
ksize.height > && ksize.height % == ); sigma1 = std::max( sigma1, . );
sigma2 = std::max( sigma2, . ); Mat kx = getGaussianKernel( ksize.width, sigma1, std::max(depth, CV_32F) );
Mat ky;
if( ksize.height == ksize.width && std::abs(sigma1 - sigma2) < DBL_EPSILON )
ky = kx;
else
ky = getGaussianKernel( ksize.height, sigma2, std::max(depth, CV_32F) ); return createSeparableLinearFilter( type, type, kx, ky, Point(-,-), , borderType );
} void cv::GaussianBlur( InputArray _src, OutputArray _dst, Size ksize,
double sigma1, double sigma2,
int borderType )
{
Mat src = _src.getMat();
_dst.create( src.size(), src.type() );
Mat dst = _dst.getMat(); if( borderType != BORDER_CONSTANT )
{
if( src.rows == )
ksize.height = ;
if( src.cols == )
ksize.width = ;
} if( ksize.width == && ksize.height == )
{
src.copyTo(dst);
return;
} #ifdef HAVE_TEGRA_OPTIMIZATION
if(sigma1 == && sigma2 == && tegra::gaussian(src, dst, ksize, borderType))
return;
#endif Ptr<FilterEngine> f = createGaussianFilter( src.type(), ksize, sigma1, sigma2, borderType );
f->apply( src, dst );
}
实验结果

非线性滤波
线性滤波易于构造,且易于从频率响应的角度分析,但如果噪声是散粒噪声而非高斯噪声时线性滤波不能去除噪声。如图像突然出现很大的值,线性滤波只是转换为柔和但仍可见的散粒。这时需要非线性滤波。
简单的非线性滤波有 中值滤波,
-截尾均值滤波,定义域滤波 和值域滤波 。

中值滤波选择每个邻域像素的中值输出;
-截尾均值滤波是指去掉百分率为
的最小值和最大值;定义域滤波中沿着边界的数字是像素的距离;值域就是去掉值域外的像素值。
中值滤波代码
medianBlur ( src, dst, i );
中值滤波实验
下图是对一幅图像分别用3*3,5*5,7*7,9*9(这里必须是奇数)标准方框滤波后的图像:

【双边滤波】
双边滤波的思想是抑制与中心像素值差别太大的像素,输出像素值依赖于邻域像素值的加权合:

权重系数 取决于定义域核

和依赖于数据的值域核

的乘积。相乘后会产生依赖于数据的双边权重函数:

双边滤波源码
/****************************************************************************************\
Bilateral Filtering
\****************************************************************************************/ namespace cv
{ static void
bilateralFilter_8u( const Mat& src, Mat& dst, int d,
double sigma_color, double sigma_space,
int borderType )
{
int cn = src.channels();
int i, j, k, maxk, radius;
Size size = src.size(); CV_Assert( (src.type() == CV_8UC1 || src.type() == CV_8UC3) &&
src.type() == dst.type() && src.size() == dst.size() &&
src.data != dst.data ); if( sigma_color <= )
sigma_color = ;
if( sigma_space <= )
sigma_space = ; double gauss_color_coeff = -0.5/(sigma_color*sigma_color);
double gauss_space_coeff = -0.5/(sigma_space*sigma_space); if( d <= )
radius = cvRound(sigma_space*1.5);
else
radius = d/;
radius = MAX(radius, );
d = radius* + ; Mat temp;
copyMakeBorder( src, temp, radius, radius, radius, radius, borderType ); vector<float> _color_weight(cn*);
vector<float> _space_weight(d*d);
vector<int> _space_ofs(d*d);
float* color_weight = &_color_weight[];
float* space_weight = &_space_weight[];
int* space_ofs = &_space_ofs[]; // initialize color-related bilateral filter coefficients
for( i = ; i < *cn; i++ )
color_weight[i] = (float)std::exp(i*i*gauss_color_coeff); // initialize space-related bilateral filter coefficients
for( i = -radius, maxk = ; i <= radius; i++ )
for( j = -radius; j <= radius; j++ )
{
double r = std::sqrt((double)i*i + (double)j*j);
if( r > radius )
continue;
space_weight[maxk] = (float)std::exp(r*r*gauss_space_coeff);
space_ofs[maxk++] = (int)(i*temp.step + j*cn);
} for( i = ; i < size.height; i++ )
{
const uchar* sptr = temp.data + (i+radius)*temp.step + radius*cn;
uchar* dptr = dst.data + i*dst.step; if( cn == )
{
for( j = ; j < size.width; j++ )
{
float sum = , wsum = ;
int val0 = sptr[j];
for( k = ; k < maxk; k++ )
{
int val = sptr[j + space_ofs[k]];
float w = space_weight[k]*color_weight[std::abs(val - val0)];
sum += val*w;
wsum += w;
}
// overflow is not possible here => there is no need to use CV_CAST_8U
dptr[j] = (uchar)cvRound(sum/wsum);
}
}
else
{
assert( cn == );
for( j = ; j < size.width*; j += )
{
float sum_b = , sum_g = , sum_r = , wsum = ;
int b0 = sptr[j], g0 = sptr[j+], r0 = sptr[j+];
for( k = ; k < maxk; k++ )
{
const uchar* sptr_k = sptr + j + space_ofs[k];
int b = sptr_k[], g = sptr_k[], r = sptr_k[];
float w = space_weight[k]*color_weight[std::abs(b - b0) +
std::abs(g - g0) + std::abs(r - r0)];
sum_b += b*w; sum_g += g*w; sum_r += r*w;
wsum += w;
}
wsum = .f/wsum;
b0 = cvRound(sum_b*wsum);
g0 = cvRound(sum_g*wsum);
r0 = cvRound(sum_r*wsum);
dptr[j] = (uchar)b0; dptr[j+] = (uchar)g0; dptr[j+] = (uchar)r0;
}
}
}
}
双边滤波调用
bilateralFilter(InputArray src, OutputArray dst, int d, double sigmaColor, double sigmaSpace,
int borderType=BORDER_DEFAULT );
双边滤波实验
【OpenCV】邻域滤波:方框、高斯、中值、双边滤波的更多相关文章
- opencv-11-中值滤波及自适应中值滤波
开始之前 在上一篇我们实现了读取噪声图像, 然后 进行三种形式的均值滤波得到结果, 由于我们自己写的均值滤波未作边缘处理, 所以效果有一定的下降, 但是总体来说, 我们得到的结果能够说明我们的算法执行 ...
- opencv —— boxFilter、blur、GaussianBlur、medianBlur、bilateralFilter 线性滤波(方框滤波、均值滤波、高斯滤波)与非线性滤波(中值滤波、双边滤波)
图像滤波,指在尽量保留图像细节特征的条件下对目标图像的噪声进行抑制,是图像与处理中不可缺少的操作. 邻域算子,指利用给定像素及其周围的像素值,决定此像素的最终输出值的一种算子.线性邻域滤波器就是一种常 ...
- OpenCV计算机视觉学习(4)——图像平滑处理(均值滤波,高斯滤波,中值滤波,双边滤波)
如果需要处理的原图及代码,请移步小编的GitHub地址 传送门:请点击我 如果点击有误:https://github.com/LeBron-Jian/ComputerVisionPractice &q ...
- 学习 opencv---(8)非线性滤波:中值滤波,双边滤波
正如我们上一篇文章中讲到的,线性滤波可以实现很多种不同的图像变换.然而非线性滤波,如中值滤波器和双边滤波器,有时可以达到更好的实现效果. 邻域算子的其他一些例子还有对 二值图像进行操作的形态学算子,用 ...
- 学习 opencv---(7) 线性邻域滤波专场:方框滤波,均值滤波,高斯滤波
本篇文章中,我们一起仔细探讨了OpenCV图像处理技术中比较热门的图像滤波操作.图像滤波系列文章浅墨准备花两次更新的时间来讲,此为上篇,为大家剖析了"方框滤波","均值滤 ...
- 中值滤波C语言优化
中值滤波C语言优化 图像平滑是图像预处理的基本操作,本文首先用不同的方法对一张图片做预处理比较它们效果的不同,然后针对中值滤波,实现了一种快速实现.(其实是copy的opencv实现,呵呵).因为op ...
- 基于FPGA的中值滤波算法实现
在这一篇开篇之前,我需要解决一个问题,上一篇我们实现了基于FPGA的均值滤波算法的实现,最后的显示效果图上发现有一些黑白色的斑点,我以为是椒盐噪声,然后在做基于FPGA的中值滤波算法的实验时,我发现黑 ...
- PIE SDK中值滤波
1.算法功能简介 中值滤波是一种最常用的非线性平滑滤波器,它将窗口内的所有像素值按高低排序后,取中间值作为中心像素的新值. 中值滤波对噪声有良好的滤除作用,特别是在滤除噪声的同时,能够保护信号的边缘, ...
- 基于记忆性的中值滤波O(r)与O(1)复杂度的算法实现
本文参考博客:https://www.cnblogs.com/Imageshop/archive/2013/04/26/3045672.html 原生的中值滤波是基于排序算法的,这样的算法复杂度基本在 ...
- opencv笔记4:模板运算和常见滤波操作
time:2015年10月04日 星期日 00时00分27秒 # opencv笔记4:模板运算和常见滤波操作 这一篇主要是学习模板运算,了解各种模板运算的运算过程和分类,理论方面主要参考<图像工 ...
随机推荐
- 自己从0开始学习Unity的笔记 IV (C#循环练习-数字猜谜游戏)
想起来现在基础的已经学了不少了,那么这次试一下用while写一个数字猜谜的. Random roll = new Random(); //建立一个骰子 , ); //让骰子在1-100内随机一个数 ; ...
- django drf 自定义jwt用户验证逻辑
新建Backend类 from django.contrib.auth.backends import ModelBackend from django.shortcuts import render ...
- 网卡NAT方式下虚拟机安装FTP服务
在windows8下安装Oracle VM VirtualBox虚拟机,虚拟机中安装的CentOS操作系统,在CentOS中搭建LNMP环境,安装vsftpd服务器,宿主机在phpStorm编程,将代 ...
- 完全卸载mysql数据库教程
转自:https://jingyan.baidu.com/article/f96699bbaa8fc1894f3c1b5a.html 1,控制面板——>所有控制面板项——>程序和功能,卸载 ...
- Python3之urllib模块
简介 urllib是python的一个获取url(Uniform Resource Locators,统一资源定位符),可以用来抓取远程的数据. 常用方法 (1)urlopen urllib.requ ...
- 设计简单登录界面(Java web)
程序设计思想: 在Input.jsp中创建一个表格里边分别是课程名称,任课老师,教学地点,并分别用三个文本框来接受输入的三个属性, 并传到另外的Jsp页面中,又来接受三个数据,并判断传来的教师,与教室 ...
- 何在不联网的情况下ping通主机与虚拟机
选择NAT模式,VM对windows选择ping操作时选择VMnet8的IP地址.
- 基于iTop4412的FM收音机系统设计(三)
说明:第一版架构为:APP+JNI(NDK)+Driver(linux),优点是开发简单,周期短,也作为自己的毕业设计 现在更新第二版,FM服务完全植入Android系统中,成为系统服务,架构为:AP ...
- Q72 编辑距离
给定两个单词 word1 和 word2,计算出将 word1 转换成 word2 所使用的最少操作数 . 你可以对一个单词进行如下三种操作: 插入一个字符 删除一个字符 替换一个字符 示例 1: 输 ...
- HLS:OpenCV和RTL代码转换关系
OpenCV 图像处理是基于存储器帧缓存而构建的, 它总是假设视频帧数据存放在外部 DDR 存储器中. 由于处理器的小容量高速缓存性能的限制, 因此, OpenCV 访问局部图像性能较差. 并且, 从 ...