Apakah produk tensor interpolasi Lagrange kubik sama dengan interpolasi bikubik?

11

Saya baru saja menerapkan beberapa sampling tekstur interpolasi dengan mengambil sampel piksel terdekat 4x4 kemudian melakukan interpolasi Lagrange melintasi sumbu x untuk mendapatkan empat nilai untuk menggunakan interpolasi Lagrange pada melintasi sumbu y.

Apakah ini sama dengan interpolasi bikubik atau berbeda? Atau ada berbagai macam interpolasi bikubik, dan ini mungkin salah satunya saja?

Implementasi Webgl Shadertoy di sini dan kode GLSL (WebGL) yang relevan di bawah: https://www.shadertoy.com/view/MllSzX

Terima kasih!

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);
}
Alan Wolfe
sumber
2
Anda dapat memposting kode shader yang relevan di sini dalam kasus bitrot, bukan?
joojaa
1
kita harus memiliki beberapa markup kode cantik untuk kode shader, saya akan memposting di meta jika seseorang belum mengalahkan saya untuk itu!
Alan Wolfe
Apakah itu bahasa shader tertentu tidak tersedia dalam daftar bahasa yang dicakup oleh penyorotan sintaksis kami?
trichoplax
Saya tidak yakin. Itu hanya GLSL (dari webgl tepatnya!). Saya hanya melakukan 4 spasi sebelum setiap baris kode, tidak yakin apakah ada cara yang lebih baik untuk menandainya ...
Alan Wolfe

Jawaban:

8

Ternyata tidak, sementara Anda dapat menggunakan interpolasi Lagrange bikubik untuk pengambilan sampel tekstur bikubik, itu bukan pilihan kualitas tertinggi, dan mungkin sebenarnya tidak mungkin digunakan.

Cubic hermite splines adalah alat yang lebih baik untuk pekerjaan itu.

Interpolasi Lagrange akan membuat kurva yang melewati titik-titik data, sehingga menjaga kontinuitas C0, tetapi hermite splines mempertahankan turunannya di tepian sementara juga melewati titik-titik data, sehingga menjaga kontinuitas C1 dan terlihat jauh lebih baik.

Pertanyaan ini memiliki beberapa info hebat tentang splines hermite kubik: /signals/18265/bicubic-interpolation

Ini adalah versi hermite kubik dari kode yang saya posting di pertanyaan:

//=======================================================================================
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);
}

Berikut adalah gambar yang menunjukkan perbedaan antara metode pengambilan sampel. Dari kiri ke kanan: Tetangga Terdekat, Bilinear, Lagrange Bicubic, Hermite Bicubic

masukkan deskripsi gambar di sini

Alan Wolfe
sumber
Meskipun semua splines kubik, dalam arti tertentu, setara, mungkin secara konseptual lebih mudah untuk menggunakan splines Catmull-Rom. mis. cs.cmu.edu/~462/projects/assn2/assn2/catmullRom.pdf
Simon F
Apakah menurut Anda parameter tau membantu atau menghalangi dalam hal ini? Saya mungkin salah tetapi saya merasa seperti catmull rom terlalu "didefinisikan pengguna" (dan harus disetel), sedangkan spline hermite mencoba untuk hanya menggunakan informasi dari data yang ada di sana. Sepertinya pertapa kubik lebih dekat ke "kebenaran dasar", yang saya kira akan menjadi sesuatu seperti filter sinc yang ideal. Apa yang kamu pikirkan?
Alan Wolfe
Saya tidak melihat bagaimana Catmull-Rom "didefinisikan pengguna". Setelah Anda memiliki urutan 4 titik yang berdekatan, P [i-1], P [i], P [i + 1], P [i + 2] (4x4 untuk kasus 2D) segmen kurva didefinisikan antara P [i ] dan P [i + 1] dan C1 kontinu dengan segmen tetangga. Filter tulus tidak masalah untuk audio tetapi tidak untuk video. Lihat Mitchell & Netravali: cs.utexas.edu/~fussell/courses/cs384g-fall2013/lectures/… IIRC Catmull-Rom adalah kasus khusus dari keluarga filter yang mereka ajukan, tapi saya pikir filter tersebut merupakan kurva perkiraan jadi, tidak seperti CR, mungkin tidak melalui poin asli.
Simon F
Begitulah cara kerjanya hermite spline kecuali bahwa catmull rom spline memiliki parameter tambahan tau (ketegangan) yang ditentukan pengguna. Selain itu, sinc tidak berlaku untuk video, DSP adalah DSP: P
Alan Wolfe
Harus saya akui, saya belum pernah melihat parameter tegangan yang terkait dengan splines Catmull Rom sebelumnya, tapi kemudian saya benar-benar hanya mengetahuinya melalui Foley & van Dam (et al) atau, katakanlah, Watt & Watt yang, AFAICR, buat tidak disebutkan. Sebenarnya, setelah mengatakan itu, mengingat ada empat kendala - yaitu kurva harus melewati 2 poin dan memiliki dua garis singgung yang ditetapkan ** pada titik-titik tersebut dan itu adalah kubik - Saya sedikit bingung bagaimana ada lebih banyak derajat kebebasan untuk mendukung parameter tegangan .... ** Kecuali maksud Anda tangen dapat ditingkatkan?
Simon F