Clase 9 — Introducción a la Visión Artificial y OpenCV
Resumen Ejecutivo
Primera clase del bloque de visión artificial. Se abandona OpenGL y se presenta el marco conceptual de la visión por ordenador: qué es, para qué sirve y los dos enfoques existentes (redes neuronales vs. algoritmos clásicos). Se justifica por qué en esta asignatura se usa el enfoque clásico con la librería OpenCV. A continuación se introduce la representación de imágenes en memoria (mapa de bits, modelos de color BGR/RGB/BGRA/escala de grises, rango 0-255) y las primeras funciones de la librería: cv2.imread, cv2.imshow, cv2.waitKey, cv2.destroyAllWindows y cv2.split. Se cierra con una demostración en vivo de detección de bordes en tiempo real sobre la webcam usando el algoritmo Canny.
Avisos importantes: la actividad grupal se ha pospuesto al 18 de mayo; el examen contará con un módulo .py de funciones de apoyo que la profesora proporcionará.
Conceptos Clave
- Visión artificial: disciplina que busca emular la percepción visual humana para adquirir imágenes, procesarlas y tomar decisiones automáticas. ⚠️ EXAMEN
- Dos enfoques:
- Redes neuronales / Deep Learning: alta precisión, necesita muchos datos etiquetados y cómputo intensivo. Caja negra.
- Visión clásica (nuestro enfoque): métodos matemáticos y geométricos, interpretables, sin entrenamiento, peor en escenas complejas. ⚠️ EXAMEN
- OpenCV: librería open-source de visión artificial. Usaremos Python + Numpy + (algo de) Matplotlib.
- Mapa de bits: representación píxel a píxel. Cada píxel es un array de valores de intensidad. ⚠️ EXAMEN
- BGR vs RGB: OpenCV lee imágenes en BGR (Blue-Green-Red), no en RGB. Históricamente así lo adoptaron los fabricantes de hardware en los 90. ⚠️ EXAMEN
- Canal alfa (A): transparencia por píxel. 0 = totalmente transparente, 255 = totalmente opaco.
- Rango de valores: entero sin signo de 8 bits,
uint8, intervalo [0, 255] (en OpenGL era [0, 1]). - ndarray de Numpy: tipo de dato que devuelven las funciones de OpenCV para almacenar imágenes.
- Pipeline de procesamiento: secuencia de pasos que transforma la imagen original hasta extraer la información deseada.
- Algoritmo Canny: detector de bordes clásico disponible en OpenCV (
cv2.Canny).
Desarrollo del Temario
1. Avisos iniciales
- Notas de la Actividad 1 publicadas. Corrección generosa porque era de "romper el hielo".
- Para la Actividad 2 (grupal) la profesora subirá un módulo
.pycon funciones de apoyo (pintar ortoedros huecos, etc.) para que los grupos puedan importarlo en lugar de incluirlo dentro del cuaderno. El mismo módulo se facilitará en el examen. ⚠️ EXAMEN - Entrega actividad grupal: ~~11 de mayo~~ → 18 de mayo.
- Formato de entrega: cuaderno Jupyter con comentarios insertados, o PDF + código separado.
2. Qué es la visión artificial
El objetivo es emular la percepción visual humana:
Adquisición de imágenes
↓
Procesamiento
↓
Extracción de información
↓
Toma de decisiones → Acciones automáticas
Ejemplos de aplicaciones:
| Sector | Aplicación |
|---|---|
| Automoción | Vehículos autónomos, detección de carril |
| Traducción | Google Translate (OCR sobre imagen) |
| Medicina | Detección de cáncer en imágenes radiológicas / plasma sanguíneo |
| Industria | Pick & place, control de calidad, calibrado de fruta |
| Agricultura | Seguimiento de cultivos con drones, detección de déficit mineral |
3. Dos enfoques de visión artificial
3.1 Redes neuronales / Deep Learning
- Modelo con muchas capas y millones de pesos ajustados en entrenamiento supervisado (imágenes etiquetadas).
- Una vez entrenado clasifica nuevas imágenes con alta precisión.
- Ventajas: alta precisión, modelos pre-entrenados disponibles (fine-tuning).
- Inconvenientes: necesita muchos datos (80% del tiempo se dedica a preparar el dataset), alto coste de cómputo, caja negra (no explica el "por qué"). ⚠️ EXAMEN
Nota de la profesora: existe la rama de IA explicable (Explainable AI) que intenta superar la opacidad, tanto añadiendo "mochilas" a los modelos opacos como mediante IA simbólica (representación matemática 100% fiel del conocimiento, sin estadística).
3.2 Visión clásica (nuestro enfoque)
- Métodos matemáticos y geométricos: filtros, detección de bordes, contornos, matching de formas.
- Ventajas: interpretable, no necesita datos de entrenamiento, claro en su razonamiento. ⚠️ EXAMEN
- Inconvenientes: peor rendimiento en escenas complejas o con mucha variabilidad.
Analogía con el cuadrado:
| Enfoque | Cómo detecta un cuadrado |
|---|---|
| Red neuronal | Entrena con miles de imágenes etiquetadas |
| Visión clásica | Filtra → detecta bordes → detecta contorno → matching de 4 vértices |
4. La librería OpenCV
- Sitio oficial: opencv.org — sección OpenCV Python Tutorials para consultas.
- Se usa con Python 3, Numpy (obligatorio, almacenamiento interno) y Matplotlib (opcional, visualización).
- Entorno separado del de OpenGL. Instalar con
pip install opencv-python numpy matplotlib.
5. Representación de imágenes en memoria
5.1 Tipos de imagen según canales
| Tipo | Estructura por píxel | Rango | Notas |
|---|---|---|---|
| Color (BGR) | 3 componentes: B, G, R | [0, 255] | Formato por defecto en OpenCV ⚠️ EXAMEN |
| Color con transparencia (BGRA) | 4 componentes: B, G, R, A | [0, 255] | PNG lo soporta; JPG no |
| Escala de grises | 1 componente | [0, 255] | 0 = negro, 255 = blanco |
Diferencia con OpenGL: en OpenGL los valores de color se normalizaban a [0, 1]; en OpenCV se trabaja directamente con enteros [0, 255] (uint8). ⚠️ EXAMEN
5.2 BGR vs RGB
OpenCV adoptó históricamente BGR (Blue-Green-Red). Si se muestra una imagen BGR directamente en Matplotlib (que espera RGB) los canales rojo y azul aparecen intercambiados. Solución: cv2.cvtColor(img, cv2.COLOR_BGR2RGB) antes de mostrar con Matplotlib. ⚠️ EXAMEN
5.3 Canal alfa
- A = 0: píxel totalmente transparente.
- A = 255: píxel totalmente opaco.
- Si una aplicación no soporta transparencias muestra negro en las zonas transparentes porque los valores BGR suelen ser 0-0-0 (negro) y solo varía el canal A.
5.4 Atributos del ndarray de Numpy
img.ndim # número de dimensiones (2 para grises, 3 para color)
img.shape # tupla con tamaño de cada dimensión, p. ej. (alto, ancho, 3)
img.dtype # tipo de dato; por defecto uint8 (entero sin signo 8 bits)
6. Primeras funciones de OpenCV
6.1 Lectura: cv2.imread
img = cv2.imread(path, flag)
| Flag | Comportamiento |
|---|---|
cv2.IMREAD_GRAYSCALE |
Lee y convierte a escala de grises |
cv2.IMREAD_COLOR |
Lee y convierte a BGR color (valor por defecto) |
cv2.IMREAD_UNCHANGED |
Lee sin conversión (mantiene canales originales, incluyendo alfa) |
- Si la lectura falla devuelve
None(no lanza excepción). Siempre comprobarif img is None. - Devuelve un
numpy.ndarray.
img = cv2.imread('images/foto.jpg')
if img is None:
sys.exit('Error al leer la imagen')
6.2 Visualización: cv2.imshow + cv2.waitKey + cv2.destroyAllWindows
cv2.imshow('nombre_ventana', img) # muestra la imagen en una ventana
cv2.waitKey(0) # espera indefinidamente hasta pulsación de tecla
cv2.destroyAllWindows() # cierra todas las ventanas abiertas
- El string de
imshowes el ID interno de la ventana. waitKey(0)espera infinitamente;waitKey(n)espera n milisegundos.- No cerrar la ventana con la X: siempre pulsar una tecla para liberar recursos correctamente.
6.3 Separación de canales: cv2.split
b, g, r = cv2.split(img) # devuelve tres arrays (uno por canal)
Cada canal resultante es un array 2D de uint8. Al visualizarlo con imshow, los píxeles con valor alto (cerca de 255) aparecen blancos y los de valor bajo (cerca de 0) aparecen negros — no en el color del canal. ⚠️ EXAMEN
Ejemplo con los tomates: el canal rojo muestra blancos los tomates rojos/naranjas/amarillos y negro el tomate verde.
6.4 Conversión de color: cv2.cvtColor
gris = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
7. Pipeline de procesamiento (concepto)
Al igual que en OpenGL existía un pipeline de transformaciones de vértices, en visión artificial se diseña un pipeline de procesamiento de imagen:
Imagen original
↓
Preprocesado (filtros, conversión de color)
↓
Extracción de características (bordes, contornos, formas)
↓
Toma de decisión / Matching
↓
Resultado
En las clases siguientes se verán los bloques concretos de este pipeline (tema 8 y siguientes).
8. Demostración: detección de bordes en tiempo real (Canny)
import cv2
cap = cv2.VideoCapture(0) # cámara 0; pasar un path para vídeo grabado
if not cap.isOpened():
sys.exit('No se puede abrir la cámara')
while True:
ret, frame = cap.read() # ret=False cuando acaba un fichero de vídeo
if not ret:
break
gris = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
bordes = cv2.Canny(gris, 100, 200) # detector de bordes Canny
cv2.imshow('video', bordes)
if cv2.waitKey(1) & 0xFF == ord('s'): # salir con 's'
break
cap.release()
cv2.destroyAllWindows()
cv2.Canny: uno de los mejores algoritmos de detección de bordes. Requiere imagen en escala de grises. Los dos parámetros numéricos son los umbrales (se verán en detalle más adelante). ⚠️ EXAMEN- En ~10 líneas se procesa vídeo en tiempo real.
- Para un vídeo grabado basta con pasar la ruta del fichero a
VideoCapture.
9. Organización de ficheros para los cuadernos
- Directorio de trabajo del cuaderno Jupyter.
- Subdirectorio
images/con todas las imágenes que la profesora comparte. - Las imágenes proceden mayoritariamente de Pixabay (gratuitas).
Preguntas de Autoevaluación
- ¿Cuál es el objetivo de la visión artificial? ¿Qué cuatro pasos conforman el proceso general?
- ¿En qué se diferencian el enfoque de redes neuronales y el enfoque de visión clásica? ¿Cuál se usa en esta asignatura y por qué?
- ¿Por qué OpenCV trabaja en BGR y no en RGB? ¿Qué problema produce al mostrar imágenes con Matplotlib?
- ¿Cuál es el rango de valores de los píxeles en OpenCV? ¿En qué tipo de dato se almacenan por defecto?
- ¿Qué devuelve
cv2.imreadsi no puede leer el fichero? ¿Cómo se detecta ese error? - ¿Qué hace cada flag de
cv2.imread:IMREAD_GRAYSCALE,IMREAD_COLOR,IMREAD_UNCHANGED? - ¿Para qué sirve
cv2.waitKey(0)y por qué no se debe cerrar la ventana con la X? - Cuando se visualiza el canal rojo de una imagen con
cv2.imshow, ¿los píxeles con mucho rojo aparecen rojos o blancos? ¿Por qué? - ¿Qué hace
cv2.Canny? ¿Qué tipo de imagen espera como entrada? - ¿Qué diferencia hay entre los valores de color en OpenCV ([0, 255]) y en OpenGL ([0, 1])?