Python en Ingeniería Electrónica
Estos ejercicios son para demostrar a los alumnos el uso de Python en la resolución de problemas en el ámbito de la Ingeniería Electrónica.
1. Detección de Temperatura Mediante Análisis de Imagen
1.3. Proceso de Desarrollo del Programa
Espacio de Color
Existen varios espacios de color, el más conocido es el RGB (Rojo, Verde, Azul). Es este espacio, se escribe un color como una tupla de tres componentes. Cada componente puede tomar un valor entre 0 y 255, donde la tupla (0, 0, 0) representa el negro y (255, 255, 255) representa el blanco.
El espacio predeterminado de OpenCV es el BGR, el concepto es similar al RGB, con la diferencia de invertir la posición entre Rojo (R) y Azul (B). Muchas funciones y métodos de esta librería establecen los colores de esta forma (por ejemplo: la de escribir texto o formas por pantalla).
Por otra parte, el espacio de color HSV (Matriz, Saturación, Valor) es útil en tarea de procesamientos de imagen. En OpenCV, los canales de HSV varían así: [H:0–179, S:0–255, V:0–255]. En la Figura 1 puede apreciarse la representación del modelo.
Figura 1
A modo de de dejar más claro esto, con V=255, es decir, haciendo un corte horizontal al cono de la Figura 1, se obtiene lo que se visualiza en la Figura 2. Con un sistema de coordenadas se designan los colores a utilizar.
Figura 2
Lo que se aprecia en la Figura 2, es equivalente a usar los colores que se ven en la base del cono (la parte de arriba de la Figura 1, está invertido el cono).
Entendiendo este concepto, es posible mapear los colores en un sistema de coordenadas, es decir, lo que se ve en Álgebra, Cálculo, etc. Mirando la Figura 2, el eje horizontal es H y el vertical S. Entonces, si lo que me interesa es la gamma de verdes encerrados en el recuadro blanco de la Figura 2, basta con designar las coordenadas de los vértices opuestos del cuadrado. Quedando ese espectro de verdes en HSV así:
umbral_bajo_verde = (40, 150, 255)
umbral_alto_verde = (70, 250, 255)
A esta altura probablemente ya sepas por dónde viene la mano, en la parte de conceptos teóricos se mostró una tabla con los colores que debe tomar el acero. Esa tabla la vamos a mapear en este espacio de color. Al procesar las imágenes se buscan coincidencias y se decide si lo que se detecta es acero, en ese caso, se sabe a qué temperatura está. El principio es válido para un sin número de aplicaciones (detección de objetos, clasificación, etc.).
Dejo una tabla de temperatura más nítida, con esta nos vamos a guiar en el desarrollo del programa.
Tabla 1
Codificación
En el apartado de instalación de recursos, se mencionó que OpenCV requiere Numpy. Por tal motivo, los umbrales se definirán con el sistema de matrices de Numpy. Esto permitirá al algoritmo ser más eficiente, pero se pueden hacer las declaraciones como tuplas normales. Entonces, para el color correspondiente a 550 °C tendríamos las siguientes líneas:
bajo_550 = np.array([1,100,70], dtype=np.uint8)
alto_550 = np.array([5,160,80], dtype=np.uint8)
Teniendo esto en claro, se tiene la parte más complicada del programa, definir cada uno de los rangos para cada temperatura.
Pasamos a escribir un pequeño script que permita reconocer este color en una imagen. Lo dejo como imagen así se visualizan números de líneas y colores de sintaxis.
Figura 3
En el código de la Figura 3 aparecen varios métodos de OpenCV. Se encuentra comentado de forma breve lo que hace cada uno. En síntesis:
- En la línea 8 se carga la imagen de la Tabla 1, tiene que tener el nombre que se especifica en el código (o adecuarlo).
- En la línea 9 la imagen se convierte a su equivalente en el espacio de color HSV.
- En la línea 14 se genera una nueva imagen "la máscara", para ello se toma la imagen en HSV y los umbrales establecidos. Esta máscara es el resultado de buscar coincidencias en la imagen original respecto al color establecido. Si coincide el pixel es un 1, sino un 0; blanco o negro, verdadero o falso, vienen a ser como una operación booleana.
- En las líneas 18 y 19 se muestran por pantalla ambas imágenes, a fines de comparar los resultados. Si el umbral de colores es correcto, en la máscara deberá aparecer coloreado blanco la zona correspondiente al color del umbral.
- De la línea 22 en adelante se tiene un pequeño bucle para visualizar el resultado hasta presionar la tecla escape del teclado (Esc).
Al ejecutar el código, se obtiene como resultado:
Figura 4
Cómo se aprecia en la Figura 4, en la máscara se tiene coloreado prácticamente la totalidad del recuadro que representa a los 550 °C. Se identifican a su vez pequeñas zonas negras y blancas en lugares que no corresponde. Puede deberse a "ruido", distorsiones en la imagen original, etc. Esto está presente en la vida real, así que es necesario considerarlos. Para ello, se filtran con algún método o se efectúa un análisis de los resultados obtenidos, la complejidad del algoritmo tiene cómo límites los estándares del proyecto, la capacidad de cómputo disponible, etc.
Un filtrado sencillo, sería delimitar las zonas válidas de acuerdo al área que abarcan. En la Figura 5 se ve el código adecuado a la necesidad de filtrar los pixeles blancos sueltos.
Figura 5
En la línea 17 se emplea un método que busca contornos en la máscara. Luego, en la línea 19 con otro método de OpenCV se obtiene el área de los contornos existentes. El área se compara con un valor escogido y de esta forma de filtran o separan las que no califican. Por último, en la línea 22 se dibuja sobre la imagen original el o los contornos reconocidos como válidos. En esta línea, el método drawContours recibe una tupla como uno de sus parámetros (0, 255, 0), que si recordamos del espacio BGR corresponde a un verde puro.
El resultado ahora es:
Figura 6
Como puede apreciarse en la figura, la máscara de detección no cambia respecto a la anterior, pero esta vez se está considerando sólo el área encerrada en verde en la imagen original.
El principio básico para el funcionamiento del programa es este. Cómo existe una gamma variada de colores, será necesario trabajar con los datos de cada uno de ellos. Basta con agrupar la información para las máscaras en un arreglo, y realizar la misma operación de los códigos mostrados (anidada en una estructura repetitiva por ejemplo). Entre máscaras es posible efectuar determinadas operaciones (suma, resta, etc.)
Lo que resta, es por ejemplo definir la forma en la que se muestran las zonas detectadas y a qué temperatura corresponden. OpenCV tiene el método putText, que permite insertar texto en una imagen definiendo varios parámetros (ubicación, tamaño, tipo de fuente, etc.).
Dejo un compendio de los métodos vistos:
cv2.imread
cv2.cvtColor
np.array
cv2.inRange
cv2.findContours
cv2.contourArea
cv2.drawContours
cv2.putText
cv2.imshow
cv2.waitKey
cv2.destroyAllWindows