【VS开发】【图像处理】双边滤波器bilateral filter
1. 简介
图像平滑是一个重要的操作,而且有多种成熟的算法。这里主要简单介绍一下Bilateral方法(双边滤波),这主要是由于前段时间做了SSAO,需要用bilateral blur 算法进行降噪。Bilateral blur相对于传统的高斯blur来说很重要的一个特性即可可以保持边缘(Edge Perseving),这个特点对于一些图像模糊来说很有用。一般的高斯模糊在进行采样时主要考虑了像素间的空间距离关系,但是却并没有考虑像素值之间的相似程度,因此这样我们得到的模糊结果通常是整张图片一团模糊。Bilateral
blur的改进就在于在采样时不仅考虑像素在空间距离上的关系,同时加入了像素间的相似程度考虑,因而可以保持原始图像的大体分块进而保持边缘。在于游戏引擎的post blur算法中,bilateral blur常常被用到,比如对SSAO的降噪。
2. 原理
滤波算法中,目标点上的像素值通常是由其所在位置上的周围的一个小局部邻居像素的值所决定。在2D高斯滤波中的具体实现就是对周围的一定范围内的像素值分别赋以不同的高斯权重值,并在加权平均后得到当前点的最终结果。而这里的高斯权重因子是利用两个像素之间的空间距离(在图像中为2D)关系来生成。通过高斯分布的曲线可以发现,离目标像素越近的点对最终结果的贡献越大,反之则越小。其公式化的描述一般如下所述:
其中的c即为基于空间距离的高斯权重,而用来对结果进行单位化。
高斯滤波在低通滤波算法中有不错的表现,但是其却有另外一个问题,那就是只考虑了像素间的空间位置上的关系,因此滤波的结果会丢失边缘的信息。这里的边缘主要是指图像中主要的不同颜色区域(比如蓝色的天空,黑色的头发等),而Bilateral就是在Gaussian blur中加入了另外的一个权重分部来解决这一问题。Bilateral滤波中对于边缘的保持通过下述表达式来实现:
其中的s为基于像素间相似程度的高斯权重,同样用来对结果进行单位化。对两者进行结合即可以得到基于空间距离、相似程度综合考量的Bilateral滤波:
上式中的单位化分部综合了两种高斯权重于一起而得到,其中的c与s计算可以详细描述如下:
且有
且有
上述给出的表达式均是在空间上的无限积分,而在像素化的图像中当然无法这么做,而且也没必要如此做,因而在使用前需要对其进行离散化。而且也不需要对于每个局部像素从整张图像上进行加权操作,距离超过一定程度的像素实际上对当前的目标像素影响很小,可以忽略的。限定局部子区域后的离散化公就可以简化为如下形式:
上述理论公式就构成了Bilateral滤波实现的基础。为了直观地了解高斯滤波与双边滤波的区别,我们可以从下列图示中看出依据。假设目标源图像为下述左右区域分明的带有噪声的图像(由程序自动生成),蓝色框的中心即为目标像素所在的位置,那么当前像素处所对应的高斯权重与双边权重因子3D可视化后的形状如后边两图所示:
左图为原始的噪声图像;中间为高斯采样的权重;右图为Bilateral采样的权重。从图中可以看出Bilateral加入了相似程度分部以后可以将源图像左侧那些跟当前像素差值过大的点给滤去,这样就很好地保持了边缘。为了更加形象地观察两者间的区别,使用Matlab将该图在两种不同方式下的高度图3D绘制出来,如下:
上述三图从左到右依次为:双边滤波,原始图像,高斯滤波。从高度图中可以明显看出Bilateral和Gaussian两种方法的区别,前者较好地保持了边缘处的梯度,而在高斯滤波中,由于其在边缘处的变化是线性的,因而就使用连累的梯度呈现出渐变的状态,而这表现在图像中的话就是边界的丢失(图像的示例可见于后述)。
3. 代码实现
有了上述理论以后实现Bilateral Filter就比较简单了,其实它也与普通的Gaussian Blur没有太大的区别。这里主要包括3部分的操作: 基于空间距离的权重因子生成;基于相似度的权重因子的生成;最终filter颜色的计算。
3.1 Spatial Weight
这就是通常的Gaussian Blur中使用的计算高斯权重的方法,其主要通过两个pixel之间的距离并使用如下公式计算而来:
其中的就表示两个像素间的距离,比如当前像素与其右边紧邻的一个像素之间的距离我们就可以用来计算,也即两个二维向量{0
, 0}以及{0 , 1}之间的欧氏距离。直接计算一个区域上的高斯权重并单位化后就可以进行高斯模糊了。
3.2 Similarity Weight
与基于距离的高斯权重计算类似,只不过此处不再根据两个pixel之间的空间距离,而是根据其相似程度(或者两个pixel的值之间的距离)。
其中的表示两个像素值之间的距离,可以直接使用其灰度值之间的差值或者RGB向量之间的欧氏距离。
3.3 Color Filtering
有了上述两部分所必需的权重因子之后,那么具体的双边滤波的实现即与普通的高斯滤波无异。主要部分代码如下述:
- UCHAR3 BBColor(int posX , int posY)
- {
- int centerItemIndex = posY * picWidth4 + posX * 3 , neighbourItemIndex;
- int weightIndex;
- double gsAccumWeight = 0;
- double accumColor = 0;
- // 计算各个采样点处的Gaussian权重,包括closeness,similarity
- for(int i = -number ; i <= number ; ++i)
- {
- for(int j = -number ; j <= number ; ++j)
- {
- weightIndex = (i + number) * (number * 2 + 1) + (j + number);
- neighbourItemIndex = min(noiseImageHeight - 1 , max(0 , posY + j * radius)) * picWidth4 +
- min(noiseImageWidth - 1 , max(0 , posX + i * radius)) * 3;
- pCSWeight[weightIndex] = LookupGSWeightTable(pSrcDataBuffer[neighbourItemIndex] , pSrcDataBuffer[centerItemIndex]);
- pCSWeight[weightIndex] = pGSWeight[weightIndex] * pGCWeight[weightIndex];
- gsAccumWeight += pCSWeight[weightIndex];
- }
- }
- // 单位化权重因子
- gsAccumWeight = 1 / gsAccumWeight;
- for(int i = -number ; i <= number ; ++i)
- {
- for(int j = -number ; j <= number ; ++j)
- {
- weightIndex = (i + number) * (number * 2 + 1) + (j + number);
- pCSWeight[weightIndex] *= gsAccumWeight;
- }
- }
- // 计算最终的颜色并返回
- for(int i = -number ; i <= number ; ++i)
- {
- for(int j = -number ; j <= number ; ++j)
- {
- weightIndex = (i + number) * (number * 2 + 1) + (j + number);
- neighbourItemIndex = min(noiseImageHeight - 1 , max(0 , posY + j * radius)) * picWidth4 +
- min(noiseImageWidth - 1 , max(0 , posX + i * radius)) * 3;
- accumColor += pSrcDataBuffer[neighbourItemIndex + 0] * pCSWeight[weightIndex];
- }
- }
- return UCHAR3(accumColor , accumColor , accumColor);
- }
其中的相似度分部的权重s主要根据两个Pixel之间的颜色差值计算面来。对于灰度图而言,这个差值的范围是可以预知的,即[-255, 255],因而为了提高计算的效率我们可以将该部分权重因子预计算生成并存表,在使用时快速查询即可。使用上述实现的算法对几张带有噪声的图像进行滤波后的结果如下所示:
上图从左到右分别为:双边滤波;原始图像;高斯滤波。从图片中可以较为明显地看出两种算法的区别,最直观的感受差别就是使用高斯算法后整张图片都是一团模糊的状态;而双边滤波则可以较好地保持原始图像中的区域信息,看起来仍然嘴是嘴、眼是眼(特别是在第一张美女图像上的效果!看来PS是灰常重要啊~~^o^)。
4. 在SSAO中的使用
在上述实现中的边缘判定函数主要是通过两个像素值之间的差异来决定,这也是我们观察普通图片的一种普遍感知方式。当然,也可以根据使用的需求情况来使用其它的方式判断其它定义下的边缘,比如使用场景的depth或是normal。比如在对SSAO进行滤波时可以直接使用Depth值来行边缘判断。首先,设置一个深度的阈值,在作边缘检测时比较两点间的depth差值,如果差值大于阈值,则认为其属于不同的区域,则此处就应为边界。使用此方法得到的效果可见于下图所示:
高斯滤波
双边滤波
在得到滤波之后的SSAO图像之后,与原始图像进行直接的整合就可以得到最终的渲染效果,如下图所示:
SSAO关闭
SSAO开启
【VS开发】【图像处理】双边滤波器bilateral filter的更多相关文章
- 【C++】双边滤波器(bilateral filter)
Bilateral Filtering for Gray and Color Images 双边滤波器:保留边界的平滑滤波器. 在局部上,就是在灰度值差异不大的区域平滑,在灰度值差异比较大的边界地区保 ...
- Bilateral Filter
最近在看图像风格化的论文的时候,频繁遇到 Bilateral Filter.google 一波后,发现并不是什么不得了的东西,但它的思想却很有借鉴意义. 简介 Bilateral Filter,中文又 ...
- 三维网格去噪算法(bilateral filter)
受图像双边滤波算法的启发,[Fleishman et al. 2003]和[Jones et al. 2003]分别提出了利用双边滤波算法对噪声网格进行光顺去噪的算法,两篇文章都被收录于当年的SIGG ...
- vs2015+opencv3.3.1 实现 c++ 双边滤波器(Bilateral Filter)
#include <opencv2\highgui\highgui.hpp> #include <iostream> #include<vector> using ...
- 卡尔曼滤波器 Kalman Filter (转载)
在学习卡尔曼滤波器之前,首先看看为什么叫“卡尔曼”.跟其他著名的理论(例如傅立叶变换,泰勒级数等等)一样,卡尔曼也是一个人的名字,而跟他们不同的是,他是个现代人! 卡 尔曼全名Rudolf Emil ...
- 记录我第一次在Android开发图像处理算法的经历
大概是四月底的时候.有人加我QQ问我是否做能做一些基于图像皮肤检測的算法, 主要是实现对皮肤六项指标: 1. 水分 2. 有份 3. 痤疮与痘痘 4. 色斑与肤 ...
- 【Java Web开发学习】Servlet、Filter、Listener
[Java Web开发学习]Servlet 转发:https://www.cnblogs.com/yangchongxing/p/9274739.html 1.Servlet package cn.y ...
- [转]计算机视觉之跟踪算法——相关滤波器Correlation Filter
https://blog.csdn.net/victoriaw/article/details/62416759 ASEF相关滤波器: Average of Synthetic Exact Filte ...
- springboot整合web开发(整合servlet、filter、listener、访问静态、文件上传)
整合servlet 1.继承HttpServlet 2.添加@WebServlet注解 @WebServlet(name="FirstServlet",urlPatterns=&q ...
随机推荐
- hivesql之str_to_map函数
str_to_map(字符串参数, 分隔符1, 分隔符2) 使用两个分隔符将文本拆分为键值对. 分隔符1将文本分成K-V对,分隔符2分割每个K-V对.对于分隔符1默认分隔符是 ',',对于分隔符2默认 ...
- 前端js之BOM和DOM操作
目录 引入 BOM操作 window对象 history对象 location对象(重点) 弹出框 定时器 计时器相关 DOM 查找标签 直接查找 间接查找 节点操作 创建节点及添加节点 删除节点 替 ...
- 2019春Python程序设计练习5(0416--0422)
6-1 6-1.使用函数求特殊a串数列和 (30 分) 给定两个均不超过9的正整数a和n,要求编写函数fn(a,n) 求a+aa+aaa++⋯+aa⋯aa(n个a)之和,fn须返回的是数列和 函数 ...
- sql DATEDIFF函数使用
date_part abbreviations year yy, yyyy quarter qq, q month mm, m dayofyear dy, y day dd, d week wk, w ...
- 网页“console”输出图文信息
http://www.monmonkey.com/javascript/jiben2.html 参考以上链接中的转义字符使用. http://www.cnblogs.com/Wayou/p/chrom ...
- python解析字体反爬
爬取一些网站的信息时,偶尔会碰到这样一种情况:网页浏览显示是正常的,用python爬取下来是乱码,F12用开发者模式查看网页源代码也是乱码.这种一般是网站设置了字体反爬 一.58同城 用谷歌浏览器打开 ...
- UE4 使用VaRest的最佳实践
背景介绍: 用Node.js,express,Mongo搭建了一个简单后台,为项目提供REST风格的API服务. 第一个查询是通过Get进行,返回一个json字符串. 在虚幻里使用VaRest来进行访 ...
- 9.Python关键字(保留字)一览表
保留字是 Python 语言中一些已经被赋予特定意义的单词,这就要求开发者在开发程序时,不能用这些保留字作为标识符给变量.函数.类.模板以及其他对象命名. Python 包含的保留字可以执行如下命令进 ...
- JavaWeb_(SSH论坛)_五、帖子模块
基于SSH框架的小型论坛项目 一.项目入门 传送门 二.框架整合 传送门 三.用户模块 传送门 四.页面显示 传送门 五.帖子模块 传送门 六.点赞模块 传送门 七.辅助模块 传送门 回复帖子 分析回 ...
- C++入门经典-例5.19-指针的引用与传递参数
1:引用传递参数与指针传递参数能达到同样的目的.指针传递参数也属于一种值传递,其传递的是指针变量的副本.如果使用指针的引用,就可以达到在函数体内改变指针地址的目的.运行代码如下: // 5.19.cp ...