5.31. Mise en correspondance par déplacement

La mise en correspondance par modèle répond à la question où se trouve ce fragment dans la trame ; le scoring de similarité répond à la question à quel point ces deux images se ressemblent-elles globalement. Une autre question se situe entre les deux : les deux trames montrent la même scène, mais la caméra (ou la scène) a bougé entre elles – de combien ? C’est le problème du déplacement, et le module image le résout avec une unique méthode de corrélation de phase.

5.31.1. Déplacement par corrélation de phase

find_displacement() estime l’alignement rigide entre deux images de même taille en utilisant la corrélation de phase – une méthode dans le domaine fréquentiel qui exécute une transformée de Fourier rapide (FFT) sur chaque image, corrèle de façon croisée leurs phases, et localise le pic dans le résultat. La position du pic est la translation qui aligne les deux images :

d = img.find_displacement(template)

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

L’objet Displacement renvoyé porte x_translation et y_translation – le décalage en pixels sur chaque axe – ainsi que response, un score de confiance de 0.0 à 1.01.0 est un pic parfait. Filtrer les détections en dessous de response > 0.3 écarte les résultats parasites pour lesquels la corrélation de phase n’a jamais trouvé de pic net.

rotation et scale valent respectivement 0.0 et 1.0 dans le mode par défaut ; ils ne prennent des valeurs réelles que lorsque logpolar=True (voir ci-dessous).

La méthode impose deux contraintes pratiques. La première concerne les dimensions en puissance de deux : la FFT au cœur de la corrélation de phase est la plus rapide – et, sur la caméra, n’est pleinement prise en charge – qu’à des tailles comme 32 sur 32, 64 sur 64 et 128 sur 128. La configuration la plus propre consiste à capturer directement à l’une de ces tailles, en passant la résolution à framesize() sous forme de tuple :

csi0.framesize((64, 64))

Une application qui a besoin du déplacement à partir d’une trame plus grande découpe plutôt un fragment en puissance de deux dans la région qui l’intéresse et exécute le système de mise en correspondance sur celui-ci.

La seconde concerne les entrées de même taille : roi et template_roi doivent sélectionner des largeurs et hauteurs identiques, sinon le système de mise en correspondance refuse l’appel. Deux captures de la même caméra avec la même configuration satisfont cette condition automatiquement ; une trame capturée comparée à une référence chargée nécessite que les deux soient d’abord recadrées en fragments correspondants en puissance de deux.

5.31.2. Rotation et échelle via le log-polaire

Le mode par défaut ne trouve que la translation. Lorsque les deux trames diffèrent aussi par une rotation autour d’un centre choisi ou par une échelle autour du même centre, exécuter la corrélation de phase sur la reprojection log-polaire de chaque image transforme ces paramètres en translation dans le système de coordonnées log-polaire – que le même système de mise en correspondance par corrélation de phase peut récupérer :

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

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

Avec logpolar=True, la méthode exécute le même pipeline de mise en correspondance sur les images projetées en log-polaire au lieu des originales. Les champs rotation et scale du résultat sont alors renseignés : rotation est l’angle en radians entre les deux trames, scale est le facteur d’échelle entre elles. x_translation et y_translation n’ont plus de sens dans ce mode (la translation le long des axes log-polaires ne correspond pas à une translation linéaire dans la source).

Le mot-clé fix_rotation_scale=True couvre le cas intermédiaire : les deux images diffèrent à la fois par la translation et par la rotation/échelle, et l’application n’a besoin que de la translation après correction de la rotation et de l’échelle. Le système de mise en correspondance exécute d’abord la passe log-polaire pour récupérer la rotation et l’échelle, applique l’inverse à l’une des images, puis exécute la passe de translation pour récupérer le décalage restant. L’indicateur n’a de sens que lorsque logpolar=False – il demande au système de mise en correspondance en mode translation de retirer d’abord la rotation/échelle.

Le motif des transformées polaires – cartésien → polaire → mise en correspondance – est ce que find_displacement() avec logpolar=True fait en un seul appel. L’application stocke un fragment log-polaire de référence au démarrage, capture et transforme en log-polaire chaque trame en direct, et la méthode récupère la différence de rotation et d’échelle entre eux. Pour les applications qui ont besoin d’un suivi invariant en rotation et en échelle – un robot d’accostage dont la caméra s’incline et zoome à l’approche d’une cible, un cardan stabilisé qui doit savoir comment l’image tourne par rapport à une référence – c’est la construction standard.

5.31.3. L’usage classique

L’usage le plus courant de find_displacement() est l”estimation du mouvement de trame à trame dans un pipeline qui traite une caméra en mouvement. La caméra capture un petit fragment en puissance de 2 à la trame N, capture le fragment de même taille à la trame N+1, exécute find_displacement() sur les deux, et lit le décalage en pixels entre elles. Ce décalage est le mouvement estimé de la caméra (ou de la scène, selon le référentiel qui importe) entre les deux captures, utile pour :

  • Détection de type flux optique – un drone en vol stationnaire avec une caméra orientée vers le bas utilise le déplacement par trame pour estimer son mouvement latéral et le réinjecter dans le contrôleur de vol.

  • Stabilisation d’image – le déplacement entre trames consécutives est soustrait de l’image capturée avant son enregistrement ou sa transmission, produisant un flux vidéo plus fluide.

  • Alignement d’inspection – une caméra de balayage se déplaçant le long d’un convoyeur utilise le déplacement par trame pour recaler chaque trame par rapport à la suivante et construire une vue assemblée de la pièce entière.

Chacune de ces applications prend la même forme : capturer, déplacer, accumuler dans une estimation continue, capturer à nouveau.