【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:模板运算和常见滤波操作 这一篇主要是学习模板运算,了解各种模板运算的运算过程和分类,理论方面主要参考<图像工 ...
随机推荐
- UWP开发砸手机系列(一)—— Accessibility
因为今天讨论的内容不属于入门系列,所以我把标题都改了.这个啥Accessibility说实话属于及其蛋疼的内容,即如何让视力有障碍的人也能通过声音来使用触屏手机……也许你这辈子也不会接触,但如果有一天 ...
- dynamic的一些使用心得
dynamic关键字才出来的时候,觉得真是没什么用,谁总是和com交互来交互去啊,唯恐避之不及啊. 后来逐渐算是有了一些使用心得,发现这货还真是犀利啊,故在此举几个例子,起抛砖引玉之用. 1.替代XX ...
- 使用ubuntu搭建时间机器备份服务
如何在ubuntu下搭建时间备份服务 折腾了很久,终于可以了. 请严格按照下面的方式来操作. 真正明白问题的,可以按照自己的思路来. 我用的是ubnutu 16.04 安装配置netatalk sud ...
- Gogland使用 - 非常简单查看Go语言源代码全貌!
Go语言也支持面向对象开发,不过和以往我们所使用的面向对象开发还是有不同,Go语言主张组合方式形成类的概念,在Go语言中,结构起到很大作用,如果用结构组合字段和方法,那么单纯在源代码中看,真的是费时费 ...
- HDP Spark2 HIVE3.1 的问题
HDP 上安装了 Hive3.1 和 Spark2, 提交 Spark 作业时,报找不到 Hive 中表的问题 但是查一了下 hive 表,明明是存在这个表的.查看日志,注意到如下的一段日志. 没修改 ...
- CodeChef April Challenge 2019题解
传送门 \(Maximum\ Remaining\) 对于两个数\(a,b\),如果\(a=b\)没贡献,所以不妨假设\(a<b\),有\(a\%b=a\),而\(b\%a<a\).综上, ...
- Mac下安装HomeBrew
本文章为菲利克斯猫(Felix.mao)原创,转载务必在明显处注明:原文链接:http://blog.csdn.net/maojudong/article/details/7918291 1. 前言 ...
- jmeter+ant+jenkins+mac报告优化(二):添加90% Line和QPS
一.优化内容 1.Summary中只标红Failures数 2.Pages页面按Average Time倒序排序 3.Average Time超过2s标黄显示 4.Pagelist 模块中针对错误和超 ...
- java后台简单从阿里云上传下载文件并通知前端以附件的形式保存
一. 首先开通阿里的OSS 服务 创建一个存储空间在新建一个Bucket 在你新建的bucket有所需的id和key 获取外网访问地址或者是内网 看个人需求 我使用的是外网(内网没用过 估计是部署到阿 ...
- 架构师养成记--18.NIO
有人叫new IO 我这里就叫Non-block IO 经典概念: Buffer(缓冲区):之前直接通过流,现在提供一个buffer存放数据. Channel:管道,包括ServerSocketCha ...