Skip to content

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 .py con 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 comprobar if 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 imshow es 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

  1. ¿Cuál es el objetivo de la visión artificial? ¿Qué cuatro pasos conforman el proceso general?
  2. ¿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é?
  3. ¿Por qué OpenCV trabaja en BGR y no en RGB? ¿Qué problema produce al mostrar imágenes con Matplotlib?
  4. ¿Cuál es el rango de valores de los píxeles en OpenCV? ¿En qué tipo de dato se almacenan por defecto?
  5. ¿Qué devuelve cv2.imread si no puede leer el fichero? ¿Cómo se detecta ese error?
  6. ¿Qué hace cada flag de cv2.imread: IMREAD_GRAYSCALE, IMREAD_COLOR, IMREAD_UNCHANGED?
  7. ¿Para qué sirve cv2.waitKey(0) y por qué no se debe cerrar la ventana con la X?
  8. Cuando se visualiza el canal rojo de una imagen con cv2.imshow, ¿los píxeles con mucho rojo aparecen rojos o blancos? ¿Por qué?
  9. ¿Qué hace cv2.Canny? ¿Qué tipo de imagen espera como entrada?
  10. ¿Qué diferencia hay entre los valores de color en OpenCV ([0, 255]) y en OpenGL ([0, 1])?