LYGIA Shader Library

2D_fast3 (lygia/filter/median/2D_fast3)

3x3 median filter, adapted from "A Fast, Small-Radius GPU Median Filter" by Morgan McGuire in ShaderX6 https://casual-effects.com/research/McGuire2008Median/index.html

Dependencies:

Use:

median2D_fast3(<SAMPLER_TYPE> texture, <vec2> st, <vec2> pixel)

Check it on Github



#ifndef MEDIAN2D_FAST3_TYPE
#ifdef MEDIAN2D_TYPE
#define MEDIAN2D_FAST3_TYPE MEDIAN2D_TYPE
#else
#define MEDIAN2D_FAST3_TYPE vec4
#endif
#endif

#ifndef MEDIAN2D_FAST3_SAMPLER_FNC
#ifdef MEDIAN_SAMPLER_FNC
#define MEDIAN2D_FAST3_SAMPLER_FNC(TEX, UV) MEDIAN_SAMPLER_FNC(TEX, UV)
#else
#define MEDIAN2D_FAST3_SAMPLER_FNC(TEX, UV) SAMPLER_FNC(TEX, UV)
#endif
#endif

#ifndef MEDIAN_S2
#define MEDIAN_S2(a, b) temp = a; a = min(a, b); b = max(temp, b);
#endif

#ifndef MEDIAN_2
#define MEDIAN_2(a, b) MEDIAN_S2(v[a], v[b]);
#endif

#ifndef FNC_MEDIAN2D_FAST3
#define FNC_MEDIAN2D_FAST3
#define MEDIAN_MN3(a, b, c) MEDIAN_2(a, b); MEDIAN_2(a, c);
#define MEDIAN_MX3(a, b, c) MEDIAN_2(b, c); MEDIAN_2(a, c);
#define MEDIAN_MNMX3(a, b, c) MEDIAN_MX3(a, b, c); MEDIAN_2(a, b);                                                                // 3 exchanges
#define MEDIAN_MNMX4(a, b, c, d) MEDIAN_2(a, b); MEDIAN_2(c, d); MEDIAN_2(a, c); MEDIAN_2(b, d);                                  // 4 exchanges
#define MEDIAN_MNMX5(a, b, c, d, e) MEDIAN_2(a, b); MEDIAN_2(c, d); MEDIAN_MN3(a, c, e); MEDIAN_MX3(b, d, e);                     // 6 exchanges
#define MEDIAN_MNMX6(a, b, c, d, e, f) MEDIAN_2(a, d); MEDIAN_2(b, e); MEDIAN_2(c, f); MEDIAN_MN3(a, b, c); MEDIAN_MX3(d, e, f);  // 7 exchanges
MEDIAN2D_FAST3_TYPE median2D_fast3(in SAMPLER_TYPE tex, in vec2 st, in vec2 radius) {
    MEDIAN2D_FAST3_TYPE v[9];
    for (int dX = -1; dX <= 1; ++dX) {
        for (int dY = -1; dY <= 1; ++dY) {
            vec2 offset = vec2(float(dX), float(dY));
            // If a pixel in the window is located at (x+dX, y+dY), put it at index (dX + R)(2R + 1) + (dY + R) of the
            // pixel array. This will fill the pixel array, with the top left pixel of the window at pixel[0] and the
            // bottom right pixel of the window at pixel[N-1].
            v[(dX + 1) * 3 + (dY + 1)] = MEDIAN2D_FAST3_SAMPLER_FNC(tex, st + offset * radius);
        }
    }
    MEDIAN2D_FAST3_TYPE temp = MEDIAN2D_FAST3_TYPE(0.);
    MEDIAN_MNMX6(0, 1, 2, 3, 4, 5);
    MEDIAN_MNMX5(1, 2, 3, 4, 6);
    MEDIAN_MNMX4(2, 3, 4, 7);
    MEDIAN_MNMX3(3, 4, 8);
    return v[4];
}
#endif

Dependencies:

Use:

median2D_fast3(<SAMPLER_TYPE> texture, <float2> st, <float2> pixel)

Check it on Github



#ifndef MEDIAN2D_FAST3_TYPE
#ifdef MEDIAN2D_TYPE
#define MEDIAN2D_FAST3_TYPE MEDIAN2D_TYPE
#else
#define MEDIAN2D_FAST3_TYPE float4
#endif
#endif

#ifndef MEDIAN2D_FAST3_SAMPLER_FNC
#ifdef MEDIAN_SAMPLER_FNC
#define MEDIAN2D_FAST3_SAMPLER_FNC(TEX, UV) MEDIAN_SAMPLER_FNC(TEX, UV)
#else
#define MEDIAN2D_FAST3_SAMPLER_FNC(TEX, UV) SAMPLER_FNC(TEX, UV)
#endif
#endif

#ifndef MEDIAN_S2
#define MEDIAN_S2(a, b) temp = a; a = min(a, b); b = max(temp, b);
#endif

#ifndef MEDIAN_2
#define MEDIAN_2(a, b) MEDIAN_S2(v[a], v[b]);
#endif

#ifndef FNC_MEDIAN2D_FAST3
#define FNC_MEDIAN2D_FAST3
#define MEDIAN_MN3(a, b, c) MEDIAN_2(a, b); MEDIAN_2(a, c);
#define MEDIAN_MX3(a, b, c) MEDIAN_2(b, c); MEDIAN_2(a, c);
#define MEDIAN_MNMX3(a, b, c) MEDIAN_MX3(a, b, c); MEDIAN_2(a, b);                                                                // 3 exchanges
#define MEDIAN_MNMX4(a, b, c, d) MEDIAN_2(a, b); MEDIAN_2(c, d); MEDIAN_2(a, c); MEDIAN_2(b, d);                                  // 4 exchanges
#define MEDIAN_MNMX5(a, b, c, d, e) MEDIAN_2(a, b); MEDIAN_2(c, d); MEDIAN_MN3(a, c, e); MEDIAN_MX3(b, d, e);                     // 6 exchanges
#define MEDIAN_MNMX6(a, b, c, d, e, f) MEDIAN_2(a, d); MEDIAN_2(b, e); MEDIAN_2(c, f); MEDIAN_MN3(a, b, c); MEDIAN_MX3(d, e, f);  // 7 exchanges
MEDIAN2D_FAST3_TYPE median2D_fast3(in SAMPLER_TYPE tex, in float2 st, in float2 radius) {
    MEDIAN2D_FAST3_TYPE v[9];
    for (int dX = -1; dX <= 1; ++dX) {
        for (int dY = -1; dY <= 1; ++dY) {
            float2 offset = float2(float(dX), float(dY));
            // If a pixel in the window is located at (x+dX, y+dY), put it at index (dX + R)(2R + 1) + (dY + R) of the
            // pixel array. This will fill the pixel array, with the top left pixel of the window at pixel[0] and the
            // bottom right pixel of the window at pixel[N-1].
            v[(dX + 1) * 3 + (dY + 1)] = MEDIAN2D_FAST3_SAMPLER_FNC(tex, st + offset * radius);
        }
    }
    MEDIAN2D_FAST3_TYPE temp = float4(0.0, 0.0, 0.0, 0.0);
    MEDIAN_MNMX6(0, 1, 2, 3, 4, 5);
    MEDIAN_MNMX5(1, 2, 3, 4, 6);
    MEDIAN_MNMX4(2, 3, 4, 7);
    MEDIAN_MNMX3(3, 4, 8);
    return v[4];
}
#endif

Examples

License

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