
Entrada 3: Proyecto BermejaPi — Visualización de Coincidencias Fotogramétricas con OpenCV
En la entrada anterior logramos calcular numéricamente la velocidad de la ISS a partir del desplazamiento de terreno entre dos fotografías. Sin embargo, en un proyecto científico real no basta con obtener un número: debemos validar visualmente que el algoritmo está rastreando elementos reales del terreno (costas, islas, valles) y no ruido, nubes en movimiento o reflejos en la ventana de la estación.
En esta tercera entrada del proyecto BermejaPi, implementaremos un módulo de inspección visual que dibuja vectores de coincidencia entre ambas imágenes.
1. El Fundamento Didáctico: ¿Por qué visualizamos las coincidencias?
Cuando el algoritmo ORB analiza dos imágenes:
- Detecta puntos clave (Keypoints) en la Foto 1: coordeandas $(x_1, y_1)$ con alto contraste o bordes definidos.
- Encuentra sus correspondientes puntos homólogos en la Foto 2: coordenadas $(x_2, y_2)$.
- Traza una línea de conexión entre ambos puntos.
Si el satélite o la estación espacial se desplaza en una trayectoria rectilínea, todas las líneas de conexión deben ser paralelas y de longitud similar. Si vemos líneas cruzadas o en direcciones opuestas, el algoritmo ha cometido un error de emparejamiento (outlier).
2. La Función cv2.drawMatches
OpenCV proporciona una función nativa para fusionar las dos fotos lado a lado y trazar las líneas vectoriales de correspondencia:
$$\text{Imagen Salida} = \text{cv2.drawMatches}(\text{img1}, \text{kp1}, \text{img2}, \text{kp2}, \text{coincidencias}, \text{None})$$
img1,img2: Las dos capturas de terreno.kp1,kp2: Lista de puntos clave detectados por ORB en cada imagen.coincidencias: Las mejores parejas fijadas por la distancia de Hamming.
3. Código Python Completo (03-visualizar_match.py)
Crea el archivo 03-visualizar_match.py dentro de tu carpeta de trabajo (C:\2627\esa\astropi\02-velocidad\). Este script incluye la generación automática de fotos si no detecta las capturas anteriores en el disco, garantizando su ejecución directa en Windows:
Python
import time
from pathlib import Path
import cv2
import numpy as np
def verificar_o_generar_imagenes():
"""Asegura que existen foto1.jpg y foto2.jpg en el directorio actual."""
f1 = Path("foto1.jpg")
f2 = Path("foto2.jpg")
if not f1.exists() or not f2.exists():
print("Aviso: No se encontraron las fotos. Generando terreno sintetico...")
h, w = 1080, 1920
np.random.seed(42)
terreno = np.random.randint(80, 180, (h, w), dtype=np.uint8)
terreno = cv2.GaussianBlur(terreno, (31, 31), 0)
# Añadir formas geograficas para contraste
cv2.circle(terreno, (400, 400), 120, (240), -1)
cv2.circle(terreno, (1100, 600), 180, (30), -1)
cv2.rectangle(terreno, (200, 750), (900, 820), (210), -1)
# Foto 1 y Foto 2 (desplazada 45 px)
cv2.imwrite("foto1.jpg", terreno)
matriz_desplazamiento = np.float32([[1, 0, -45], [0, 1, 0]])
foto2 = cv2.warpAffine(terreno, matriz_desplazamiento, (w, h))
cv2.imwrite("foto2.jpg", foto2)
print("Imagenes de prueba creadas correctamente.")
def generar_mapa_coincidencias():
print("=== INICIANDO VISUALIZACION DE TELEMETRIA BERMEJAPI ===")
# 1. Comprobar archivos de imagen
verificar_o_generar_imagenes()
# 2. Cargar imagenes en escala de grises
img1 = cv2.imread("foto1.jpg", cv2.IMREAD_GRAYSCALE)
img2 = cv2.imread("foto2.jpg", cv2.IMREAD_GRAYSCALE)
if img1 is None or img2 is None:
print("Error: No se pudieron cargar las imagenes de entrada.")
return
# 3. Detectar puntos clave y descriptores con ORB
orb = cv2.ORB_create(nfeatures=1000)
kp1, des1 = orb.detectAndCompute(img1, None)
kp2, des2 = orb.detectAndCompute(img2, None)
if des1 is None or des2 is None:
print("Error: No se detectaron suficientes puntos caracteristicos.")
return
# 4. Emparejar caracteristicas mediante BFMatcher
bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)
coincidencias = bf.match(des1, des2)
# Ordenar por calidad de coincidencia (menor distancia = mejor)
coincidencias = sorted(coincidencias, key=lambda x: x.distance)
# Seleccionar las 30 mejores coincidencias para una visualizacion limpia
mejores_30 = coincidencias[:30]
# 5. Dibujar las lineas de conexion entre Foto 1 y Foto 2
imagen_matches = cv2.drawMatches(
img1,
kp1,
img2,
kp2,
mejores_30,
None,
flags=cv2.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS,
)
# 6. Guardar el archivo de inspeccion visual
nombre_salida = "coincidencias_visuales.jpg"
cv2.imwrite(nombre_salida, imagen_matches)
print(f"Proceso completado con exito.")
print(f"Puntos clave detectados en Foto 1: {len(kp1)}")
print(f"Puntos clave detectados en Foto 2: {len(kp2)}")
print(f"Coincidencias representadas: {len(mejores_30)}")
print(
f"Resultado guardado en: {Path(nombre_salida).resolve()}"
)
if __name__ == "__main__":
generar_mapa_coincidencias()
4. Guía de Ejecución en el Aula
- Abre la Terminal de Windows (CMD o PowerShell).
- Navega a la carpeta de trabajo:
DOScd C:\2627\esa\astropi\02-velocidad\ - Ejecuta el script con Python:
DOSpython 03-visualizar_match.py - Inspecciona el resultado: Abre el archivo generado
coincidencias_visuales.jpgcon el visor de fotos predeterminado de Windows.
5. Análisis del Resultado e Interpretación de Datos
Al abrir la imagen resultante coincidencias_visuales.jpg, observarás dos paneles compuestos:
- Panel Izquierdo: Muestra la Foto 1 con círculos de colores sobre los puntos clave detectados.
- Panel Derecho: Muestra la Foto 2 con los puntos homólogos identificados tras el avance orbital de la nave.
- Líneas de Vector: Líneas continuas que unen ambos paneles.

Preguntas de verificación para el cuaderno del alumno:
- Unifomidad de líneas: ¿Son paralelas todas las líneas dibujadas o existe alguna línea diagonal cruzada? ¿A qué se debe si aparece una línea cruzada?
- Distribución espacial: ¿Las coincidencias se concentran en una sola zona o se reparten por todo el terreno de la imagen?
- Filtrado de ruido: Si cambiamos
mejores_30porcoincidencias[:200], ¿es más fácil o más difícil inspeccionar la precisión del algoritmo?
Etiqueta:Astro Pi, ASTROPI, BermejaPi, Fotogrametría, ISS, OpenCV, ORB, python, Telemetría Visual, Velocidad Orbital, visión por computador, windows


