5.31. Coincidencia de desplazamiento

La coincidencia de plantillas responde a dónde está este parche dentro del fotograma; la puntuación de similitud responde a cuán parecidas son estas dos imágenes en conjunto. Entre ambas se sitúa una pregunta diferente: los dos fotogramas muestran la misma escena, pero la cámara (o la escena) se movió entre ellos – ¿cuánto? Ese es el problema del desplazamiento, y el módulo image lo resuelve con un único método de correlación de fase.

5.31.1. Desplazamiento por correlación de fase

find_displacement() estima la alineación rígida entre dos imágenes del mismo tamaño usando correlación de fase – un método en el dominio de la frecuencia que ejecuta una transformada rápida de Fourier (FFT) sobre cada imagen, correlaciona de forma cruzada sus fases, y localiza el pico en el resultado. La posición del pico es la traslación que alinea las dos imágenes:

d = img.find_displacement(template)

print("shift:", d.x_translation, d.y_translation,
      " response:", d.response)

El objeto Displacement devuelto lleva x_translation e y_translation – el desplazamiento en píxeles en cada eje – más response, una puntuación de confianza de 0.0 a 1.0 donde 1.0 es un pico perfecto. Filtrar las detecciones por debajo de response > 0.3 descarta resultados espurios en los que la correlación de fase nunca encontró un pico limpio.

Tanto rotation como scale son 0.0 y 1.0 respectivamente en el modo por defecto; toman valores reales solo cuando logpolar=True (ver más abajo).

El método conlleva dos restricciones prácticas. La primera son las dimensiones potencia de dos: la FFT que está en el corazón de la correlación de fase es más rápida – y en la cámara, solo está totalmente soportada – en tamaños como 32 por 32, 64 por 64 y 128 por 128. La configuración más limpia es capturar directamente a uno de esos tamaños, pasando la resolución a framesize() como una tupla:

csi0.framesize((64, 64))

Una aplicación que necesita el desplazamiento a partir de un fotograma más grande recorta en su lugar un parche potencia de dos de la región que le interesa y ejecuta el comparador sobre eso.

La segunda son las entradas del mismo tamaño: roi y template_roi deben seleccionar anchos y altos idénticos, o el comparador rechaza la llamada. Dos capturas de la misma cámara con la misma configuración satisfacen esto automáticamente; un fotograma capturado comparado con una referencia cargada necesita que ambos se recorten primero a parches potencia de dos coincidentes.

5.31.2. Rotación y escala mediante log-polar

El modo por defecto encuentra solo la traslación. Cuando los dos fotogramas también difieren en rotación en torno a un centro elegido o en escala en torno al mismo centro, ejecutar la correlación de fase sobre la reproyección log-polar de cada imagen convierte esos parámetros en traslación en el sistema de coordenadas log-polar – que el mismo comparador por correlación de fase puede recuperar:

d = img.find_displacement(template, logpolar=True)

print("rotation rad:", d.rotation,
      " scale:", d.scale,
      " response:", d.response)

Con logpolar=True, el método ejecuta la misma canalización de coincidencia contra las imágenes proyectadas en log-polar en lugar de las originales. Los campos rotation y scale del resultado vuelven rellenados: rotation es el ángulo en radianes entre los dos fotogramas, scale es el factor de escala entre ellos. x_translation e y_translation pierden su significado en este modo (la traslación a lo largo de los ejes log-polar no se corresponde con una traslación lineal en la fuente).

La palabra clave fix_rotation_scale=True cubre el caso intermedio: las dos imágenes difieren tanto en traslación como en rotación/escala, y la aplicación necesita solo la traslación después de corregir la rotación y la escala. El comparador ejecuta primero la pasada log-polar para recuperar la rotación y la escala, aplica la inversa a una de las imágenes, y luego ejecuta la pasada de traslación para recuperar el desplazamiento restante. El indicador solo tiene sentido cuando logpolar=False – pide al comparador en modo traslación que primero elimine la rotación/escala.

El patrón de las transformaciones polares – cartesiano → polar → coincidencia – es lo que hace find_displacement() con logpolar=True en una sola llamada. La aplicación almacena un parche log-polar de referencia al inicio, captura y transforma a log-polar cada fotograma en vivo, y el método recupera la diferencia de rotación y escala entre ellos. Para las aplicaciones que necesitan un rastreador invariante a la rotación y la escala – un robot de acoplamiento cuya cámara se inclina y hace zoom a medida que se aproxima a un objetivo, un cardán estabilizado que necesita saber cómo está rotando la imagen respecto a una referencia – esta es la construcción estándar.

5.31.3. El uso clásico

El uso más común de find_displacement() es la estimación de movimiento de fotograma a fotograma en una canalización que procesa una cámara en movimiento. La cámara captura un pequeño parche potencia de 2 en el fotograma N, captura el parche del mismo tamaño en el fotograma N+1, ejecuta find_displacement() sobre los dos, y lee el desplazamiento en píxeles entre ellos. El desplazamiento es el movimiento estimado de la cámara (o de la escena, dependiendo de qué marco de referencia importe) entre las dos capturas, útil para:

  • Detección al estilo de flujo óptico – un dron de vuelo estacionario con una cámara apuntando hacia abajo usa el desplazamiento por fotograma para estimar su movimiento lateral y realimentarlo al controlador de vuelo.

  • Estabilización de imagen – el desplazamiento entre fotogramas consecutivos se resta de la imagen capturada antes de grabarla o transmitirla, produciendo un flujo de vídeo más suave.

  • Alineación de inspección – una cámara de escaneo que se desplaza a lo largo de una cinta transportadora usa el desplazamiento por fotograma para registrar cada fotograma respecto al siguiente y construir una vista cosida de toda la pieza.

Cada una de esas aplicaciones adopta la misma forma: capturar, desplazar, acumular en una estimación continua, capturar de nuevo.