模糊滤镜总结 GLSL & shadertoy
1.本文介绍内容
- 模糊
- 高斯模糊
- 方框模糊
- 表面模糊
- 径向模糊
- 特殊模糊
2.模糊
模糊效果的主体思路就是用一片区域像素值的平均来代替当前像素值。
1. 高斯模糊
高斯模糊是以二维高斯函数计算出来的系数卷积核来平均一片区域像素值。
一维高斯函数为:
二维高斯函数为:
由于高斯函数的线性可分的性质ρ = 0, σ1=σ2=σ,且取μ1 = μ2 = 0。则二维高斯函数可写作
以3X3卷积核大小为例,(x,y)的取值分别为:
带入σ = 1.5的高斯函数中可以得到3X3卷积核为
经过归一化后(3X3卷积核权重值之和为1)
高斯模糊计算思路一,正常计算:
- 选定好卷积核大小N x N和高斯函数方差σ
- 根据卷积核内部坐标计算卷积核权重值,并归一化
- 对每个像素用该卷积核做加权平均处理,用新像素值赋值原像素值
优化1:利用高斯函数线性可分性质
二维高斯函数可以拆分为两个一维高斯函数计算
利用该性质,我们可以将NxN的卷积核处理分成N1(横)和1N(竖)两次处理
为什么将二维卷积核换成两次一维处理可以优化算法?可以简单分析下,对于一个W x H分辨率大小的图片。
如果用二维卷积核处理每个像素点时需要取纹理N*N次,对于一整张图片来说就是W * H * N^2次
如果有一维处理,每个像素需要取纹理N次,对于一整张图片来说就是W * H * N * 2次
可以看到优化效率还是很高的。特别是如果需要在手机端实现该滤镜,通过该优化方法可以提高一倍的帧率。
优化2:简化卷积核的计算
用二项式分布近似替代高斯函数。以下图的二项式分布数据为例。我们可以提前在程序中准备好数据,当我们要计算3X3的卷积核时,可以选用下标为6的二项式。此时卷积核中的值为
可以将二项式计算结果与高斯函数计算结果做比较,我们可以发现值是非常近似的。且如果选取更底层的二项式数据计算,结果会更加准确。而使用二项式替换高斯函数计算时可以省略幂乘、开方等耗时巨大的计算,可以大幅提高帧率。
优化3:利用线性采样(硬件自动插值)
用1N一维卷积核处理图像时意味着,对于一个像素,我们需要读取N次纹理。由于在GPU线性插值是有硬件自动完成,因此我们可以通过偏移纹理坐标来得到插值后的像素值(用一个像素值包含两种像素值的混和)。因此对于13的卷积可以只取两次纹理,对于1*9的卷积只需取5次纹理。
新权重和新的坐标偏移分别为:
程序样例:
fast Gaussain Blur
左半边是原图,右半边是模糊后的效果。
参考资料
Efficient Gaussian blur with linear sampling 基于线性采样的高效高斯模糊实现(译) 高斯模糊的算法(阮一峰)
2.方框模糊
方框模糊即平均模糊,卷积核内所有像素的权值相等,均为1(未归一化时)。
同理方框模糊也可以利用线性可分和线性采样的优化方法提高效率
程序样例:
Fast Box Blur
左半边是原图,右半边是模糊后的效果。
3.表面模糊
表面模糊的作用是在保留图像边界的情况下对图像进行模糊处理。
思路一:
网上分享的表面模糊公式为:
程序样例:
surface blur 1
左半边是表面模糊后的洗过,右半边是原图。
思路二:
思路一效果较好,但是需要对RGB三个通道分别进行处理,计算量大。如果移植到手机上,效率极差。思路二来自于参考资料中**Fast surface blur 参考,**用边缘检测 + 选择性gaussian模糊 + 混合来近似实现表面模糊效果。
实现表面模糊思路在于如何保留图像边界。首先要确定图像边界,这里我使用的soble算子,其次是保留图像边界,我使用了两种方法:
- 模糊过程中,通过判断卷积核中的像素soble值与卷积核中心像素的soble值的差距是否在一定阈值内,来取舍该像素是否参与模糊。
- 在模糊结果后,在图像边界处,混合边界原始像素与模糊后的像素。
程序样例:
fast Surface blur
左半边是表面模糊后的效果,右半边是原图。
参考资料
**表面模糊公式介绍 Fast surface blur 参考**
4.径向模糊
根据PS中效果可知,径向模糊是以图像中心点为轴心,离中心点越远模糊效果越明显(即模糊半径越大)。且PS中提供旋转和缩放两种径向模糊(即两种不同的模糊方向)
方法:
1.对于模糊半径与距中心点距离相关的特性,我们可以构造一个模糊半径缩放mask。如下图所示,图像中的像素值,记录着当前像素模糊半径的缩放程度。具体来说即,R(真正) = R(全局) * 像素值。
2.旋转和缩放两种模糊方向
缩放径向模糊方向即当前像素点位置与中心点位置的直线方向
旋转径向模糊方向 即当前像素点位置与中心点位置的直线方向的 切线方向
程序样例:
RadialBlur
左边是旋转径向、右边是缩放径向
5.特殊模糊
特殊模糊效果与表面模糊类似。实现思路都是按两步走:
- 图像边缘检测
- 根据图像边缘来选择性的选取模糊像素区域
根据我个人观察(这部分是个人理解),特殊模糊与表面模糊的区别在于,特殊模糊效果更像是颜色值近似的一片像素区域的模糊。表面模糊更强调模糊后边界的清晰程度。
以观察为指导,参照表面模糊思路。特殊模糊的模糊过程与表面模糊类似,区别在于当模糊区域到达图像边缘时,跳出该方向上的模糊(模糊一般从横竖两个方向上进行)。
程序样例
special blur
左边为模糊效果,右边是原图