Чи кубічний тензорний інтерполяційний лагранж такий самий, як бикубическая інтерполяція?


11

Я щойно реалізував деяку інтерпольовану вибірку текстури шляхом відбору проб найближчих пікселів 4х4, потім зробив інтерполяцію Лагранжа по осі x, щоб отримати чотири значення для використання інтерполяції Лагранжа на осі у.

Це те саме, що бикубическая інтерполяція чи це інше? Або є різні види двостулкової інтерполяції, і це, можливо, лише одна з них?

Реалізація 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
Ви можете опублікувати тут відповідний шейдерний код у випадку з бітротом, ні?
joojaa

1
у нас повинна бути якась краща розмітка коду для шейдерного коду, я публікую на мета, якщо хтось не побив мене до цього!
Алан Вулф

Це певна мова шейдера відсутня у списку мов, які охоплені підсвічуванням нашого синтаксису?
трихоплакс

Я не впевнений. Це просто GLSL (від webgl, якщо бути точним!). Я щойно зробив 4 пробіли перед кожним рядком коду, не впевнений, чи є кращий спосіб його позначити ...
Алан Вулф

Відповіді:


8

Виявляється, що ні, хоча ви можете використовувати двосмугову інтерполяцію Lagrange для відбору проб двостулкової текстури, це не найвищий варіант якості і, мабуть, насправді не буде використаний.

Кубічні гермітові сплайни - кращий інструмент для роботи.

Інтерполяція Лагранжа зробить криву, яка проходить через точки даних, тим самим зберігаючи безперервність C0, але сплави гермітів зберігають похідні по краях, одночасно проходячи через точки даних, зберігаючи таким чином безперервність C1 і виглядаючи набагато краще.

У цьому питанні є чудова інформація про кубічні гермітові сплайни: /signals/18265/bicubic-interpolation

Ось кубічна гермітова версія коду, яку я розмістив у запитанні:

//=======================================================================================
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 занадто "визначений користувачем" (і його слід налаштовувати), тоді як герміт сплайну намагається просто використовувати інформацію з даних, які там є. Здається, що кубічний герміт ближче до "ґрунтової істини", яка, напевно, була б чимось на зразок ідеального фільтра sinc. Як ти думаєш, хоча?
Алан Вулф

Я не бачу, як Catmull-Rom "визначений користувачем". Після того, як у вас є послідовність з 4 суміжних точок, P [i-1], P [i], P [i + 1], P [i + 2] (4х4 для двовимірного випадку) сегмент кривої визначається між P [i ] і P [i + 1] і є С1 безперервним із сусідніми сегментами. Фільтр sinc чудово підходить для аудіо, але не для відео. Дивіться Mitchell & Netravali: cs.utexas.edu/~fussell/courses/cs384g-fall2013/lectures/… IIRC Catmull-Rom - особливий випадок сімейства фільтрів, які вони пропонують, але я думаю, що фільтр є приблизною кривою, на відміну від CR, може не пройти через початкові точки.
Саймон F

Ось так працює герміновий сплайн, за винятком того, що у катамату rom spline є додатковий параметр tau (напруга), визначений користувачем. Крім того, sinc застосовується до відео, DSP - це DSP: P
Алан Вулф

Я мушу визнати, я ніколи раніше не бачив параметра напруженості, пов'язаного зі сплайсами Catmull Rom, але тоді я дійсно дізнався про них лише через Foley & van Dam (та ін.) Або, скажімо, Watt & Watt, який, AFAICR, робить жодної згадки про таке. Насправді, сказавши, що, маючи чотири обмеження - тобто крива повинна пройти через 2 точки і мати дві визначені дотичні ** в цих точках, і це кубічний - я трохи втрачаю, як є більше ступенів свободи для підтримки параметра напруги .... ** Якщо ви не маєте на увазі, дотичні можна змінити?
Саймон Ф
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.