En este post, aprenderemos los detalles del descriptor de características del Histograma de Gradientes Orientados (HOG). Aprenderemos qué hay debajo del capó y cómo se calcula internamente este descriptor mediante OpenCV, MATLAB y otros paquetes.
Este post es parte de una serie que estoy escribiendo sobre Reconocimiento de Imágenes y Detección de Objetos.
La lista completa de tutoriales de esta serie se muestra a continuación:
- Reconocimiento de imágenes mediante técnicas tradicionales de Visión por ordenador : Parte 1
- Histograma de Gradientes Orientados : Parte 2
- Código de ejemplo para el reconocimiento de imágenes : Parte 3
- Entrenamiento de un mejor detector de ojos: Parte 4a
- Detección de objetos mediante técnicas tradicionales de Visión por computadora : Parte 4b
- Cómo entrenar y probar su propio detector de objetos OpenCV : Parte 5
- Reconocimiento de imágenes mediante Aprendizaje profundo : Parte 6
- Introducción a las Redes Neuronales
- Comprensión de las Redes Neuronales de Alimentación
- Reconocimiento de Imágenes mediante Redes Neuronales Convolucionales
- Detección de objetos mediante Aprendizaje profundo: Parte 7
Muchas cosas parecen difíciles y misteriosas. Pero una vez que te tomas el tiempo para deconstruirlos, el misterio es reemplazado por la maestría y eso es lo que buscamos. Si usted es un principiante y está encontrando la Visión artificial difícil y misteriosa, solo recuerde lo siguiente
P: ¿Cómo se come un elefante ?
A : ¡Un bocado a la vez!
- ¿Qué es un descriptor de características?
- ¿Cómo calcular el Histograma de Gradientes Orientados ?
- Paso 1 : Preprocesamiento
- Paso 2: Calcular las imágenes de Gradiente
- Paso 3: Calcular el Histograma de Gradientes en celdas de 8×8
- Paso 4 : Normalización de bloques de 16×16
- Paso 5: Calcular el vector de entidad de CERDO
- Visualización de Histograma de Gradientes Orientados
- Suscribirse & Código de descarga
¿Qué es un descriptor de características?
Un descriptor de entidad es una representación de una imagen o un parche de imagen que simplifica la imagen extrayendo información útil y desechando información extraña.
Normalmente, un descriptor de entidad convierte una imagen de tamaño ancho x alto x 3 (canales ) en un vector de entidad / matriz de longitud n. En el caso del descriptor de entidad HOG, la imagen de entrada es de tamaño 64 x 128 x 3 y el vector de entidad de salida es de longitud 3780.
Tenga en cuenta que el descriptor de CERDO se puede calcular para otros tamaños, pero en este post me atengo a los números presentados en el artículo original para que pueda comprender fácilmente el concepto con un ejemplo concreto.
todo Esto suena bien, pero ¿qué es «útil» y lo «extraño» ? Para definir «útil», necesitamos saber para qué es» útil». Claramente, el vector de características no es útil para el propósito de ver la imagen. Sin embargo, es muy útil para tareas como el reconocimiento de imágenes y la detección de objetos. El vector de características producido por estos algoritmos cuando se introduce en una clasificación de imágenes los algoritmos como Support Vector Machine (SVM) producen buenos resultados.
Pero, ¿qué tipos de «características» son útiles para las tareas de clasificación ? Discutamos este punto usando un ejemplo. Supongamos que queremos construir un detector de objetos que detecte botones de camisas y abrigos.
Un botón es circular (puede verse elíptico en una imagen) y generalmente tiene algunos agujeros para coser. Puede ejecutar un detector de bordes en la imagen de un botón y saber fácilmente si se trata de un botón con solo mirar la imagen de borde. En este caso, la información de bordes es «útil» y la información de color no lo es. Además, las características también deben tener poder discriminativo. Por ejemplo, las buenas características extraídas de una imagen deben ser capaces de distinguir entre botones y otros objetos circulares, como monedas y neumáticos de automóvil.
En el descriptor de entidad HOG, la distribución ( histogramas ) de direcciones de gradientes ( gradientes orientados ) se utilizan como entidades. Los degradados ( derivados x e y ) de una imagen son útiles porque la magnitud de los degradados es grande alrededor de bordes y esquinas (regiones de cambios bruscos de intensidad ) y sabemos que los bordes y esquinas contienen mucha más información sobre la forma del objeto que las regiones planas.
¿Cómo calcular el Histograma de Gradientes Orientados ?
En esta sección, entraremos en los detalles del cálculo del descriptor de características HOG. Para ilustrar cada paso, usaremos un parche de una imagen.
Paso 1 : Preprocesamiento
Como se mencionó anteriormente, el descriptor de características HOG utilizado para la detección de peatones se calcula en un parche de 64×128 de una imagen. Por supuesto, una imagen puede ser de cualquier tamaño. Por lo general, los parches a múltiples escalas se analizan en muchas ubicaciones de imágenes. La única restricción es que los parches que se analizan tienen una relación de aspecto fija. En nuestro caso, los parches deben tener una relación de aspecto de 1: 2. Por ejemplo, pueden ser 100×200, 128×256 o 1000×2000, pero no 101×205.
Para ilustrar este punto, he mostrado una imagen grande de tamaño 720×475. Hemos seleccionado un parche de tamaño 100×200 para calcular nuestro descriptor de características de CERDO. Este parche se recorta de una imagen y se cambia de tamaño a 64×128. Ahora estamos listos para calcular el descriptor HOG para este parche de imagen.
El artículo de Dalal y Triggs también menciona la corrección gamma como un paso de preprocesamiento, pero las ganancias de rendimiento son menores y, por lo tanto, estamos omitiendo el paso.
Paso 2: Calcular las imágenes de Gradiente
Para calcular un descriptor de CERDO, primero debemos calcular los gradientes horizontales y verticales; después de todo, queremos calcular el histograma de gradientes. Esto se logra fácilmente filtrando la imagen con los siguientes núcleos.
También podemos lograr los mismos resultados, utilizando el operador Sobel en OpenCV con tamaño de núcleo 1.
// C++ gradient calculation.// Read imageMat img = imread("bolt.png");img.convertTo(img, CV_32F, 1/255.0);// Calculate gradients gx, gyMat gx, gy;Sobel(img, gx, CV_32F, 1, 0, 1);Sobel(img, gy, CV_32F, 0, 1, 1);
# Python gradient calculation # Read imageim = cv2.imread('bolt.png')im = np.float32(im) / 255.0# Calculate gradientgx = cv2.Sobel(img, cv2.CV_32F, 1, 0, ksize=1)gy = cv2.Sobel(img, cv2.CV_32F, 0, 1, ksize=1)
A continuación, podemos encontrar la magnitud y la dirección del gradiente utilizando la siguiente fórmula
Si está utilizando OpenCV, el cálculo se puede hacer utilizando la función cartToPolar como se muestra a continuación.
// C++ Calculate gradient magnitude and direction (in degrees)Mat mag, angle;cartToPolar(gx, gy, mag, angle, 1);
El mismo código en python se ve así.
# Python Calculate gradient magnitude and direction ( in degrees )mag, angle = cv2.cartToPolar(gx, gy, angleInDegrees=True)
La siguiente figura muestra los degradados.
Observe que el gradiente x se dispara en líneas verticales y el gradiente y se dispara en líneas horizontales. La magnitud de los incendios en gradiente donde siempre hay un cambio brusco en la intensidad. Ninguno de ellos dispara cuando la región es suave. He omitido deliberadamente la imagen que muestra la dirección del degradado porque la dirección que se muestra como imagen no transmite mucho.
La imagen degradada eliminó una gran cantidad de información no esencial ( por ejemplo, fondo de color constante), pero resaltó los contornos. En otras palabras, puede mirar la imagen degradada y aún así decir fácilmente que hay una persona en la imagen.
En cada píxel, el gradiente tiene una magnitud y una dirección. Para las imágenes en color, se evalúan los degradados de los tres canales (como se muestra en la figura anterior ). La magnitud del gradiente en un píxel es el máximo de la magnitud de los gradientes de los tres canales, y el ángulo es el ángulo correspondiente al gradiente máximo.
Paso 3: Calcular el Histograma de Gradientes en celdas de 8×8
En este paso, la imagen se divide en celdas de 8×8 y se calcula un histograma de degradados para cada celda de 8×8.
Aprenderemos sobre los histogramas en un momento, pero antes de ir allí, primero entendamos por qué hemos dividido la imagen en celdas de 8×8. Una de las razones importantes para usar un descriptor de características para describir un parche de una imagen es que proporciona una representación compacta. Un parche de imagen de 8×8 contiene valores de 8x8x3 = 192 píxeles. El gradiente de este parche contiene 2 valores (magnitud y dirección ) por píxel que suman 8x8x2 = 128 números.
Al final de esta sección veremos cómo se representan estos 128 números utilizando un histograma de 9 bin que se puede almacenar como una matriz de 9 números. No solo la representación es más compacta, el cálculo de un histograma sobre un parche hace que esta representación sea más robusta al ruido. Los graidents individuales pueden tener ruido, pero un parche de histograma de más de 8×8 hace que la representación sea mucho menos sensible al ruido.
Pero, ¿por qué parche de 8×8 ? ¿Por qué no 32×32 ? Es una elección de diseño informada por la escala de características que estamos buscando. HOG se utilizó inicialmente para la detección de peatones. las celdas de 8×8 en una foto de un peatón a una escala de 64×128 son lo suficientemente grandes como para capturar características interesantes ( por ejemplo, la cara, la parte superior de la cabeza, etc.). ).
El histograma es esencialmente un vector ( o una matriz) de 9 contenedores (números ) correspondientes a ángulos 0, 20, 40, 60 … 160.
Veamos un parche de 8×8 en la imagen y veamos cómo se ven los degradados.
Si eres un principiante en visión artificial, la imagen en el centro es muy informativa. Muestra el parche de la imagen superpuesto con flechas que muestran el gradiente: la flecha muestra la dirección del gradiente y su longitud muestra la magnitud. Observe cómo la dirección de las flechas apunta a la dirección del cambio de intensidad y la magnitud muestra cuán grande es la diferencia.
A la derecha, vemos los números sin procesar que representan los gradientes en las celdas de 8×8 con una diferencia menor: los ángulos están entre 0 y 180 grados en lugar de 0 a 360 grados. Estos se llaman gradientes «sin signo» porque un gradiente y su negativo están representados por los mismos números. En otras palabras, una flecha de gradiente y la de 180 grados opuesta a ella se consideran iguales. Pero, ¿por qué no usar los grados 0-360 ?
Empíricamente se ha demostrado que los gradientes sin signo funcionan mejor que los gradientes con signo para la detección de peatones. Algunas implementaciones de HOG le permitirán especificar si desea usar degradados firmados.
El siguiente paso es crear un histograma de degradados en estas celdas de 8×8. El histograma contiene 9 contenedores correspondientes a ángulos 0, 20 , 40 1 160. La siguiente figura ilustra el proceso. Estamos viendo la magnitud y dirección del gradiente del mismo parche de 8×8 que en la figura anterior.
Se selecciona un contenedor en función de la dirección, y el voto ( el valor que entra en el contenedor ) se selecciona en función de la magnitud. Centrémonos primero en el píxel rodeado de azul. Tiene un ángulo (dirección ) de 80 grados y una magnitud de 2. Por lo que añade 2 a la 5ta papelera. El gradiente en el píxel rodeado con rojo tiene un ángulo de 10 grados y una magnitud de 4. Dado que 10 grados está a mitad de camino entre 0 y 20, el voto por píxel se divide uniformemente en los dos contenedores.
Hay un detalle a tener en cuenta. Si el ángulo es mayor de 160 grados, está entre 160 y 180, y sabemos que el ángulo se envuelve alrededor, lo que equivale a 0 y 180. En el ejemplo siguiente, el píxel con ángulo de 165 grados contribuye proporcionalmente a la bandeja de 0 grados y a la de 160 grados.
Las contribuciones de todos los píxeles de las celdas de 8×8 se suman para crear el histograma de 9 bin. Para el parche de arriba, se ve así
En nuestra representación, el eje y es 0 grados. Puede ver que el histograma tiene mucho peso cerca de 0 y 180 grados, que es solo otra forma de decir que en el parche los gradientes apuntan hacia arriba o hacia abajo.
Paso 4 : Normalización de bloques de 16×16
En el paso anterior, creamos un histograma basado en el degradado de la imagen. Los degradados de una imagen son sensibles a la iluminación general. Si oscurece la imagen dividiendo todos los valores de píxeles por 2, la magnitud del gradiente cambiará a la mitad y, por lo tanto, los valores del histograma cambiarán a la mitad.
Idealmente, queremos que nuestro descriptor sea independiente de las variaciones de iluminación. En otras palabras, nos gustaría «normalizar» el histograma para que no se vean afectados por las variaciones de iluminación.
Antes de explicar cómo se normaliza el histograma, veamos cómo se normaliza un vector de longitud 3.
Digamos que tenemos un vector de color RGB . La longitud de este vector es \ \ sqrt{128^2 + 64^2 + 32^2} = 146.64$. Esto también se llama la norma L2 del vector. Dividir cada elemento de este vector por 146,64 nos da un vector normalizado .
Ahora considere otro vector en el que los elementos son el doble del valor del primer vector 2 x = . Puede resolverlo usted mismo para ver que resultará en la normalización, que es la misma que la versión normalizada del vector RGB original. Puede ver que la normalización de un vector elimina la escala.
Ahora que sabemos cómo normalizar un vector, puede sentirse tentado a pensar que al calcular HOG, simplemente puede normalizar el histograma 9×1 de la misma manera que normalizamos el vector 3×1 anterior. No es una mala idea, pero una mejor idea es normalizar sobre un bloque de mayor tamaño de 16×16.
Un bloque de 16×16 tiene 4 histogramas que se pueden concatenar para formar un vector de elemento de 36 x 1 y se puede normalizar de la misma manera que se normaliza un vector de 3×1. La ventana se mueve entonces por 8 píxeles (ver animación) y se calcula un vector normalizado de 36×1 sobre esta ventana y se repite el proceso.
Paso 5: Calcular el vector de entidad de CERDO
Para calcular el vector de entidad final para todo el parche de imagen, los vectores de 36×1 se concatenan en un vector gigante. ¿Cuál es el tamaño de este vector ? Calculemos
- ¿Cuántas posiciones de los bloques de 16×16 tenemos ? Hay 7 posiciones horizontales y 15 verticales, lo que hace un total de 7 x 15 = 105 posiciones.
- Cada bloque de 16×16 está representado por un vector de 36×1. Así que cuando los concatenamos todos en un vector de gaint obtenemos un vector dimensional de 36×105 = 3780.
Visualización de Histograma de Gradientes Orientados
El descriptor HOG de un parche de imagen generalmente se visualiza trazando los histogramas normalizados de 9×1 en las células de 8×8. Ver imagen en el lateral. Notarás que la dirección dominante del histograma captura la forma de la persona, especialmente alrededor del torso y las piernas.
Desafortunadamente, no hay una forma fácil de visualizar el descriptor HOG en OpenCV.