2013-01-16 12 views
9

Web üzerinde çalıştığım bir uygulamada görüntüleri hızlı bir şekilde yeniden boyutlandırmak için WebGL kullanıyorum. Ben küçültüyorum görüntüleri üzerinde basit bilineer filtreleme gerçekleştiren bir GLSL shader yazdım.Bu WebGL/GLSL görüntüsünü downsampling gölgelendiricisini nasıl geliştirebilirim

Çoğu bölüm için iyi çalışıyor ancak yeniden boyutlandırmanın çok büyük olduğu birçok durum var. Bir küçük resim oluşturmak için 2048x2048 görüntüden 110x110 değerine kadar. Bu durumlarda, kalite zayıf ve çok bulanık. aşağıdaki gibi

geçerli benim GLSL Shader:

uniform float textureSizeWidth;\ 
uniform float textureSizeHeight;\ 
uniform float texelSizeX;\ 
uniform float texelSizeY;\ 
varying mediump vec2 texCoord;\ 
uniform sampler2D texture;\ 
\ 
vec4 tex2DBiLinear(sampler2D textureSampler_i, vec2 texCoord_i)\ 
{\ 
    vec4 p0q0 = texture2D(textureSampler_i, texCoord_i);\ 
    vec4 p1q0 = texture2D(textureSampler_i, texCoord_i + vec2(texelSizeX, 0));\ 
\ 
    vec4 p0q1 = texture2D(textureSampler_i, texCoord_i + vec2(0, texelSizeY));\ 
    vec4 p1q1 = texture2D(textureSampler_i, texCoord_i + vec2(texelSizeX , texelSizeY));\ 
\ 
    float a = fract(texCoord_i.x * textureSizeWidth);\ 
\ 
    vec4 pInterp_q0 = mix(p0q0, p1q0, a);\ 
    vec4 pInterp_q1 = mix(p0q1, p1q1, a);\ 
\ 
    float b = fract(texCoord_i.y * textureSizeHeight);\ 
    return mix(pInterp_q0, pInterp_q1, b);\ 
}\ 
void main() { \ 
\ 
    gl_FragColor = tex2DBiLinear(texture,texCoord);\ 
}'); 

TexelsizeX ve TexelsizeY

daha yüksek kalitede bir filtreleme tekniği uygulamak istiyorum ... sadece (1.0/doku genişlik) ve sırasıyla, yükseklik İdeal olarak [Lancosz] [1] filtresi çok daha iyi sonuçlar vermelidir ancak genel olarak WebGL ve GLSL için çok yeni olduğumdan GLSL ile algoritmayı nasıl uygulayacağım konusunda kafamı alamıyorum.

Herkes bana doğru yönde işaret edebilir mi?

Şimdiden teşekkürler.

cevap

15

Eğer Lanczos yeniden örnekleme arıyorsanız, aşağıdaki benim açık kaynak GPUImage kütüphanede kullanmak shader programdır:

Vertex Shader:

attribute vec4 position; 
attribute vec2 inputTextureCoordinate; 

uniform float texelWidthOffset; 
uniform float texelHeightOffset; 

varying vec2 centerTextureCoordinate; 
varying vec2 oneStepLeftTextureCoordinate; 
varying vec2 twoStepsLeftTextureCoordinate; 
varying vec2 threeStepsLeftTextureCoordinate; 
varying vec2 fourStepsLeftTextureCoordinate; 
varying vec2 oneStepRightTextureCoordinate; 
varying vec2 twoStepsRightTextureCoordinate; 
varying vec2 threeStepsRightTextureCoordinate; 
varying vec2 fourStepsRightTextureCoordinate; 

void main() 
{ 
    gl_Position = position; 

    vec2 firstOffset = vec2(texelWidthOffset, texelHeightOffset); 
    vec2 secondOffset = vec2(2.0 * texelWidthOffset, 2.0 * texelHeightOffset); 
    vec2 thirdOffset = vec2(3.0 * texelWidthOffset, 3.0 * texelHeightOffset); 
    vec2 fourthOffset = vec2(4.0 * texelWidthOffset, 4.0 * texelHeightOffset); 

    centerTextureCoordinate = inputTextureCoordinate; 
    oneStepLeftTextureCoordinate = inputTextureCoordinate - firstOffset; 
    twoStepsLeftTextureCoordinate = inputTextureCoordinate - secondOffset; 
    threeStepsLeftTextureCoordinate = inputTextureCoordinate - thirdOffset; 
    fourStepsLeftTextureCoordinate = inputTextureCoordinate - fourthOffset; 
    oneStepRightTextureCoordinate = inputTextureCoordinate + firstOffset; 
    twoStepsRightTextureCoordinate = inputTextureCoordinate + secondOffset; 
    threeStepsRightTextureCoordinate = inputTextureCoordinate + thirdOffset; 
    fourStepsRightTextureCoordinate = inputTextureCoordinate + fourthOffset; 
} 

Fragment shader:

precision highp float; 

uniform sampler2D inputImageTexture; 

varying vec2 centerTextureCoordinate; 
varying vec2 oneStepLeftTextureCoordinate; 
varying vec2 twoStepsLeftTextureCoordinate; 
varying vec2 threeStepsLeftTextureCoordinate; 
varying vec2 fourStepsLeftTextureCoordinate; 
varying vec2 oneStepRightTextureCoordinate; 
varying vec2 twoStepsRightTextureCoordinate; 
varying vec2 threeStepsRightTextureCoordinate; 
varying vec2 fourStepsRightTextureCoordinate; 

// sinc(x) * sinc(x/a) = (a * sin(pi * x) * sin(pi * x/a))/(pi^2 * x^2) 
// Assuming a Lanczos constant of 2.0, and scaling values to max out at x = +/- 1.5 

void main() 
{ 
    lowp vec4 fragmentColor = texture2D(inputImageTexture, centerTextureCoordinate) * 0.38026; 

    fragmentColor += texture2D(inputImageTexture, oneStepLeftTextureCoordinate) * 0.27667; 
    fragmentColor += texture2D(inputImageTexture, oneStepRightTextureCoordinate) * 0.27667; 

    fragmentColor += texture2D(inputImageTexture, twoStepsLeftTextureCoordinate) * 0.08074; 
    fragmentColor += texture2D(inputImageTexture, twoStepsRightTextureCoordinate) * 0.08074; 

    fragmentColor += texture2D(inputImageTexture, threeStepsLeftTextureCoordinate) * -0.02612; 
    fragmentColor += texture2D(inputImageTexture, threeStepsRightTextureCoordinate) * -0.02612; 

    fragmentColor += texture2D(inputImageTexture, fourStepsLeftTextureCoordinate) * -0.02143; 
    fragmentColor += texture2D(inputImageTexture, fourStepsRightTextureCoordinate) * -0.02143; 

    gl_FragColor = fragmentColor; 
} 

İki geçişte uygulanır, ilk önce yatay bir altörnekleme ve ikincisi dikey bir alt örnekleme yapılır. texelWidthOffset ve texelHeightOffset üniformaları dönüşümlü olarak sırasıyla 0,0 değerine ve görüntüdeki tek bir pikselin genişlik kesir veya yükseklik oranına ayarlanır.

Köşe gölgelendiricisindeki doku ofsetlerini sabit olarak hesaplıyorum çünkü bu, hedeflediğim mobil aygıtlardaki doku okumalarını engelliyor ve bu da orada önemli ölçüde daha iyi bir performans sağlıyor. Yine de, biraz ayrıntılı. Bu Lanczos yeniden örnekleme gelen

Sonuçlar:

Lanczos

Normal çiftdoğrusal altörnekleme:

Bilinear

yakın komşu altörnekleme:

Nearest-neighbor

+0

A güzel inşa edilmiş bir cevap. Teşekkür ederim. Göndermiş olduğunuz koddan oraya ulaşabilmem gerekir. Şerefe! – gordyr

+0

Sadece bildiğimi bildirmek için bu mükemmel çalışıyor ve sonuçlar güzel. Garip bir şekilde Texeloffsets'i en iyi sonuç için (1.0/(destinationwidth * 3)) ve (1.0/(destinationheight * 3)) olarak ayarladım. Nedenini anladığımdan emin değilim ama standart genişlik/yükseklik kullanmak çok bulanık bir görüntü üretti. Her şeye rağmen şimdi muhteşem. Kocaman teşekkürler! – gordyr

+0

@gordyr - Duymak güzel. Yani, texelWidthOffset = 3.0/(piksel cinsinden görüntü genişliği) veya texelWidthOffset = 1.0/(3.0 * (piksel cinsinden görüntü genişliği)) kullanmanız gerektiği anlamına mı geliyor?Yukarıdaki görüntüleri texelWidthOffset = 1.0/(piksel cinsinden görüntü genişliği) ve texelHeightOffset = 1.0/(piksel cinsinden görüntü yüksekliği) ile oluşturdum, ancak üçlü bir faktör sizin için işe yararsa, onunla birlikte ilerleyin. –

İlgili konular