LYGIA Shader Library

bilateral (lygia/filter/bilateral)

This is a two dimensioanl Bilateral filter (for a single pass) It's a non-linear, edge-preserving, and noise-reducing smoothing filter for images. It replaces the intensity of each pixel with a weighted average of intensity values from nearby pixels. This filter is very effective at noise removal while preserving edges. It is very similar to the Gaussian blur, but it also takes into account the intensity differences between a pixel and its neighbors. This is what makes it particularly effective at noise removal while preserving edges.

Dependencies:

Use:

bilateral(<SAMPLER_TYPE> texture, <vec2> st, <vec2> duv [, <int> kernelSize]])

Check it on Github



#ifndef BILATERAL_TYPE
#define BILATERAL_TYPE vec4
#endif

#ifndef BILATERAL_SAMPLER_FNC
#define BILATERAL_SAMPLER_FNC(TEX, UV) sampleClamp2edge(TEX, UV)
#endif

#ifndef BILATERAL_LUMA
#define BILATERAL_LUMA(RGB) rgb2luma(RGB.rgb)
#endif

#ifndef FNC_BILATERALFILTER
#define FNC_BILATERALFILTER
BILATERAL_TYPE bilateral(in SAMPLER_TYPE tex, in vec2 st, in vec2 offset, const int kernelSize) {
    BILATERAL_TYPE accumColor = BILATERAL_TYPE(0.);

    #ifndef BILATERAL_KERNELSIZE
    #if defined(PLATFORM_WEBGL)
    #define BILATERAL_KERNELSIZE 20
    float kernelSizef = float(kernelSize);
    #else
    #define BILATERAL_KERNELSIZE kernelSize
    float kernelSizef = float(BILATERAL_KERNELSIZE);
    #endif
    #else 
    float kernelSizef = float(BILATERAL_KERNELSIZE);
    #endif

    float accumWeight = 0.0;
    const float k = 0.15915494; // 1. / (2.*PI)
    const float k2 = k * k;

    float kernelSize2 = kernelSizef * kernelSizef;
    BILATERAL_TYPE tex0 = BILATERAL_SAMPLER_FNC(tex, st);
    float lum0 = BILATERAL_LUMA(tex0);

    for (int j = 0; j < BILATERAL_KERNELSIZE; j++) {
        #if defined(PLATFORM_WEBGL)
        if (j >= kernelSize)
            break;
        #endif
        float dy = -0.5 * (kernelSizef - 1.0) + float(j);
        for (int i = 0; i < BILATERAL_KERNELSIZE; i++) {
            #if defined(PLATFORM_WEBGL)
            if (i >= kernelSize)
                break;
            #endif
            float dx = -0.5 * (kernelSizef - 1.0) + float(i);
            BILATERAL_TYPE t = BILATERAL_SAMPLER_FNC(tex, st + vec2(dx, dy) * offset);
            float lum = BILATERAL_LUMA(t);
            float dl = 255.0 * (lum - lum0);
            float weight = (k2 / kernelSize2) * gaussian(vec3(dx,dy,dl), kernelSizef);
            accumColor += weight * t;
            accumWeight += weight;
        }
    }
    return accumColor / accumWeight;
}
#endif

Dependencies:

Use:

bilateral(<SAMPLER_TYPE> texture, <float2> st, <float2> duv)

Check it on Github



#ifndef BILATERAL_TYPE
#define BILATERAL_TYPE float4
#endif

#ifndef BILATERAL_SAMPLER_FNC
#define BILATERAL_SAMPLER_FNC(TEX, UV) sampleClamp2edge(TEX, UV)
#endif

#ifndef BILATERAL_LUMA
#define BILATERAL_LUMA(RGB) rgb2luma(RGB.rgb)
#endif

#ifndef BILATERAL_KERNEL_MAXSIZE
#define BILATERAL_KERNEL_MAXSIZE 20
#endif

#ifndef FNC_BILATERALFILTER
#define FNC_BILATERALFILTER

BILATERAL_TYPE bilateral(SAMPLER_TYPE tex, float2 st, float2 offset, const int kernelSize) {
    BILATERAL_TYPE accumColor = float4(0.0, 0.0, 0.0, 0.0);
    float accumWeight = 0.0;
    const float k = 0.15915494; // 1. / (2.*PI)
    const float k2 = k * k;
    float kernelSizef = float(kernelSize);
    float kernelSize2f = kernelSizef * kernelSizef;
    BILATERAL_TYPE tex0 = BILATERAL_SAMPLER_FNC(tex, st);
    float lum0 = BILATERAL_LUMA(tex0);

    for (int j = 0; j < BILATERAL_KERNEL_MAXSIZE; j++) {
        if (j >= kernelSize)
            break;
        float dy = -0.5 * (kernelSizef - 1.0) + float(j);
        for (int i = 0; i < BILATERAL_KERNEL_MAXSIZE; i++) {
            if (i >= kernelSize)
                break;
            float dx = -0.5 * (kernelSizef - 1.0) + float(i);

            BILATERAL_TYPE t = BILATERAL_SAMPLER_FNC(tex, st + float2(dx, dy) * offset);
            float lum = BILATERAL_LUMA(t);
            float dl = 255.0 * (lum - lum0);
            float weight = (k2 / kernelSize2f) * gaussian(kernelSizef, float3(dx, dy, dl));
            accumColor += weight * t;
            accumWeight += weight;
        }
    }
    return accumColor / accumWeight;
}
#endif

Examples

Licenses

LYGIA is dual-licensed under the Prosperity License and the Patron License for sponsors and contributors.

Sponsors and contributors are automatically added to the Patron License and they can ignore the any non-commercial rule of the Prosperity Licensed software (please take a look to the exception).

It's also possible to get a permanent comercial license hook to a single and specific version of LYGIA.

Get the latest news and releases

Sign up for the news letter bellow, joing the LYGIA's channel on Discord or follow the Github repository