From f7da3a347d91cd2be207eadb85c8d8f032e1a6c7 Mon Sep 17 00:00:00 2001 From: Bruno Herbelin Date: Sat, 7 May 2022 23:01:17 +0200 Subject: [PATCH] New morphological operators --- CMakeLists.txt | 4 ++++ ImageFilter.cpp | 5 +++++ rsc/shaders/filters/blackhat.glsl | 36 +++++++++++++++++++++++++++++++ rsc/shaders/filters/dilation.glsl | 25 +++++++++++++++++++++ rsc/shaders/filters/erosion.glsl | 25 +++++++++++++++++++++ rsc/shaders/filters/tophat.glsl | 36 +++++++++++++++++++++++++++++++ 6 files changed, 131 insertions(+) create mode 100644 rsc/shaders/filters/blackhat.glsl create mode 100644 rsc/shaders/filters/dilation.glsl create mode 100644 rsc/shaders/filters/erosion.glsl create mode 100644 rsc/shaders/filters/tophat.glsl diff --git a/CMakeLists.txt b/CMakeLists.txt index 5dd81d7..4ec3d88 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -583,6 +583,10 @@ set(VMIX_RSC_FILES ./rsc/shaders/filters/grain.glsl ./rsc/shaders/filters/stippling.glsl ./rsc/shaders/filters/dithering.glsl + ./rsc/shaders/filters/erosion.glsl + ./rsc/shaders/filters/dilation.glsl + ./rsc/shaders/filters/tophat.glsl + ./rsc/shaders/filters/blackhat.glsl ) # Include the CMake RC module diff --git a/ImageFilter.cpp b/ImageFilter.cpp index f1dcdec..ded76d2 100644 --- a/ImageFilter.cpp +++ b/ImageFilter.cpp @@ -99,6 +99,11 @@ std::list< ImageFilter > ImageFilter::presets = { ImageFilter("Pixelate", "shaders/filters/pixelate.glsl", "", { { "Size", 0.5}, { "Sharpen", 0.5} }), ImageFilter("Chromakey","shaders/filters/chromakey.glsl", "", { { "Red", 0.05}, { "Green", 0.63}, { "Blue", 0.14}, { "Tolerance", 0.54} }), ImageFilter("Fisheye", "shaders/filters/fisheye.glsl", "", { { "Factor", 0.5} }), + ImageFilter("Openning", "shaders/filters/erosion.glsl", "shaders/filters/dilation.glsl", { { "Radius", 0.5} }), + ImageFilter("Closing", "shaders/filters/dilation.glsl", "shaders/filters/erosion.glsl", { { "Radius", 0.5} }), + ImageFilter("TopHat", "shaders/filters/erosion.glsl", "shaders/filters/tophat.glsl", { { "Radius", 0.5} }), + ImageFilter("BlackHat", "shaders/filters/dilation.glsl", "shaders/filters/blackhat.glsl", { { "Radius", 0.5} }) + }; diff --git a/rsc/shaders/filters/blackhat.glsl b/rsc/shaders/filters/blackhat.glsl new file mode 100644 index 0000000..213c056 --- /dev/null +++ b/rsc/shaders/filters/blackhat.glsl @@ -0,0 +1,36 @@ +uniform float Radius; +#define MAX_SIZE 5 + +vec3 erosion (sampler2D source, vec2 uv, vec2 uv_step, float R) +{ + vec3 minValue = vec3(1.0); + float D = length(vec2( R / 2.)); + + for (float i=-R; i <= R; ++i) + { + for (float j=-R; j <= R; ++j) + { + vec2 delta = vec2(i, j); + minValue = min(texture(source, uv + delta * smoothstep(R, D, length(delta)) * uv_step ).rgb, minValue); + } + } + + return minValue; +} + +void mainImage( out vec4 fragColor, in vec2 fragCoord ) +{ + vec2 uv = fragCoord.xy / iResolution.xy; + + // blackhat is the difference between the Closing of the input image and the image + // Closing is Dilation (first pass) followed by Erosion (second pass)tion.xy; + + // get original image + vec3 c = texture(iChannel1, uv).rgb; + + // get result of Closing + vec3 e = erosion(iChannel0, uv, 1.0 / iResolution.xy, mix(1., MAX_SIZE, Radius)); + + // composition + fragColor = vec4( c + (c-e), 1.0); +} diff --git a/rsc/shaders/filters/dilation.glsl b/rsc/shaders/filters/dilation.glsl new file mode 100644 index 0000000..d0d095c --- /dev/null +++ b/rsc/shaders/filters/dilation.glsl @@ -0,0 +1,25 @@ +uniform float Radius; +#define MAX_SIZE 5 + +vec3 dilation (sampler2D source, vec2 uv, vec2 uv_step, float R) { + + vec3 maxValue = vec3(0.0); + float D = length(vec2( R / 2.)); + + for (float i=-R; i <= R; ++i) + { + for (float j=-R; j <= R; ++j) + { + vec2 delta = vec2(i, j); + maxValue = max(texture(source, uv + delta * smoothstep(R, D, length(delta)) * uv_step ).rgb, maxValue); + } + } + + return maxValue; +} + +void mainImage( out vec4 fragColor, in vec2 fragCoord ) +{ + vec2 uv = fragCoord.xy / iResolution.xy; + fragColor = vec4( dilation(iChannel0, uv, 1.0 / iResolution.xy, mix(1., MAX_SIZE, Radius)), 1.0); +} diff --git a/rsc/shaders/filters/erosion.glsl b/rsc/shaders/filters/erosion.glsl new file mode 100644 index 0000000..994c1e3 --- /dev/null +++ b/rsc/shaders/filters/erosion.glsl @@ -0,0 +1,25 @@ +uniform float Radius; +#define MAX_SIZE 5 + +vec3 erosion (sampler2D source, vec2 uv, vec2 uv_step, float R) +{ + vec3 minValue = vec3(1.0); + float D = length(vec2( R / 2.)); + + for (float i=-R; i <= R; ++i) + { + for (float j=-R; j <= R; ++j) + { + vec2 delta = vec2(i, j); + minValue = min(texture(source, uv + delta * smoothstep(R, D, length(delta)) * uv_step ).rgb, minValue); + } + } + + return minValue; +} + +void mainImage( out vec4 fragColor, in vec2 fragCoord ) +{ + vec2 uv = fragCoord.xy / iResolution.xy; + fragColor = vec4( erosion(iChannel0, uv, 1.0 / iResolution.xy, mix(1., MAX_SIZE, Radius)), 1.0); +} diff --git a/rsc/shaders/filters/tophat.glsl b/rsc/shaders/filters/tophat.glsl new file mode 100644 index 0000000..0891801 --- /dev/null +++ b/rsc/shaders/filters/tophat.glsl @@ -0,0 +1,36 @@ +uniform float Radius; +#define MAX_SIZE 5 + +vec3 dilation (sampler2D source, vec2 uv, vec2 uv_step, float R) { + + vec3 maxValue = vec3(0.0); + float D = length(vec2( R / 2.)); + + for (float i=-R; i <= R; ++i) + { + for (float j=-R; j <= R; ++j) + { + vec2 delta = vec2(i, j); + maxValue = max(texture(source, uv + delta * smoothstep(R, D, length(delta)) * uv_step ).rgb, maxValue); + } + } + + return maxValue; +} + +void mainImage( out vec4 fragColor, in vec2 fragCoord ) +{ + vec2 uv = fragCoord.xy / iResolution.xy; + + // tophat is the difference between input image and Opening of the input image + // Opening is Erosion (first pass) followed by Dilation (second pass) + + // get original image + vec3 c = texture(iChannel1, uv).rgb; + + // get result of Opening + vec3 d = dilation(iChannel0, uv, 1.0 / iResolution.xy, mix(1., MAX_SIZE, Radius)); + + // composition + fragColor = vec4( c + (c-d), 1.0); +}