三次ラグランジュ補間テンソル積は、双三次補間と同じですか?


11

4x4の最も近いピクセルをサンプリングし、x軸でラグランジュ補間を実行して4つの値を取得し、y軸でラグランジュ補間を使用することにより、いくつかの補間テクスチャサンプリングを実装しました。

これはバイキュービック補間と同じですか、それとも異なりますか?または、さまざまな種類のバイキュービック補間がありますが、これはおそらくそのうちの1つにすぎませんか?

ここでの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
シェーダーコードのよりきれいなコードマークアップを用意する必要があります。誰かが私を倒していない場合は、メタに投稿します!
アランウルフ

その特定のシェーダー言語は、構文の強調表示の対象となる言語のリストにありませんか?
trichoplax

よく分かりません。それは単なるGLSLです(正確にはwebglからです!)。コードの各行の前に4つのスペースを挿入しましたが、それをマークアップするためのより良い方法があるかどうかはわかりません...
アランウルフ

回答:


8

いいえ、バイキュービックテクスチャサンプリングにバイキュービックラグランジュ補間を使用できますが、これは最高品質のオプションではなく、おそらく実際には使用されない可能性があります。

キュービックエルミートスプラインは、この作業に適したツールです。

ラグランジュ補間では、データポイントを通過する曲線が作成されるため、C0の連続性が維持されますが、エルミートスプラインは、データポイントも通過する間、エッジの導関数を維持するため、C1の連続性が維持され、見栄えがよくなります。

この質問には、3次エルミートスプラインに関するいくつかの素晴らしい情報がありますhttps ://dsp.stackexchange.com/questions/18265/bicubic-interpolation

これは、私が質問で投稿したコードの3次エルミートバージョンです。

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

これは、サンプリング方法の違いを示す画像です。左から右へ:最近傍、双一次、ラグランジュ双三次、エルミート双三次

ここに画像の説明を入力してください


すべての3次スプラインは、ある意味では同等ですが、おそらく概念的にはCatmull-Romスプラインを使用する方が簡単です。例 cs.cmu.edu/~462/projects/assn2/assn2/catmullRom.pdf
Simon F

この場合、タウパラメータが役立つか、または妨げると思いますか?私は間違っているかもしれませんが、私はcatmull romが「ユーザー定義」されている(そして調整する必要がある)ように感じますが、エルミートスプラインはそこにあるデータからの情報のみを使用しようとします。立方エルミートは「グラウンドトゥルース」に近いようです。これは理想的なシンクフィルターのようなものだと思います。あなたはどう思いますか?
アランウルフ

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/…を参照してください 。IIRCCatmull-Romは、彼らが提案するフィルターファミリーの特別なケースですが、フィルターは近似曲線なので、 CRとは異なり、元のポイントを通過しない場合があります。
Simon F

catmull romスプラインにユーザー定義の追加パラメーターtau(張力)があることを除いて、それが彼のエルミートスプラインの動作方法です。また、sincはビデオに適用され、DSPはDSP:Pです
Alan Wolfe

認める必要があります。これまでにCatmull Romスプラインに関連する張力パラメータを見たことがありませんが、実際にはFoley&van Dam(et al)またはたとえば、ワット&ワット(AFAICR、そのような言及はありません。実際には、4つの制約がある場合、つまり、曲線は2つの点を通過し、それらの点に2つの接線が定義されている必要があります**。これは3次式です。どのような方法があるのか​​、私は少し困っています。張力パラメータをサポートするためのより多くの自由度.... **接線をスケーリングできることを意味しない限り?
Simon F
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.