在片段着色器中计算2D高斯滤波器 [英] Calculating 2D Gaussian filter in Fragment Shader

查看:59
本文介绍了在片段着色器中计算2D高斯滤波器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想计算2D高斯函数,输入为X,Y纹理UV坐标并获得相应的高斯值.

在获得相应的Texel的uv高斯值方面,我面临着困难.

  float Gaussian2D(float x,float y){浮点数x_y_squared = x * x + y * y;float stDevSquared = 2 * _2D_StandardDeviation * _2D_StandardDeviation;float div = x_y_squared/stDevSquared;浮点高斯= pow(E,-div);高斯}浮点高斯(int偏移量){float stDevSquared = _StandardDeviation * _StandardDeviation;浮点高斯=(1/sqrt(2 * PI * stDevSquared))* pow(E,-((offset * offset)/(2 * stDevSquared))));高斯}fixed4 frag(v2f i):SV_Target{固定来源= tex2D(_MainTex,i.uv).r;浮点g0 =高斯(0);浮点g1 =高斯(1);浮点g2 =高斯(2);浮点数g3 =高斯(3);浮点数g4 =高斯(4);浮点数g5 =高斯(5);浮点欧米茄= g0 + g1 + g2 + g3 + g4 + g5;浮点高斯= Gaussian2D(i.uv.x,i.uv.y);固定prev_a = tex2D(_HistoryA,i.uv).r;固定的prev_b = tex2D(_HistoryB,i.uv).r;固定的prev_c = tex2D(_HistoryC,i.uv).r;固定prev_d = tex2D(_HistoryD,i.uv).r;固定的prev_e = tex2D(_HistoryE,i.uv).r;固定电流=(gauss * source * g0 + gauss * prev_a * g1 + gauss * prev_b * g2 + gauss * prev_c * g3 + gauss * prev_d * g4 + gauss * prev_e * g5)/(Ω);float diff =源-prev_a;如果(diff< = _dataDelta){返回电流}返回来源;}ENDCG} 

更新Spektre的惊人作品

  sampler2D _MainTex;sampler2D _HistoryA;sampler2D _HistoryB;sampler2D _HistoryC;sampler2D _HistoryD;float4 _MainTex_TexelSize;float _dataDelta;float _blurRadius;float _stepsDelta;float _resolution;float4 _MainTex_ST;float _StandardDeviation;#define E 2.71828182846#define PI 3.14159265359v2f vert(appdata v){v2f o;o.vertex = UnityObjectToClipPos(v.vertex);o.uv = v.uv;返回o;}浮点高斯(int偏移量){float stDevSquared = _StandardDeviation * _StandardDeviation;浮点高斯=(1/sqrt(2 * PI * stDevSquared))* pow(E,-((offset * offset)/(2 * stDevSquared))));高斯}浮点blur2d_horizo​​ntal(sampler2D tex,v2f i,浮点hstep,浮点vstep){float2 uv = i.uv;浮点数= 0;float2 tc = uv;//模糊半径(以像素为单位)浮点模糊= _blurRadius/_resolution/4;sum + = tex2D(tex,float2(tc.x-4.0 *模糊* hstep,tc.y-4.0 *模糊* vstep)).r * 0.0162162162;sum + = tex2D(tex,float2(tc.x-3.0 *模糊* hstep,tc.y-3.0 *模糊* vstep)).r * 0.0540540541;sum + = tex2D(tex,float2(tc.x-2.0 *模糊* hstep,tc.y-2.0 *模糊* vstep)).r * 0.1216216216;sum + = tex2D(tex,float2(tc.x-1.0 *模糊* hstep,tc.y-1.0 *模糊* vstep)).r * 0.1945945946;sum + = tex2D(tex,float2(tc.x,tc.y)).r * 0.2270270270;sum + = tex2D(tex,float2(tc.x + 1.0 *模糊* hstep,tc.y + 1.0 *模糊* vstep)).r * 0.1945945946;sum + = tex2D(tex,float2(tc.x + 2.0 *模糊* hstep,tc.y + 2.0 *模糊* vstep)).r * 0.1216216216;sum + = tex2D(tex,float2(tc.x + 3.0 *模糊* hstep,tc.y + 3.0 *模糊* vstep)).r * 0.0540540541;sum + = tex2D(tex,float2(tc.x + 4.0 *模糊* hstep,tc.y + 4.0 *模糊* vstep)).r * 0.0162162162;返回总和}fixed4 frag(v2f i):SV_Target {const int m = 5;浮点数d = 5.0;浮点z [m];浮动gauss_curve [m];浮动_resolution = 900;z [0] = tex2D(_MainTex,i.uv).r;//最旧的2帧z [1] = tex2D(_HistoryA,i.uv).r;if(abs(z [0]-z [1])< _dataDelta)//阈值深度变化{//z [0] = 0.0;//z0的2D空间高斯模糊z [0] = blur2d_horizo​​ntal(_MainTex,i,_stepsDelta,_stepsDelta);//从最多m帧获取深度z [2] = tex2D(_HistoryB,i.uv).r;z [3] = tex2D(_HistoryC,i.uv).r;z [4] = tex2D(_HistoryD,i.uv).r;zed = 0.0;gauss_curve [0] =高斯(0);gauss_curve [1] =高斯(1);gauss_curve [2] =高斯(2);gauss_curve [3] =高斯(3);gauss_curve [4] =高斯(4);浮点数= 0.0;//一维时间高斯模糊对于(int idx = 1; idx< = m; idx ++){zed + = gauss_curve [idx-1] * z [idx-1];}}别的zed = z [0];返回fixed4(zed,zed,zed,0.0);} 

解决方案

好的,我想我做到了……+/-等式:

仅仅是符号简化(在CV/DIP中很常见),不是唯一确定的不完整方程式...因此对它的解释(和实现)尚不清楚...但是我设法将缺少的东西组合成这样的东西(GLSL):

 <代码>//---------------------------------------------------------------------------//顶点//---------------------------------------------------------------------------#version 420核心//---------------------------------------------------------------------------在vec4顶点中的layout(location = 0);vec2 pos;//屏幕位置< -1,+ 1>无效main(){pos = vertex.xy;gl_Position =顶点;}//--------------------------------------------------------------------------- 

 <代码>//---------------------------------------------------------------------------//片段//---------------------------------------------------------------------------#version 420核心//---------------------------------------------------------------------------在vec2 pos中;//屏幕位置< -1,+ 1>出vec4 gl_FragColor;//片段输出颜色统一采样器2D txr_rgb;统一采样器2D txr_zed0;统一采样器2D txr_zed1;统一采样器2D txr_zed2;统一采样器2D txr_zed3;统一采样器2D txr_zed4;均匀浮点数xs,ys;//纹理分辨率均匀浮动r;//模糊半径//---------------------------------------------------------------------------浮点数G(float t){返回0.0;}//---------------------------------------------------------------------------无效main(){vec2 p;vec4 rgb;const int m = 5;const float Th = 0.0015;浮动z [m],zed;p = 0.5 *(pos + 1.0);//p =位置在纹理中的位置rgb = texture2D(txr_rgb,p);//RGB颜色(仅用于查看)z [0] = texture2D(txr_zed0,p).r;//最旧的2帧z [1] = texture2D(txr_zed1,p).r;if(abs(z [0] -z [1])> Th)//阈值深度变化{我浮点数x,y,xx,yy,rr,dx,dy,w,w0;//z0的2D空间高斯模糊rr = r * r;w0 = 0.3780/pow(r,1.975);z [0] = 0.0;对于(dx = 1.0/xs,x = -r,px = 0.5 +(pos.x * 0.5)+(x * dx); x <= r; x ++,p.x + = dx){xx = x * x;对于(dy = 1.0/ys,y = -r,py = 0.5 +(pos.y * 0.5)+(y * dy); y <= r; y ++,p.y + = dy){yy = y * y;如果(xx + yy <= rr){w = w0 * exp((-xx-yy)/(2.0 * rr));z [0] + = texture2D(txr_zed0,p).r * w;}}}//从最多m帧获取深度z [2] = texture2D(txr_zed2,p).r;z [3] = texture2D(txr_zed3,p).r;z [4] = texture2D(txr_zed4,p).r;//一维时间高斯模糊对于(zed = 0.0,i = 1; i <= m; i ++)zed + = exp(0.5 * float(i * i)/float(m * m))* z [i-1];zed/= 2.506628274631000502415765284811 * float(m);}否则zed = z [0];zed * = 20.0;//调试视图:强调深度,以便其颜色可见//gl_FragColor = rgb;//调试视图:渲染RGB纹理gl_FragColor = vec4(zed,zed,zed,0.0);//渲染结果深度纹理}//--------------------------------------------------------------------------- 

我使用了

时间深度是 m (硬编码),空间是 r (均匀).最后的 m 个帧在 txr_zed0 ... txr_zed(m-1)中传递,其中 txr_zed0 是最早的帧.必须选择阈值 Th ,以便算法选择正确的区域!!!

为使此着色器正常工作,应在其着色器的结果应用后替换 txr_zed0 (在CPU端或渲染为纹理,然后交换ID ...).否则,空间高斯模糊将不会应用于较旧的帧.

[edit1]

此处预览 Th = 0.01;

的预览(在 if 内部输出红色而不是模糊)

如您所见,它选择了边缘...因此变化(仅用于选择Th)是:

 //---------------------------------------------------------------------------//片段//---------------------------------------------------------------------------#version 420核心//---------------------------------------------------------------------------在vec2 pos中;//屏幕位置< -1,+ 1>出vec4 gl_FragColor;//片段输出颜色统一采样器2D txr_rgb;统一采样器2D txr_zed0;统一采样器2D txr_zed1;统一采样器2D txr_zed2;统一采样器2D txr_zed3;统一采样器2D txr_zed4;均匀浮点数xs,ys;//纹理分辨率均匀浮动r;//模糊半径//---------------------------------------------------------------------------浮点数G(float t){返回0.0;}//---------------------------------------------------------------------------无效main(){vec2 p;vec4 rgb;const int m = 5;//const float Th = 0.0015;const float Th = 0.01;浮动z [m],zed;p = 0.5 *(pos + 1.0);//p =位置在纹理中的位置rgb = texture2D(txr_rgb,p);//RGB颜色(仅用于查看)z [0] = texture2D(txr_zed0,p).r;//最旧的2帧z [1] = texture2D(txr_zed1,p).r;if(abs(z [0] -z [1])> Th)//阈值深度变化{gl_FragColor = vec4(1.0,0.0,0.0,0.0);//调试输出返回;我浮点数x,y,xx,yy,rr,dx,dy,w,w0;//z0的2D空间高斯模糊rr = r * r;w0 = 0.3780/pow(r,1.975);z [0] = 0.0;对于(dx = 1.0/xs,x = -r,px = 0.5 +(pos.x * 0.5)+(x * dx); x <= r; x ++,p.x + = dx){xx = x * x;对于(dy = 1.0/ys,y = -r,py = 0.5 +(pos.y * 0.5)+(y * dy); y <= r; y ++,p.y + = dy){yy = y * y;如果(xx + yy <= rr){w = w0 * exp((-xx-yy)/(2.0 * rr));z [0] + = texture2D(txr_zed0,p).r * w;}}}//从最多m帧获取深度z [2] = texture2D(txr_zed2,p).r;z [3] = texture2D(txr_zed3,p).r;z [4] = texture2D(txr_zed4,p).r;//一维时间高斯模糊w0 = 0.5/float(m * m);对于(zed = 0.0,i = 1; i <= m; i ++)zed + = exp(w0 * float(i * i))* z [i-1];zed/= 2.506628274631000502415765284811 * float(m);}否则zed = z [0];zed * = 40.0;//调试视图:强调深度,以便其颜色可见//gl_FragColor = rgb;//调试视图:渲染RGB纹理gl_FragColor = vec4(zed,zed,zed,0.0);//渲染结果深度纹理}//--------------------------------------------------------------------------- 

I would like to calculated the 2D Gaussian function and the input is X,Y texture UV coordinate and get the corresponding gaussian value.

I'm facing difficulties on how to get the corresponding Texel's uv gaussian value.

float Gaussian2D(float x, float y)
{
    float x_y_squared =  x * x + y * y;
    float stDevSquared = 2 *_2D_StandardDeviation * _2D_StandardDeviation;

    float div = x_y_squared / stDevSquared;

    float gauss = pow(E, -div);
    return gauss;
}

float Gaussian(int offset)
{
    float stDevSquared = _StandardDeviation * _StandardDeviation;
    float gauss = (1 / sqrt(2 * PI * stDevSquared)) * pow(E, -((offset * offset) / (2 * stDevSquared)));
    return gauss;
}

fixed4 frag(v2f i) : SV_Target
            {
                fixed source = tex2D(_MainTex, i.uv).r;
                float g0 = Gaussian(0);
                float g1 = Gaussian(1);
                float g2 = Gaussian(2);
                float g3 = Gaussian(3);
                float g4 = Gaussian(4);
                float g5 = Gaussian(5);

                float omega = g0 + g1 + g2 + g3 + g4 + g5;
                float gauss = Gaussian2D(i.uv.x, i.uv.y);

                fixed prev_a = tex2D(_HistoryA, i.uv).r;
                fixed prev_b = tex2D(_HistoryB, i.uv).r;
                fixed prev_c = tex2D(_HistoryC, i.uv).r;
                fixed prev_d = tex2D(_HistoryD, i.uv).r;
                fixed prev_e = tex2D(_HistoryE, i.uv).r;

                fixed current = (gauss*source * g0 + gauss*prev_a * g1 + gauss*prev_b * g2 + gauss*prev_c * g3 + gauss*prev_d * g4 + gauss*prev_e * g5)/(omega);
                
                float diff = source - prev_a;

                if (diff <= _dataDelta)
                {
                    return current;
                }

                return source;
            }
            ENDCG
        }

Update to the Amazing work by Spektre

   sampler2D _MainTex;
            sampler2D _HistoryA;
            sampler2D _HistoryB;
            sampler2D _HistoryC;
            sampler2D _HistoryD;
            float4 _MainTex_TexelSize;
            float _dataDelta;
            float _blurRadius;
            float _stepsDelta;
            float _resolution;
            float4 _MainTex_ST;
            float _StandardDeviation;

            #define E 2.71828182846
            #define PI 3.14159265359


                v2f vert(appdata v) {
                  v2f o;
                  o.vertex = UnityObjectToClipPos(v.vertex);
         
                  o.uv = v.uv;
                  return o;
                }


                float Gaussian(int  offset)
                {
                    float stDevSquared = _StandardDeviation * _StandardDeviation;
                    float gauss = (1 / sqrt(2 * PI * stDevSquared)) * pow(E, -((offset * offset) / (2 * stDevSquared)));
                    return gauss;
                }
                float blur2d_horizontal(sampler2D tex, v2f i, float hstep, float vstep) {
                  float2 uv = i.uv;
                  float sum = 0;
                  float2 tc = uv;

                  //blur radius in pixels
                  float blur = _blurRadius / _resolution / 4;

                  sum += tex2D(tex, float2(tc.x - 4.0 * blur * hstep, tc.y - 4.0 * blur * vstep)).r * 0.0162162162;
                  sum += tex2D(tex, float2(tc.x - 3.0 * blur * hstep, tc.y - 3.0 * blur * vstep)).r * 0.0540540541;
                  sum += tex2D(tex, float2(tc.x - 2.0 * blur * hstep, tc.y - 2.0 * blur * vstep)).r * 0.1216216216;
                  sum += tex2D(tex, float2(tc.x - 1.0 * blur * hstep, tc.y - 1.0 * blur * vstep)).r * 0.1945945946;

                  sum += tex2D(tex, float2(tc.x, tc.y)).r * 0.2270270270;

                  sum += tex2D(tex, float2(tc.x + 1.0 * blur * hstep, tc.y + 1.0 * blur * vstep)).r * 0.1945945946;
                  sum += tex2D(tex, float2(tc.x + 2.0 * blur * hstep, tc.y + 2.0 * blur * vstep)).r * 0.1216216216;
                  sum += tex2D(tex, float2(tc.x + 3.0 * blur * hstep, tc.y + 3.0 * blur * vstep)).r * 0.0540540541;
                  sum += tex2D(tex, float2(tc.x + 4.0 * blur * hstep, tc.y + 4.0 * blur * vstep)).r * 0.0162162162;
                  return sum;
                }
                fixed4 frag(v2f i) : SV_Target {

                const int m = 5;
                float d = 5.0;
                float z[m];
                float gauss_curve[m];
                float zed;
                
                _resolution = 900;
                  z[0] = tex2D(_MainTex, i.uv).r;// oldest 2 frames

                  z[1] = tex2D(_HistoryA, i.uv).r;
                  if (abs(z[0] - z[1]) < _dataDelta) // threshold depth change
                  {
                   // z[0] = 0.0;
                    // 2D spatial gauss blur of z0
                    z[0] = blur2d_horizontal(_MainTex, i, _stepsDelta, _stepsDelta);
                    // fetch depths from up to m frames
                    z[2] = tex2D(_HistoryB, i.uv).r;

                    z[3] = tex2D(_HistoryC, i.uv).r;

                    z[4] = tex2D(_HistoryD, i.uv).r;
                    zed = 0.0;

                    gauss_curve[0] = Gaussian(0);
                    gauss_curve[1] = Gaussian(1);
                    gauss_curve[2] = Gaussian(2);
                    gauss_curve[3] = Gaussian(3);
                    gauss_curve[4] = Gaussian(4);

                    float sum = 0.0;
                    // 1D temporal gauss blur
                    for (int idx = 1; idx <= m; idx++)
                    {
                        zed += gauss_curve[idx - 1] * z[idx - 1];
                    }


                  }
                   else
                     zed = z[0];

                  return fixed4(zed, zed, zed, 0.0);
                }

解决方案

OK I think I managed to do this... well +/- as the equation:

Is just symbolical simplification (common in CV/DIP) not complete equation not uniquely determined... So its interpretation (and implementation) is not clear from it... However I managed to combine the missing stuff into something like this (GLSL):

//---------------------------------------------------------------------------
// Vertex
//---------------------------------------------------------------------------
#version 420 core
//---------------------------------------------------------------------------
layout(location=0) in vec4 vertex;
out vec2 pos;   // screen position <-1,+1>
void main()
    {
    pos=vertex.xy;
    gl_Position=vertex;
    }
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
// Fragment
//---------------------------------------------------------------------------
#version 420 core
//---------------------------------------------------------------------------
in vec2 pos;                    // screen position <-1,+1>
out vec4 gl_FragColor;          // fragment output color
uniform sampler2D txr_rgb;
uniform sampler2D txr_zed0;
uniform sampler2D txr_zed1;
uniform sampler2D txr_zed2;
uniform sampler2D txr_zed3;
uniform sampler2D txr_zed4;
uniform float xs,ys;            // texture resolution
uniform float r;                // blur radius
//---------------------------------------------------------------------------
float G(float t)
    {
    return 0.0;
    }
//---------------------------------------------------------------------------
void main()
    {
    vec2 p;
    vec4 rgb;
    const int m=5;
    const float Th=0.0015;
    float z[m],zed;



    p=0.5*(pos+1.0);                    // p = pos position in texture
    rgb=texture2D(txr_rgb ,p);          // rgb color (just for view)
    z[0]=texture2D(txr_zed0,p).r;       // oldest 2 frames
    z[1]=texture2D(txr_zed1,p).r;

    if (abs(z[0]-z[1])>Th)              // threshold depth change
        {
        int i;
        float x,y,xx,yy,rr,dx,dy,w,w0;
        // 2D spatial gauss blur of z0
        rr=r*r;
        w0=0.3780/pow(r,1.975);
        z[0]=0.0;
        for (dx=1.0/xs,x=-r,p.x=0.5+(pos.x*0.5)+(x*dx);x<=r;x++,p.x+=dx){ xx=x*x;
         for (dy=1.0/ys,y=-r,p.y=0.5+(pos.y*0.5)+(y*dy);y<=r;y++,p.y+=dy){ yy=y*y;
          if (xx+yy<=rr)
            {
            w=w0*exp((-xx-yy)/(2.0*rr));
            z[0]+=texture2D(txr_zed0,p).r*w;
            }}}
        // fetch depths from up to m frames
        z[2]=texture2D(txr_zed2,p).r;
        z[3]=texture2D(txr_zed3,p).r;
        z[4]=texture2D(txr_zed4,p).r;
        // 1D temporal gauss blur
        for (zed=0.0,i=1;i<=m;i++) zed+=exp(0.5*float(i*i)/float(m*m))*z[i-1];
        zed/=2.506628274631000502415765284811*float(m);
        }
    else zed=z[0];
    zed*=20.0;                          // debug view: emphasize depth so its color is visible
//  gl_FragColor=rgb;                   // debug view: render RGB texture
    gl_FragColor=vec4(zed,zed,zed,0.0); // render resulting depth texture
    }
//---------------------------------------------------------------------------

I used this dataset for testing However the depth resolution is not very good...

Using garlic_7_1 dataset I got this result (emphasized depth):

The temporal depth is m (hard coded) and spatial is r (uniform). The last m frames are passed in txr_zed0...txr_zed(m-1) where txr_zed0 is the oldest one. The threshold Th must be chosen so the algo select correct regions!!!

In order this to work properly You should replace txr_zed0 after applying this shader by its result (on CPU side or render to texture and then swap ids ...). Otherwise the spatial Gauss blurring will not be applied to older frames.

[edit1]

Here the preview (outputting red inside the if instead of blurring) for Th=0.01;

As you can see it selects the edges ... So the change (just for chosing Th) is:

//---------------------------------------------------------------------------
// Fragment
//---------------------------------------------------------------------------
#version 420 core
//---------------------------------------------------------------------------
in vec2 pos;                    // screen position <-1,+1>
out vec4 gl_FragColor;          // fragment output color
uniform sampler2D txr_rgb;
uniform sampler2D txr_zed0;
uniform sampler2D txr_zed1;
uniform sampler2D txr_zed2;
uniform sampler2D txr_zed3;
uniform sampler2D txr_zed4;
uniform float xs,ys;            // texture resolution
uniform float r;                // blur radius
//---------------------------------------------------------------------------
float G(float t)
    {
    return 0.0;
    }
//---------------------------------------------------------------------------
void main()
    {
    vec2 p;
    vec4 rgb;
    const int m=5;
//  const float Th=0.0015;
    const float Th=0.01;
    float z[m],zed;

    p=0.5*(pos+1.0);                    // p = pos position in texture
    rgb=texture2D(txr_rgb ,p);          // rgb color (just for view)
    z[0]=texture2D(txr_zed0,p).r;       // oldest 2 frames
    z[1]=texture2D(txr_zed1,p).r;

    if (abs(z[0]-z[1])>Th)              // threshold depth change
        {
        gl_FragColor=vec4(1.0,0.0,0.0,0.0);     // debug output
        return;

        int i;
        float x,y,xx,yy,rr,dx,dy,w,w0;
        // 2D spatial gauss blur of z0
        rr=r*r;
        w0=0.3780/pow(r,1.975);
        z[0]=0.0;
        for (dx=1.0/xs,x=-r,p.x=0.5+(pos.x*0.5)+(x*dx);x<=r;x++,p.x+=dx){ xx=x*x;
         for (dy=1.0/ys,y=-r,p.y=0.5+(pos.y*0.5)+(y*dy);y<=r;y++,p.y+=dy){ yy=y*y;
          if (xx+yy<=rr)
            {
            w=w0*exp((-xx-yy)/(2.0*rr));
            z[0]+=texture2D(txr_zed0,p).r*w;
            }}}
        // fetch depths from up to m frames
        z[2]=texture2D(txr_zed2,p).r;
        z[3]=texture2D(txr_zed3,p).r;
        z[4]=texture2D(txr_zed4,p).r;
        // 1D temporal gauss blur
        w0=0.5/float(m*m);
        for (zed=0.0,i=1;i<=m;i++) zed+=exp(w0*float(i*i))*z[i-1];
        zed/=2.506628274631000502415765284811*float(m);
        }
    else zed=z[0];
    zed*=40.0;                          // debug view: emphasize depth so its color is visible
//  gl_FragColor=rgb;                   // debug view: render RGB texture
    gl_FragColor=vec4(zed,zed,zed,0.0); // render resulting depth texture
    }
//---------------------------------------------------------------------------

这篇关于在片段着色器中计算2D高斯滤波器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆