Quiero desenfocar mi imagen usando la fórmula nativa de desenfoque gaussiano. Yo leo el artículo de wikipediapero no estoy seguro de cómo implementar esto.
¿Cómo uso la fórmula para decidir los pesos?
No quiero usar ninguna función integrada como la que tiene MATLAB
Escribir un desenfoque gaussiano ingenuo es bastante fácil. Se hace exactamente de la misma manera que cualquier otro filtro de convolución. La única diferencia entre una caja y un filtro gaussiano es la matriz que utiliza.
Imagina que tienes una imagen definida de la siguiente manera:
0 1 2 3 4 5 6 7 8 9
10 11 12 13 14 15 16 17 18 19
20 21 22 23 24 25 26 27 28 29
30 31 32 33 34 35 36 37 38 39
40 41 42 43 44 45 46 47 48 49
50 51 52 53 54 55 56 57 58 59
60 61 62 63 64 65 66 67 68 69
70 71 72 73 74 75 76 77 78 79
80 81 82 83 84 85 86 87 88 89
90 91 92 93 94 95 96 97 98 99
Una matriz de filtro de caja de 3×3 se define de la siguiente manera:
0.111 0.111 0.111
0.111 0.111 0.111
0.111 0.111 0.111
Para aplicar el desenfoque gaussiano, haría lo siguiente:
Para el píxel 11, deberá cargar los píxeles 0, 1, 2, 10, 11, 12, 20, 21, 22.
luego multiplicaría el píxel 0 por la parte superior izquierda del filtro de desenfoque de 3×3. El píxel 1 por la parte superior central, el píxel 2, el píxel 3 por la parte superior derecha, el píxel 10 por la parte central izquierda y así sucesivamente.
Luego, agréguelos por completo y escriba el resultado en el píxel 11. Como puede ver, el píxel 11 ahora es el promedio de sí mismo y de los píxeles circundantes.
Los casos extremos se vuelven un poco más complejos. ¿Qué valores usas para los valores del borde de la textura? Una forma puede ser envolver al otro lado. Esto se ve bien para una imagen que luego se coloca en mosaico. Otra forma es empujar el píxel hacia los lugares circundantes.
Entonces, para la parte superior izquierda, puede colocar las muestras de la siguiente manera:
0 0 1
0 0 1
10 10 11
Espero que pueda ver cómo esto se puede extender fácilmente a núcleos de filtro grandes (es decir, 5×5 o 9×9, etc.).
La diferencia entre un filtro gaussiano y un filtro de caja son los números que van en la matriz. Un filtro gaussiano utiliza una distribución gaussiana en una fila y una columna.
por ejemplo, para un filtro definido arbitrariamente como (es decir, esto no es gaussiano, pero probablemente no esté muy lejos)
0.1 0.8 0.1
la primera columna sería la misma pero multiplicada por el primer elemento de la fila de arriba.
0.01 0.8 0.1
0.08
0.01
La segunda columna sería la misma pero los valores se multiplicarían por el 0,8 de la fila de arriba (y así sucesivamente).
0.01 0.08 0.01
0.08 0.64 0.08
0.01 0.08 0.01
El resultado de sumar todo lo anterior debe ser igual a 1. La diferencia entre el filtro anterior y el filtro de cuadro original sería que el píxel final escrito tendría una ponderación mucho mayor hacia el píxel central (es decir, el que está en esa posición). ya). El desenfoque ocurre porque los píxeles circundantes se desdibujan en ese píxel, aunque no tanto. Usando este tipo de filtro obtienes un desenfoque pero uno que no destruye la mayor parte de la información de alta frecuencia (es decir, el cambio rápido de color de píxel a píxel).
Este tipo de filtros pueden hacer muchas cosas interesantes. Puede hacer una detección de bordes usando este tipo de filtro restando los píxeles circundantes del píxel actual. Esto dejará atrás solo los cambios realmente grandes en el color (altas frecuencias).
Editar: un kernel de filtro 5×5 se define exactamente como se indica arriba.
por ejemplo, si su fila es 0.1 0.2 0.4 0.2 0.1 entonces si multiplica cada valor en su por el primer elemento para formar una columna y luego multiplica cada uno por el segundo elemento para formar la segunda columna y así sucesivamente, terminará con un filtro de
0.01 0.02 0.04 0.02 0.01
0.02 0.04 0.08 0.04 0.02
0.04 0.08 0.16 0.08 0.04
0.02 0.04 0.08 0.04 0.02
0.01 0.02 0.04 0.02 0.01
tomando algunas posiciones arbitrarias, puede ver que la posición 0, 0 es simple 0.1 * 0.1. La posición 0, 2 es 0,1 * 0,4, la posición 2, 2 es 0,4 * 0,4 y la posición 1, 2 es 0,2 * 0,4.
Espero que eso te dé una buena explicación.
Aquí está el pseudocódigo del código que usé en C# para calcular el núcleo. Sin embargo, no me atrevo a decir que trato las condiciones finales correctamente:
double[] kernel = new double[radius * 2 + 1];
double twoRadiusSquaredRecip = 1.0 / (2.0 * radius * radius);
double sqrtTwoPiTimesRadiusRecip = 1.0 / (sqrt(2.0 * Math.PI) * radius);
double radiusModifier = 1.0;
int r = -radius;
for (int i = 0; i < kernel.Length; i++)
{
double x = r * radiusModifier;
x *= x;
kernel[i] = sqrtTwoPiTimesRadiusRecip * Exp(-x * twoRadiusSquaredRecip);
r++;
}
double div = Sum(kernel);
for (int i = 0; i < kernel.Length; i++)
{
kernel[i] /= div;
}
Espero que esto ayude.
Para usar el kernel de filtro discutido en el artículo de Wikipedia, debe implementar (discreto) circunvolución. La idea es que tenga una pequeña matriz de valores (el núcleo), mueva este núcleo de píxel a píxel en la imagen (es decir, de modo que el centro de la matriz esté en el píxel), multiplique los elementos de la matriz con la imagen superpuesta elementos, sume todos los valores en el resultado y reemplace el valor de píxel anterior con esta suma.
El desenfoque gaussiano se puede separar en dos circunvoluciones 1D (una vertical y otra horizontal) en lugar de una convolución 2D, lo que también acelera un poco las cosas.
No tengo claro si quieres restringir esto. para ciertas tecnologías, pero si no SVG (gráficos vectoriales escalables) tiene una implementación de Gaussian Blur. Creo que se aplica a todas las primitivas, incluidos los píxeles. SVG tiene la ventaja de ser un estándar abierto y ampliamente implementado.
Bueno, Gaussian Kernel es un kernel separable.
Por lo tanto, todo lo que necesita es una función que admita convolución 2D separable como: ImageConvolutionSeparableKernel()
.
Una vez que lo tenga, todo lo que necesita es un contenedor para generar el kernel gaussiano 1D y enviarlo a la función como se hizo en ImageConvolutionGaussianKernel()
.
El código es una implementación en C directa de 2D Image Convolution acelerada por SIMD (SSE) y Multi Threading (OpenMP).
Todo el proyecto está dado por – Convolución de imágenes – GitHub.
básicamente necesitas implementar un operador de convolución equivalente al conv2() función en MATLAB. Sin embargo, dado que 2D Gaussian se puede separar en dos 1D Gaussian, todo lo que necesita es una implementación de la función de convolución en 1D, junto con la matriz kernel correcta.
– Amro
8 de noviembre de 2009 a las 12:13