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 desenfocar, 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 está 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 kernel puede causar una amplia gama de efectos:

Los anteriores son sólo algunos ejemplos de efectos que se pueden lograr mediante la convolución de núcleos e imágenes.

Origen

El origen es la posición del núcleo que está encima (conceptualmente) del píxel de salida actual. Esto podría estar fuera del núcleo real, aunque normalmente corresponde a uno de los elementos del núcleo. Para 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 agregar 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 de matrices tradicional, a pesar de que se denota de manera similar con *.

Por ejemplo, si tenemos dos matrices de tres por tres, la primera un núcleo y la segunda una pieza de imagen, la convolución es el proceso de invertir tanto las filas como las columnas del núcleo y multiplicar 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 la imagen, con pesos dados por el núcleo:

Las otras entradas tendrían una ponderación similar, donde ubicamos 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 del núcleo por los valores de píxel de la imagen de entrada correspondientes. 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 núcleo  en  el núcleo : para cada  elemento  en  la fila del núcleo : si  la posición del elemento corresponde* a la posición del píxel  ,  multiplique  el valor del elemento correspondiente* al valor del píxel  y agregue  el resultado al final del 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 superpondrá los píxeles vecinos alrededor del origen. Cada elemento del núcleo debe multiplicarse por el valor de 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 actualmente superpuesto con el centro del núcleo.

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

La forma general de convolución matricial es

Manejo de bordes

Ampliar el manejo de bordes

La convolución del kernel generalmente requiere valores de píxeles fuera de los límites de la imagen. Existe una variedad de métodos para manejar los bordes de la imagen.

Extender
Los píxeles del 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°. Otros píxeles de los bordes 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 opuesto.
Espejo
La imagen se refleja conceptualmente en los bordes. Por ejemplo, al intentar leer un píxel 3 unidades fuera de un borde, se lee uno 3 unidades dentro del borde.
Recortar/Evitar superposición
Se omite cualquier píxel de la imagen de salida que requiera valores más allá del borde. Este método puede dar como resultado que la imagen de salida sea ligeramente más pequeña y que los bordes se hayan recortado. Mueva el kernel para que nunca se requieran valores fuera de la imagen. El aprendizaje automático utiliza principalmente este enfoque. Ejemplo: tamaño del kernel 10x10, tamaño de imagen 32x32, la imagen resultante es 23x23.
Cultivo de granos
Cualquier píxel del núcleo 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 fuera de la imagen. Generalmente se utiliza negro o, a veces, gris. Generalmente 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 multiplicaciones M × N 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 disminuir significativamente el cálculo al realizar una convolución 1D dos veces en lugar de una convolución 2D. [2]

Implementación

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

// autor: csblo // Trabajo realizado con solo consultar: // https://en.wikipedia.org/wiki/Kernel_(image_processing)/Kernel_(image_processing)// Definir núcleos #definir identidad mat3(0, 0, 0, 0, 1, 0, 0, 0, 0) #definir borde0 mat3(1, 0, -1, 0, 0, 0, -1, 0, 1) #definir borde1 mat3(0, 1, 0, 1, -4, 1, 0, 1, 0) #definir borde2 mat3(-1, -1, -1, -1, 8, -1, -1 , -1, -1) #definir afilar mat3(0, -1, 0, -1, 5, -1, 0, -1, 0) #definir box_blur mat3(1, 1, 1, 1, 1, 1 , 1, 1, 1) * 0.1111 #definir gaussian_blur mat3(1, 2, 1, 2, 4, 2, 1, 2, 1) * 0.0625 #definir relieve mat3(-2, -1, 0, -1, 1, 1, 0, 1, 2)// Encuentra las coordenadas 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 ) ) [ índice ] / iResolution . xy ; }                           // Extrae la región de la dimensión 3x3 del sampler centrado en uv // sampler: sampler de textura // uv: coordenadas actuales en el sampler // return: una matriz de mat3, cada índice correspondiente a un canal de color mat3 [ 3 ] region3x3 ( sampler2D , vec2 uv ) { // Crea cada píxel para la región vec4 [ 9 ] región ; para ( int i = 0 ; i < 9 ; i ++ ) región [ i ] = textura ( muestra , uv + kpos ( i ));                        // Crea una región de 3x3 con 3 canales de color (rojo, verde, azul) mat3 [ 3 ] mRegión ; para ( int i = 0 ; i < 3 ; i ++ ) mRegión [ 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 ] ); devolver mRegión ; }                            // Convoluciona una textura con el kernel // kernel: kernel usado para la convolución // sampler : sampler de textura // uv: coordenadas actuales en la convolución del sampler vec3 ( kernel mat3 , sampler2D , vec2 uv ) { fragmento vec3 ; // Extrae una región de 3x3 centrada en uv mat3 [ 3 ] region = region3x3 ( sampler , uv ); // para cada canal de color de la región for ( int i = 0 ; i < 3 ; i ++ ) { // obtiene el canal de región mat3 rc = región [ i ]; // multiplicación por componentes del 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 fragmento [ i ] = r ; } devolver fragmento ; }                                                                     void mainImage ( out vec4 fragColor , in vec2 fragCoord ) { // Coordenadas de píxeles normalizadas (de 0 a 1) vec2 uv = fragCoord / iResolution . xy ; // Convolución del kernel con textura vec3 col = convolución ( emboss , iChannel0 , uv ); // Salida a la pantalla fragColor = vec4 ( col , 1.0 ); }                          

Ver 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