lygia
/v1.1.6
/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.
Other examples https://www.shadertoy.com/view/4dfGDH , https://www.shadertoy.com/view/XtVGWG
Dependencies:
lygia
/v1.1.6
/math
/gaussian
.glsl
lygia
/v1.1.6
/color
/space
/rgb2luma
.glsl
lygia
/v1.1.6
/sample
/clamp2edge
.glsl
Use:
bilateral(<SAMPLER_TYPE> texture, <vec2> st, <vec2> duv [, <int> kernelSize]])
#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:
lygia
/v1.1.6
/math
/gaussian
.glsl
lygia
/v1.1.6
/sample
/clamp2edge
.glsl
lygia
/v1.1.6
/color
/space
/rgb2luma
.glsl
Use:
bilateral(<SAMPLER_TYPE> texture, <float2> st, <float2> duv)
#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
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.
Sign up for the news letter bellow, joing the LYGIA's channel on Discord or follow the Github repository