三次Lagrange插值张量积与双三次插值相同吗?


11

我只是通过对4x4最近的像素进行采样,然后在x轴上进行Lagrange插值来获得四个值,以在y轴上使用Lagrange插值来实现一些插值纹理采样。

这与三次三次插值相同还是不同?还是有不同的双三次插值,也许只是其中之一?

这里的Webgl Shadertoy实现以及下面的相关GLSL(WebGL)代码:https ://www.shadertoy.com/view/MllSzX

谢谢!

float c_textureSize = 64.0;

float c_onePixel = 1.0 / c_textureSize;
float c_twoPixels = 2.0 / c_textureSize;

float c_x0 = -1.0;
float c_x1 =  0.0;
float c_x2 =  1.0;
float c_x3 =  2.0;

//=======================================================================================
vec3 CubicLagrange (vec3 A, vec3 B, vec3 C, vec3 D, float t)
{
    return
        A * 
        (
            (t - c_x1) / (c_x0 - c_x1) * 
            (t - c_x2) / (c_x0 - c_x2) *
            (t - c_x3) / (c_x0 - c_x3)
        ) +
        B * 
        (
            (t - c_x0) / (c_x1 - c_x0) * 
            (t - c_x2) / (c_x1 - c_x2) *
            (t - c_x3) / (c_x1 - c_x3)
        ) +
        C * 
        (
            (t - c_x0) / (c_x2 - c_x0) * 
            (t - c_x1) / (c_x2 - c_x1) *
            (t - c_x3) / (c_x2 - c_x3)
        ) +       
        D * 
        (
            (t - c_x0) / (c_x3 - c_x0) * 
            (t - c_x1) / (c_x3 - c_x1) *
            (t - c_x2) / (c_x3 - c_x2)
        );
}

//=======================================================================================
vec3 BicubicTextureSample (vec2 P)
{
    vec2 pixel = P * c_textureSize + 0.5;

    vec2 frac = fract(pixel);
    pixel = floor(pixel) / c_textureSize - vec2(c_onePixel/2.0);

    vec3 C00 = texture2D(iChannel0, pixel + vec2(-c_onePixel ,-c_onePixel)).rgb;
    vec3 C10 = texture2D(iChannel0, pixel + vec2( 0.0        ,-c_onePixel)).rgb;
    vec3 C20 = texture2D(iChannel0, pixel + vec2( c_onePixel ,-c_onePixel)).rgb;
    vec3 C30 = texture2D(iChannel0, pixel + vec2( c_twoPixels,-c_onePixel)).rgb;

    vec3 C01 = texture2D(iChannel0, pixel + vec2(-c_onePixel , 0.0)).rgb;
    vec3 C11 = texture2D(iChannel0, pixel + vec2( 0.0        , 0.0)).rgb;
    vec3 C21 = texture2D(iChannel0, pixel + vec2( c_onePixel , 0.0)).rgb;
    vec3 C31 = texture2D(iChannel0, pixel + vec2( c_twoPixels, 0.0)).rgb;    

    vec3 C02 = texture2D(iChannel0, pixel + vec2(-c_onePixel , c_onePixel)).rgb;
    vec3 C12 = texture2D(iChannel0, pixel + vec2( 0.0        , c_onePixel)).rgb;
    vec3 C22 = texture2D(iChannel0, pixel + vec2( c_onePixel , c_onePixel)).rgb;
    vec3 C32 = texture2D(iChannel0, pixel + vec2( c_twoPixels, c_onePixel)).rgb;    

    vec3 C03 = texture2D(iChannel0, pixel + vec2(-c_onePixel , c_twoPixels)).rgb;
    vec3 C13 = texture2D(iChannel0, pixel + vec2( 0.0        , c_twoPixels)).rgb;
    vec3 C23 = texture2D(iChannel0, pixel + vec2( c_onePixel , c_twoPixels)).rgb;
    vec3 C33 = texture2D(iChannel0, pixel + vec2( c_twoPixels, c_twoPixels)).rgb;    

    vec3 CP0X = CubicLagrange(C00, C10, C20, C30, frac.x);
    vec3 CP1X = CubicLagrange(C01, C11, C21, C31, frac.x);
    vec3 CP2X = CubicLagrange(C02, C12, C22, C32, frac.x);
    vec3 CP3X = CubicLagrange(C03, C13, C23, C33, frac.x);

    return CubicLagrange(CP0X, CP1X, CP2X, CP3X, frac.y);
}

2
如果发生bitrot,您可以在此处发布相关的着色器代码,不是吗?
joojaa

1
我们应该为着色器代码提供一些更漂亮的代码标记,如果有人没有击败我,我会在meta上发布!
艾伦·沃尔夫

语法突出显示覆盖的语言列表中是否没有特定的着色器语言?
trichoplax

我不确定。这只是GLSL(确切地说是从webgl!)。我只是在每行代码之前做了4个空格,不确定是否有更好的方法对其进行标记...
Alan Wolfe 2015年

Answers:


8

事实证明,没有,尽管您可以将双三次Lagrange插值用于双三次纹理采样,但这不是最高质量的选项,并且可能实际上不太可能使用。

三次方Hermite花键是完成此工作的更好工具。

拉格朗日插值法将使一条曲线穿过数据点,从而保留C0连续性,但是Hermite样条曲线保留边沿处的导数,同时也穿过数据点,从而保留C1连续性,并且看起来更好。

这个问题有关于三次Hermite样条的一些重要信息:https ://dsp.stackexchange.com/questions/18265/bicubic-interpolation

这是我在问题中发布的代码的三次方Hermite版本:

//=======================================================================================
vec3 CubicHermite (vec3 A, vec3 B, vec3 C, vec3 D, float t)
{
    float t2 = t*t;
    float t3 = t*t*t;
    vec3 a = -A/2.0 + (3.0*B)/2.0 - (3.0*C)/2.0 + D/2.0;
    vec3 b = A - (5.0*B)/2.0 + 2.0*C - D / 2.0;
    vec3 c = -A/2.0 + C/2.0;
    vec3 d = B;

    return a*t3 + b*t2 + c*t + d;
}

//=======================================================================================
vec3 BicubicHermiteTextureSample (vec2 P)
{
    vec2 pixel = P * c_textureSize + 0.5;

    vec2 frac = fract(pixel);
    pixel = floor(pixel) / c_textureSize - vec2(c_onePixel/2.0);

    vec3 C00 = texture2D(iChannel0, pixel + vec2(-c_onePixel ,-c_onePixel)).rgb;
    vec3 C10 = texture2D(iChannel0, pixel + vec2( 0.0        ,-c_onePixel)).rgb;
    vec3 C20 = texture2D(iChannel0, pixel + vec2( c_onePixel ,-c_onePixel)).rgb;
    vec3 C30 = texture2D(iChannel0, pixel + vec2( c_twoPixels,-c_onePixel)).rgb;

    vec3 C01 = texture2D(iChannel0, pixel + vec2(-c_onePixel , 0.0)).rgb;
    vec3 C11 = texture2D(iChannel0, pixel + vec2( 0.0        , 0.0)).rgb;
    vec3 C21 = texture2D(iChannel0, pixel + vec2( c_onePixel , 0.0)).rgb;
    vec3 C31 = texture2D(iChannel0, pixel + vec2( c_twoPixels, 0.0)).rgb;    

    vec3 C02 = texture2D(iChannel0, pixel + vec2(-c_onePixel , c_onePixel)).rgb;
    vec3 C12 = texture2D(iChannel0, pixel + vec2( 0.0        , c_onePixel)).rgb;
    vec3 C22 = texture2D(iChannel0, pixel + vec2( c_onePixel , c_onePixel)).rgb;
    vec3 C32 = texture2D(iChannel0, pixel + vec2( c_twoPixels, c_onePixel)).rgb;    

    vec3 C03 = texture2D(iChannel0, pixel + vec2(-c_onePixel , c_twoPixels)).rgb;
    vec3 C13 = texture2D(iChannel0, pixel + vec2( 0.0        , c_twoPixels)).rgb;
    vec3 C23 = texture2D(iChannel0, pixel + vec2( c_onePixel , c_twoPixels)).rgb;
    vec3 C33 = texture2D(iChannel0, pixel + vec2( c_twoPixels, c_twoPixels)).rgb;    

    vec3 CP0X = CubicHermite(C00, C10, C20, C30, frac.x);
    vec3 CP1X = CubicHermite(C01, C11, C21, C31, frac.x);
    vec3 CP2X = CubicHermite(C02, C12, C22, C32, frac.x);
    vec3 CP3X = CubicHermite(C03, C13, C23, C33, frac.x);

    return CubicHermite(CP0X, CP1X, CP2X, CP3X, frac.y);
}

这是一张图片,显示了采样方法之间的差异。从左至右:最近邻,双线性,拉格朗日双三次,埃尔米特双三次

在此处输入图片说明


尽管从某种意义上说,所有三次样条都是等效的,但从概念上讲,使用Catmull-Rom样条可能更容易。例如 cs.cmu.edu/~462/projects/assn2/assn2/catmullRom.pdf
Simon F

您是否认为tau参数在这种情况下有帮助还是有阻碍?我可能是错的,但是我觉得catmull rom太“用户定义”了(必须进行调整),而hermite样条曲线试图仅使用那里的数据中的信息。看来立方埃尔米特似乎更接近“基本事实”,我想这就像是理想的Sinc滤波器。你觉得呢
艾伦·沃尔夫

我看不到Catmull-Rom是“用户定义”的。一旦具有4个连续点的序列,即P [i-1],P [i],P [i + 1],P [i + 2](对于2D情况为4x4),则曲线段将在P [i ]和P [i + 1],并且C1与相邻段连续。Sinc滤波器适用于音频,但不适用于视频。参见Mitchell&Netravali:cs.utexas.edu/~fussell/courses/cs384g-fall2013/lectures/…IIRC Catmull-Rom是他们提出的滤波器系列的特例,但我认为滤波器是一个近似曲线,与CR不同,它可能无法通过原始说明。
西蒙F

这就是hermite样条曲线的工作方式,除了catmull rom样条曲线具有用户定义的附加参数tau(张力)。另外,sinc确实适用于视频,DSP是DSP:P
艾伦·沃尔夫

我必须承认,我以前从未见过与Catmull Rom花键相关的张力参数,但后来我真的只通过Foley&van Dam(et al)或例如Watt&Watt得知了它们,AFAICR使得没有提及这样。话虽如此,实际上,有四个约束条件-即曲线必须经过2个点,并且在这些点处有两个定义的切线**,并且它是三次方的-我有点茫然地知道支持张力参数的自由度更高.... **除非您的意思是切线可以缩放?
西蒙F
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.