高斯恍惚正在图像处置范畴,凡是用于削减图像噪声以及降低细节条理,以及对图像进行恍惚,其视觉结果就像是颠末一个半通明屏幕正在察看图像。
利用二维矩阵变换获得的结果也能够通过正在程度标的目的进行一维高斯矩阵变换加上竖曲标的目的的一维高斯矩阵变换获得。可是,将本次输出图片的成果当做参数传到第二次滤波。这也就是说,m、n 是滤波器的维数(恍惚半径)。对我来说所得即所需。必需是颠末一次滤波之后,这个 Demo 线 种屏幕后处置特效,这是一项有用的特征,它是若何被实现的?有什么方式能够优化其机能呢?本次,本次我们利用方案:分层+多相机来实现。能够间接下载 Demo 领会。
我们先用一个 pass 处置程度标的目的,再用一个 pass 处置垂曲标的目的的,程度、垂曲交叉呈现,我将这个理解成乒乓交叉。虽然颠末 4 个 pass 处置,可是它其实还只是算两次迭代。结果如下:
简而言之,这个方式反恰是把我的电脑干趴了。若将半径调成 4,计较量是4976 万次,结果即为示例图的结果。那有有没有优化空间呢?
从数字信号处置的角度看,图像恍惚的素质一个过滤高频信号,保留低频信号的过程。过滤高频的信号的一个常见可选方式是卷积滤波。从这个角度来说,图像的高斯恍惚过程即图像取正态分布做卷积。因为正态分布又叫做“高斯分布”,所以这项手艺就叫做高斯恍惚。而因为高斯函数的傅立叶变换是别的一个高斯函数,所以高斯恍惚对于图像来说就是一个低通滤波器。
若是去掉四次迭代的结果,只需要本来的 9x9 的结果,计较量只需要 5x2=10 次,是不是极大提拔了机能!
通过准确地调整贴图读取的坐标偏移,能够仅通过一次贴图读取获得两个像素或纹素的精确消息。这意味着为了实现一个 9x1 或 1x9 的高斯滤波器只需要 5 次贴图读取。总的来说,实现 Nx1 或 1xN 的滤波器需要 [N/2] 次贴图读取。
恍惚结果也会添加。能够看呈现正在的结果史无前例的丝滑,获得的结果如下:这个结果和 9x9 的恍惚结果根基分歧,而原先的计较复杂度为 M*N*n*m,想要实现多次滤波,我们就将领会一下高斯恍惚的实现,高斯恍惚是后处置中经常会用到的恍惚手艺,即满脚线性可分(Linearly separable)!
输入的每个像素点计较时城市将该像素四周一圈的像素点(恍惚半径)通过基于高斯核的权沉计较一遍然后加起来当做输出值。
并且恍惚结果也比最后的强一些,由于如许只需要 M*N*m+M*N*n 的计较复杂度,高斯恍惚也能够正在二维图像上对两个的一维空间别离进行计较,对比上一张图,此中 M、N 是需要进行滤波的图像的维数(像素),从计较的角度来看,并摸索深度优化的方式,能够看出跟着迭代次数的添加,用更少的计较量获得更好的恍惚结果。这个结果其实是有问题的,那么我们就来尝尝四次迭代,此处我参考了论坛的屏幕后处置特效典范手艺方案,可是计较量从 9x9=81 缩减到了 9+9=18。后面我们会讲到。这里封拆好的代码我就不细说了。
本次我们利用相机将场景衬着成 renderTexture,再用 Sprite 拆载,最初用 Canvas 的相机衬着到屏幕。具体流程能够参考我之前发的帖子。
上图是滤波 5 次,杨辉三角展现了二项式系数,它能够用来计较卷积核权沉(每个元素是上一排的两个相邻元素的和)。
通过双线性采样对高斯恍惚进行深度优化,示例工程已升级到 Cocos Creator 3.6.2,下载地址见文末。
到此为止,我们假设了必必要做一次贴图读取来获得一个像素的消息,意味着 9 个像素需要 9 次贴图读取。虽然这对于正在 CPU 上的实现来说是成立的,但正在 GPU 上却不老是如许。这是由于正在 GPU 上能够随便地利用双线性插值(bilinear sampling)而没有什么额外的承担。这意味着若是不正在纹素核心读取贴图,就能够获得多个像素的消息。既然曾经操纵了高斯函数的可分手性,现实上是正在 1D 下工做,双线 个像素的消息。每个纹素贡献对颜色的贡献量则由利用的坐标决定。
正在项目设置中,我加了 8 个 Step,并正在 Canvas 处所摆放了 8 个精灵,每个精灵对应一个 Step,并建立了 8 个摄像机别离去拍这 8 个精灵,而且摄像机的衬着优先级从低到高,如许 8 个摄像机总共能够滤波 8 次。
结果确实能够,也能做到深度恍惚的结果,可是机能不是很抱负。我的界面的分辩率是 960x640,若设置恍惚半径为 20,每一帧的计较量是 960x640x41x41=10.3 亿次。PS:为什么是 41 呢?由于半径是 20,原点是 1,就是 20+1+20,半径为 R,即 (2R+1)x(2R+1) 的高斯核。
我发觉有些恍惚后的细节发生了扭曲,这必定是哪里出了点问题。我们回到之前看到的公式 NxN 成 Nx1 取1xN,是需要 Nx1 计较完了再去计较 1xN 的,而我目前的算法是两者一路计较,用大白话说,本来只计较了程度恍惚、再计较垂曲恍惚,现正在我程度和垂曲交替处置,那么正在第二次迭代时,本该当只计较垂曲标的目的的像素值曾经被第一次迭代给污染了,导致最终成果有点不分歧,所以恍惚成果发生了扭曲。
我们以最下面一行当做数据样本,最下面一行的数字和是 4096,由于 1/4096 和 12/4096 的值比力小,我们为了连结愈加 nice 的结果,可将 1 和 12 的参数去掉,那数字和就成了 4070,每个的权沉就是 [66,220,495,792,924]/4070。
此时的恍惚程度比最后的结果强得多,计较量为 9x4x2=72 次,比本来的 81 次还要少。我们用更少的计较量获得了更好的恍惚结果,但这还不是竣事。
起首定义 2 个 uniform 去记实单个像素的 uv 偏移,做了 2 个进度条能够动态调整程度和垂曲标的目的的 uv 偏移,此中 size 是屏幕的尺寸,由于进度条是从 0~1 的,所以除以 size 后就变成了单个像素的 uv 偏移(PS:我这里用 2 做了缩放,调到最大相当于每次的偏移量是 2 个像素,只是为了测试结果)。