stringtranslate.com

Kernel (procesamiento de imágenes)

En el procesamiento de imágenes , un núcleo , una matriz de convolución o una máscara es una pequeña matriz que se utiliza para difuminar, enfocar, realzar, detectar bordes y más. Esto se logra haciendo una convolución entre el núcleo y una imagen . O, más simplemente, cuando cada píxel de la imagen de salida es una función de los píxeles cercanos (incluido él mismo) en la imagen de entrada, el núcleo es esa función.

Detalles

La expresión general de una convolución es

donde es la imagen filtrada, es la imagen original, es el núcleo del filtro. Cada elemento del núcleo del filtro es considerado por y .

Dependiendo de los valores de los elementos, un núcleo puede provocar una amplia gama de efectos:

Los anteriores son solo algunos ejemplos de efectos que se pueden lograr convolucionando núcleos e imágenes.

Origen

El origen es la posición del núcleo que está por encima (conceptualmente) del píxel de salida actual. Puede estar fuera del núcleo real, aunque normalmente corresponde a uno de los elementos del núcleo. En el caso de un núcleo simétrico, el origen suele ser el elemento central.

Circunvolución

Animación de convolución 2D

La convolución es el proceso de sumar cada elemento de la imagen a sus vecinos locales, ponderados por el núcleo. Esto está relacionado con una forma de convolución matemática . La operación matricial que se realiza (convolución) no es una multiplicación matricial tradicional, a pesar de que también se denota con *.

Por ejemplo, si tenemos dos matrices de tres por tres, la primera un núcleo y la segunda un fragmento de imagen, la convolución es el proceso de invertir tanto las filas como las columnas del núcleo y multiplicar las entradas localmente similares y sumar. El elemento en las coordenadas [2, 2] (es decir, el elemento central) de la imagen resultante sería una combinación ponderada de todas las entradas de la matriz de imagen, con pesos dados por el núcleo:

Las otras entradas tendrían una ponderación similar, donde posicionamos el centro del núcleo en cada uno de los puntos límite de la imagen y calculamos una suma ponderada.

Los valores de un píxel determinado en la imagen de salida se calculan multiplicando cada valor de kernel por los valores de píxel correspondientes de la imagen de entrada. Esto se puede describir algorítmicamente con el siguiente pseudocódigo:

para cada  fila de imagen  en  la imagen de entrada : para cada  píxel  en  la fila de imagen : Poner  el acumulador a cero para cada  fila del kernel  en  el kernel : para cada  elemento  en  la fila del kernel : Si  la posición del elemento corresponde* a la posición del píxel  , entonces  multiplica  el valor del elemento correspondiente* al valor del píxel  y suma  el resultado al acumulador  . Establecer  el píxel de la imagen de salida en el acumulador
*Los píxeles de la imagen de entrada correspondientes se encuentran en relación con el origen del núcleo.

Si el núcleo es simétrico, coloque el centro (origen) del núcleo en el píxel actual. El núcleo se superpondrá a los píxeles vecinos alrededor del origen. Cada elemento del núcleo debe multiplicarse por el valor del píxel con el que se superpone y todos los valores obtenidos deben sumarse. Esta suma resultante será el nuevo valor para el píxel actual que se superpone actualmente con el centro del núcleo.

Si el núcleo no es simétrico, debe invertirse tanto alrededor de su eje horizontal como de su eje vertical antes de calcular la convolución como se indicó anteriormente. [1]

La forma general para la convolución matricial es

Manejo de bordes

Ampliar el manejo de bordes

La convolución del núcleo generalmente requiere valores de píxeles fuera de los límites de la imagen. Existen diversos métodos para manejar los bordes de la imagen.

Extender
Los píxeles de borde más cercanos se extienden conceptualmente tanto como sea necesario para proporcionar valores para la convolución. Los píxeles de las esquinas se extienden en cuñas de 90°. Los demás píxeles de borde se extienden en líneas.
Envoltura
La imagen se envuelve conceptualmente (o se coloca en mosaico) y los valores se toman del borde o esquina opuestos.
Espejo
La imagen se refleja conceptualmente en los bordes. Por ejemplo, si se intenta leer un píxel que se encuentra 3 unidades fuera de un borde, se lee uno que se encuentra 3 unidades dentro del borde.
Recortar / Evitar superposiciones
Se omite cualquier píxel de la imagen de salida que requiera valores que estén más allá del borde. Este método puede hacer que la imagen de salida sea ligeramente más pequeña y que los bordes se hayan recortado. Mueva el kernel de modo que nunca se requieran valores que estén fuera de la imagen. El aprendizaje automático utiliza principalmente este enfoque. Ejemplo: tamaño del kernel 10x10, tamaño de la imagen 32x32, la imagen resultante es 23x23.
Cosecha de granos
Cualquier píxel del kernel que se extienda más allá de la imagen de entrada no se utiliza y la normalización se ajusta para compensar.
Constante
Utilice un valor constante para los píxeles que se encuentran fuera de la imagen. Normalmente se utiliza el color negro o, a veces, el gris. Por lo general, esto depende de la aplicación.

Normalización

La normalización se define como la división de cada elemento del núcleo por la suma de todos los elementos del núcleo, de modo que la suma de los elementos de un núcleo normalizado sea la unidad. Esto garantizará que el píxel promedio de la imagen modificada sea tan brillante como el píxel promedio de la imagen original.

Mejoramiento

Los algoritmos de convolución rápida incluyen:

Convolución separable

La convolución 2D con un núcleo M × N requiere M × N multiplicaciones para cada muestra (píxel). Si el núcleo es separable, entonces el cálculo se puede reducir a M + N multiplicaciones. El uso de convoluciones separables puede reducir significativamente el cálculo al realizar la convolución 1D dos veces en lugar de una convolución 2D. [2]

Implementación

Aquí se muestra una implementación de convolución concreta realizada con el lenguaje de sombreado GLSL :

// autor: csblo // Trabajo realizado simplemente consultando: // https://en.wikipedia.org/wiki/Kernel_(image_processing)/Kernel_(image_processing)// Definir núcleos #define identidad mat3(0, 0, 0, 0, 1, 0, 0, 0, 0) #define arista0 mat3(1, 0, -1, 0, 0, 0, -1, 0, 1) #define arista1 mat3(0, 1, 0, 1, -4, 1, 0, 1, 0) #define arista2 mat3(-1, -1, -1, -1, 8, -1, -1, -1, -1) #define nitidez mat3(0, -1, 0, -1, 5, -1, 0, -1, 0) #define desenfoque de caja mat3(1, 1, 1, 1, 1, 1, 1, 1, 1) * 0.1111 #define desenfoque gaussiano mat3(1, 2, 1, 2, 4, 2, 1, 2, 1) * 0.0625 #define el tapete de relieve3(-2, -1, 0, -1, 1, 1, 0, 1, 2)// Encuentra la coordenada del elemento de la matriz a partir del índice vec2 kpos ( int index ) { return vec2 [ 9 ] ( vec2 ( - 1 , - 1 ), vec2 ( 0 , - 1 ), vec2 ( 1 , - 1 ) , vec2 ( - 1 , 0 ), vec2 ( 0 , 0 ), vec2 ( 1 , 0 ), vec2 ( - 1 , 1 ), vec2 ( 0 , 1 ), vec2 ( 1 , 1 ) )[ index ] / iResolution . xy ; }                           // Extrae la región de dimensión 3x3 del sampler centrado en uv // sampler: muestreador de textura // uv: coordenadas actuales en el sampler // retorna: una matriz de mat3, cada índice corresponde a un canal de color mat3 [ 3 ] region3x3 ( sampler2D sampler , vec2 uv ) { // Crea cada píxel para la región vec4 [ 9 ] region ; for ( int i = 0 ; i < 9 ; i ++ ) region [ i ] = texture ( sampler , uv + kpos ( i ));                        // Crea una región 3x3 con 3 canales de color (rojo, verde, azul) mat3 [ 3 ] mRegion ; for ( int i = 0 ; i < 3 ; i ++ ) mRegion [ i ] = mat3 ( región [ 0 ][ i ], región [ 1 ][ i ], región [ 2 ][ i ], región [ 3 ][ i ], región [ 4 ][ i ], región [ 5 ][ i ], región [ 6 ][ i ], región [ 7 ][ i ], región [ 8 ][ i ] ); return mRegion ; }                            // Convolucionar una textura con kernel // kernel: kernel usado para convolución // sampler: muestreador de textura // uv: coordenadas actuales en el muestreador vec3 convolution ( mat3 kernel , sampler2D sampler , vec2 uv ) { vec3 fragment ; // Extraer una región 3x3 centrada en uv mat3 [ 3 ] region = region3x3 ( sampler , uv ); // para cada canal de color de region for ( int i = 0 ; i < 3 ; i ++ ) { // obtener el canal de región mat3 rc = region [ i ]; // multiplicación componente por componente de kernel por canal de región mat3 c = matrixCompMult ( kernel , rc ); // suma cada componente de la matriz float r = c [ 0 ][ 0 ] + c [ 1 ][ 0 ] + c [ 2 ][ 0 ] + c [ 0 ][ 1 ] + c [ 1 ][ 1 ] + c [ 2 ][ 1 ] + c [ 0 ][ 2 ] + c [ 1 ][ 2 ] + c [ 2 ][ 2 ]; // para el fragmento en el canal i, establece el resultado fragment [ i ] = r ; } return fragment ; }                                                                     void mainImage ( out vec4 fragColor , in vec2 fragCoord ) { // Coordenadas de píxeles normalizadas (de 0 a 1) vec2 uv = fragCoord / iResolution.xy ; // Núcleo de convolución con textura vec3 col = convolution ( emboss , iChannel0 , uv ); // Salida a pantalla fragColor = vec4 ( col , 1.0 ); }                          

Véase también

Referencias

  1. ^ "Ejemplo de convolución 2D".
  2. ^ "Convolución". www.songho.ca . Consultado el 19 de noviembre de 2022 .

Fuentes

Enlaces externos