3 차 라그랑주 보간 텐서 곱은 2 입방 보간과 동일합니까?


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
비 트롯의 경우 관련 셰이더 코드를 여기에 게시 할 수 있습니다.
joojaa

1
우리는 셰이더 코드에 대한 더 예쁜 코드 마크 업을 가져야합니다. 누군가 나를 이길 수 없다면 메타에 게시 할 것입니다!
Alan Wolfe

구문 강조가 적용되는 언어 목록에서 특정 셰이더 언어를 사용할 수 없습니까?
trichoplax

잘 모르겠습니다. 그것은 단지 GLSL입니다 (webgl에서 정확하게!). 각 코드 줄 앞에 4 개의 공백을 두었습니다. 표시하는 더 좋은 방법이 있는지 확실하지 않습니다 ...
Alan Wolfe

답변:


8

바이 큐빅 텍스처 샘플링에 바이 큐빅 라그랑주 보간을 사용할 수는 있지만, 최고 품질의 옵션은 아니며 실제로는 사용되지 않을 수도 있습니다.

큐빅 은자 스플라인이 작업에 더 적합한 도구입니다.

Lagrange 보간은 데이터 점을 통과하는 곡선을 만들어 C0 연속성을 유지하지만 은자 스플라인은 가장자리에서 미분을 유지하면서 데이터 점을 통과하여 C1 연속성을 유지하고 훨씬 더 잘 보입니다.

이 질문에는 큐빅 은둔 스플라인에 대한 훌륭한 정보가 있습니다.

다음은 질문에 게시 한 코드의 입방 암 버전입니다.

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

다음은 샘플링 방법의 차이점을 보여주는 그림입니다. 왼쪽에서 오른쪽으로 : 가장 가까운 이웃, 쌍 선형, Lagrange Bicubic, Hermite Bicubic

여기에 이미지 설명을 입력하십시오


모든 입방 스플라인은 의미 상 동일하지만 Catmull-Rom 스플라인을 사용하는 것이 개념적으로 더 쉽습니다. 예 : cs.cmu.edu/~462/projects/assn2/assn2/catmullRom.pdf
Simon F

이 경우 tau 매개 변수가 도움이되거나 방해가된다고 생각하십니까? 나는 틀렸을 수도 있지만 catmull rom이 너무 "사용자 정의"되어 있고 튜닝되어야한다고 생각하는 반면, 은자 스플라인은 존재하는 데이터의 정보를 사용하려고 시도합니다. 입방 암이 "지상 진실"에 더 가까운 것 같습니다. 이상적인 sinc 필터와 같은 것 같습니다. 그래도 어떻게 생각하세요?
Alan Wolfe

Catmull-Rom이 어떻게 "사용자 정의"인지 알 수 없습니다. P [i-1], P [i], P [i + 1], P [i + 2] (2D의 경우 4x4)의 연속 된 4 개의 포인트가 있으면 P [i 사이에 곡선 세그먼트가 정의됩니다. ] 및 P [i + 1]이고 인접 세그먼트와 연속적인 C1이다. sinc 필터는 오디오에는 적합하지만 비디오에는 적합하지 않습니다. Mitchell & Netravali 참조 : cs.utexas.edu/~fussell/courses/cs384g-fall2013/lectures/… IIRC Catmull-Rom은 그들이 제안하는 필터 제품군의 특별한 경우이지만 필터는 근사 곡선이라고 생각합니다. CR과 달리 원래 포인트를 거치지 않을 수 있습니다.
Simon F

이것이 Catmull 롬 스플라인에 사용자 정의 된 추가 매개 변수 tau (장력)가 있다는 점을 제외하고는 스플라인 작동 방식입니다. 또한, 싱크 비디오에 적용됩니까, DSP는 DSP입니다 : P
앨런 울프

인정해야합니다. 전에 Catmull Rom 스플라인과 관련된 장력 매개 변수를 본 적이 없지만 Foley & van Dam (et al) 또는 AFAICR, Watt & Watt를 통해 실제로 알게되었습니다. 그런 언급이 없습니다. 실제로, 네 가지 제약 조건이 있다고 가정했을 때, 즉 곡선은 2 점을 통과해야하며 그 점에서 2 개의 정의 된 접선 **이 있고 입방체입니다-나는 어떤 방법이 있는지에 대해 약간의 손실이 있습니다 장력 매개 변수를 지원할 수있는 더 많은 자유도 .... ** 탄젠트를 조정할 수 있다는 의미가 아닌 한?
Simon F
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.