GLSL-一遍高斯模糊


18

可以实现片段着色器进行一次高斯模糊吗?我发现很多两遍模糊(高斯和盒子模糊)的实现:

等等。

我一直在考虑将高斯模糊实现为卷积(实际上是卷积,上面的示例只是近似):

http://en.wikipedia.org/wiki/Gaussian_blur

Answers:


33

是的,您可以通过对内核中的所有n ^ 2像素进行采样(对于内核宽度n)来一次实现高斯模糊。通常,通过两遍在行和列上运行它会更快,因为那样您就可以采样O(n)个像素而不是O(n ^ 2)。这不是近似值,因为高斯模糊在数学上是可分离的。


1
这是一个不错的,灵活的单遍模糊着色器:shadertoy.com/view/XdfGDH
Ray

7

使用GLSL快速进行高斯模糊的技巧是利用GPU在硬件中提供线性插值这一事实。因此,您可以使用一个预取或八个3D体素有效地采样四个2D像素。通过确定采样位置,可以对输出进行加权。权威参考文献是Sigg和Hadwiger的“快速三阶纹理过滤”,您可以在网上找到它。

有关可读性的说明,请找到网页“线性采样的高效高斯模糊”。如前所述,由于高斯模糊与宽内核是可分离的,因此每维执行一次通过是最有效的。

但是,您也可以使用此技巧在一次通过中逼近具有紧密核的高斯。在下面的示例中,我模拟了顶部切片= [1 2 1; 2 4 2; 1 2 1]; 中间片= [2 4 2; 4 8 4; 2 4 2]; 底部切片= [1 2 1; 2 4 2; 1 2 1]。通过在每个维度上采样+/- 0.5体素,您只需进行8次纹理获取即可完成此操作,而不是27次。我在GLSL中以MRIcroGL着色器文件演示了这一点-只需将以下脚本保存为“ a.txt”并将其放入MRIcroGL的“ Shader”文件夹。重新启动该程序时,您将看到光线投射图像模糊。单击“ doBlur”复选框,可以打开和关闭模糊。在笔记本电脑和“ chris_t1”中使用集成的英特尔GPU MRIcroGL随附的图像我得到了70 fps(不模糊)(1个纹理获取)和21fps(不模糊)(8个获取)。大多数代码只是经典的ray caster,“ doBlur”条件封装了您的问题。

//-------a.txt文件如下

//pref
doBlur|bool|true
//vert
void main() {
    gl_TexCoord[1] = gl_MultiTexCoord1;
    gl_Position = ftransform();
}
//frag
uniform int loops;
uniform float stepSize, sliceSize, viewWidth, viewHeight;
uniform sampler3D intensityVol;
uniform sampler2D backFace;
uniform vec3 clearColor;
uniform bool doBlur;
void main() {
    // get normalized pixel coordinate in view port (e.g. [0,1]x[0,1])
    vec2 pixelCoord = gl_FragCoord.st;
    pixelCoord.x /= viewWidth;
    pixelCoord.y /= viewHeight; 
    // starting position of the ray is stored in the texture coordinate
    vec3 start = gl_TexCoord[1].xyz;
    vec3 backPosition = texture2D(backFace,pixelCoord).xyz;
    vec3 dir = backPosition - start;
    float len = length(dir);
    dir = normalize(dir);
    vec3 deltaDir = dir * stepSize;
    vec4 colorSample,colAcc = vec4(0.0,0.0,0.0,0.0);
    float lengthAcc = 0.0;
    float opacityCorrection = stepSize/sliceSize;
    //ray dithering http://marcusbannerman.co.uk/index.php/home/42-articles/97-vol-render-optimizations.html
    vec3 samplePos = start.xyz + deltaDir* (fract(sin(gl_FragCoord.x * 12.9898 + gl_FragCoord.y * 78.233) * 43758.5453));
    //offset to eight locations surround target: permute top/bottom, anterior/posterior, left/right
    float dx = 0.5; //distance from target voxel
    vec3 vTAR = vec3( dx, dx, dx)*sliceSize;
    vec3 vTAL = vec3( dx, dx,-dx)*sliceSize;
    vec3 vTPR = vec3( dx,-dx, dx)*sliceSize;
    vec3 vTPL = vec3( dx,-dx,-dx)*sliceSize;
    vec3 vBAR = vec3(-dx, dx, dx)*sliceSize;
    vec3 vBAL = vec3(-dx, dx,-dx)*sliceSize;
    vec3 vBPR = vec3(-dx,-dx, dx)*sliceSize;
    vec3 vBPL = vec3(-dx,-dx,-dx)*sliceSize;
    for(int i = 0; i < loops; i++) {
        if (doBlur) {
            colorSample = texture3D(intensityVol,samplePos+vTAR);
            colorSample += texture3D(intensityVol,samplePos+vTAL);
            colorSample += texture3D(intensityVol,samplePos+vTPR);
            colorSample += texture3D(intensityVol,samplePos+vTPL);
            colorSample += texture3D(intensityVol,samplePos+vBAR);
            colorSample += texture3D(intensityVol,samplePos+vBAL);
            colorSample += texture3D(intensityVol,samplePos+vBPR);
            colorSample += texture3D(intensityVol,samplePos+vBPL);
            colorSample *= 0.125; //average of 8 sample locations
        } else
            colorSample = texture3D(intensityVol,samplePos);
        colorSample.a = 1.0-pow((1.0 - colorSample.a), opacityCorrection);      
        colorSample.rgb *= colorSample.a; 
        //accumulate color
        colAcc = (1.0 - colAcc.a) * colorSample + colAcc;
        samplePos += deltaDir;
        lengthAcc += stepSize;
        // terminate if opacity > 95% or the ray is outside the volume
        if ( lengthAcc >= len || colAcc.a > 0.95 ) break;
    }
    colAcc.rgb = mix(clearColor,colAcc.rgb,colAcc.a);
    gl_FragColor = colAcc;
}

2
丹尼尔·拉科斯(DanielRákos)进行线性采样高效高斯模糊算法(另请注意克里斯蒂安·坎·舒尔德·詹森(Christian Cann Schuldt Jensen)的评论)。
Benji XVI
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.