Para implementar un filtro de estilo de pintura al óleo, realizamos un proceso de filtrado llamado «filtro kuwahara».

¿Qué es el filtro kuwahara?

El filtro de Kuwahara es un filtro de suavizado no lineal utilizado en el procesamiento de imágenes para la reducción de ruido adaptativo. El filtro puede aplicar suavizado en la imagen mientras conserva los bordes.

Fue diseñado por un profesor universitario llamado Michiyoshi Kuwahara.

Wikipedia

 

Procedimiento del algoritmo:

① Divide la periferia de cada píxel en cuatro áreas.

② Calcula la variación en cada área.

③ Encuentra la región con la variación más pequeña entre las cuatro regiones.

④ Aplicar el valor promedio del área al color central.

 

Contenido del filtro de Kuwabara

Se describe brevemente como un filtro en el que el color de cada píxel, es el color promedio de la región con la menor suma de variaciones en las regiones aledañas de la esquina superior izquierda, superior derecha, inferior izquierda e inferior derecha de cualquier ancho a su alrededor.

En la imagen de arriba, para determinar el color del píxel central,

  1. Calcula la variación  del área de ab ,  cd para cada color RGB, y agrega todos los RGB para cada área.
  2. Compara las variaciones obtenidas en 1. y calcula el promedio de los colores en el área más pequeña para cada RGB.
  3. Establece el color promedio obtenido en 2. como el color del píxel central.

 

Código glsl:

 
uniform vec2 iResolution;
uniform int radius;
uniform vec2 uv;

out vec4 fragColor; 
in vec2 fragCoord;

 void main() 
 {
	 vec2 src_size = vec2 (1.0 / iResolution.x, 1.0 / iResolution.y);
     vec2 uv = gl_FragCoord.xy/iResolution.xy;
     float n = float((radius + 1) * (radius + 1));
     int i; 
	 int j;
     vec3 m0 = vec3(0.0); vec3 m1 = vec3(0.0); vec3 m2 = vec3(0.0); vec3 m3 = vec3(0.0);
     vec3 s0 = vec3(0.0); vec3 s1 = vec3(0.0); vec3 s2 = vec3(0.0); vec3 s3 = vec3(0.0);
     vec3 c;

     for (int j = -radius; j <= 0; ++j)  {
         for (int i = -radius; i <= 0; ++i)  {
             c = texture(sTD2DInputs[0], uv + vec2(i,j) * src_size).rgb;
             m0 += c;
             s0 += c * c;
         }
     }

     for (int j = -radius; j <= 0; ++j)  {
         for (int i = 0; i <= radius; ++i)  {
             c = texture(sTD2DInputs[0], uv + vec2(i,j) * src_size).rgb;
             m1 += c;
             s1 += c * c;
         }
     }

     for (int j = 0; j <= radius; ++j)  {
         for (int i = 0; i <= radius; ++i)  {
             c = texture(sTD2DInputs[0], uv + vec2(i,j) * src_size).rgb;
             m2 += c;
             s2 += c * c;
         }
     }

     for (int j = 0; j <= radius; ++j)  {
         for (int i = -radius; i <= 0; ++i)  {
             c = texture(sTD2DInputs[0], uv + vec2(i,j) * src_size).rgb;
             m3 += c;
             s3 += c * c;
         }
     }


     float min_sigma2 = 1e+2;
     m0 /= n;
     s0 = abs(s0 / n - m0 * m0);

     float sigma2 = s0.r + s0.g + s0.b;
     if (sigma2 < min_sigma2) {
         min_sigma2 = sigma2;
         fragColor = vec4(m0, 1.0);
     }

     m1 /= n;
     s1 = abs(s1 / n - m1 * m1);

     sigma2 = s1.r + s1.g + s1.b;
     if (sigma2 < min_sigma2) {
         min_sigma2 = sigma2;
         fragColor = vec4(m1, 1.0);
     }

     m2 /= n;
     s2 = abs(s2 / n - m2 * m2);

     sigma2 = s2.r + s2.g + s2.b;
     if (sigma2 < min_sigma2) {
         min_sigma2 = sigma2;
         fragColor = vec4(m2, 1.0);
     }

     m3 /= n;
     s3 = abs(s3 / n - m3 * m3);

     sigma2 = s3.r + s3.g + s3.b;
     if (sigma2 < min_sigma2) {
         min_sigma2 = sigma2;
         fragColor = vec4(m3, 1.0);
     }
 }

 

Vamos a copiar el codigo glsl, y colocarlo dentro de Touchdesigner, para ejecutarlo vamos a usar el GLSL Top

Debemos editar el contenido del Dat glsl1_pixel, vamos a eliminar todo el codigo y remplazarlo por el que copiamos.

 

Debemos agregar las variables iResolution, radius y uv, para quitar la advertencia (Warning)

Colocamos las variables en la pestaña Vectors de nuestro operador glsl

Le agregue una pequeña interfaz de control utilizando un slider, para controlar el parámetro radius.

 

 

 

Para aquellos que quieran probarlo fácilmente

Ejecute el Script en colab. Kuwahara_Demo.ipynb
Ingrese la URL de la imagen que desea editar.

También hay un ejemplo en ShaderToy

Referencias:

https://en.wikipedia.org/wiki/Kuwahara_filter

https://qiita.com/Cartelet/items/5c1c012c132be3aa9608

https://qiita.com/ASaYaO/items/181b51c2a575410d6fcc

 

Share this: