5.20. Régression et similarité¶
Deux autres mesures de la classe Image résument l’image autrement que comme une distribution de valeurs de pixels. La régression linéaire des pixels seuillés donne à une application une ligne sur laquelle elle peut agir – l’entrée classique d’un robot suiveur de ligne. La mesure de similarité donne à une application un unique nombre décrivant à quel point deux images se ressemblent – l’entrée naturelle d’un test de régression par image de référence ou d’un détecteur de changements grossiers.
5.20.1. Régression linéaire¶
Lorsque les pixels de premier plan d’une image forment justement une ligne à travers la trame – le ruban d’une piste qu’un robot suit, la ligne d’un horizon, le bord d’une route ou d’un couloir – l’application ne veut généralement pas chaque pixel de premier plan individuel. Elle veut la droite de meilleur ajustement qui les traverse tous, paramétrée de sorte qu’elle puisse décider comment la ligne est orientée et où elle traverse la trame.
get_regression() réalise cet ajustement. Elle prend la même forme de tuple de seuil que binary() et find_blobs() utilisent, identifie chaque pixel qui correspond au seuil, et renvoie un unique résultat line décrivant la droite de meilleur ajustement à travers ces pixels :
line = img.get_regression([(0, 60)])
if line:
img.draw_line((line.x1(), line.y1(),
line.x2(), line.y2()),
color=(255, 0, 0))
L’ajustement est une régression linéaire de Theil-Sen – une méthode robuste qui tolère mieux les valeurs aberrantes que l’ajustement par moindres carrés, plus familier. Une petite poignée de pixels éloignés de la vraie ligne ne fausse pas le résultat comme ils le feraient avec les moindres carrés, ce qui correspond à la réalité bruitée du premier plan d’une vraie sortie de seuil.
Le résultat line porte les extrémités rognées au rectangle de l’image (x1, y1, x2, y2), la longueur et la magnitude de la ligne (length, magnitude), et la description géométrique de la ligne sous forme polaire (theta, rho) – l’angle de la ligne par rapport à l’horizontale et sa distance perpendiculaire à l’origine. La forme polaire est ce qu’une boucle de contrôle veut généralement : theta indique au robot de quel côté la ligne penche, rho lui indique où la ligne traverse l’image, et une boucle de rétroaction sur les deux maintient le robot centré sur la ligne.
Une poignée d’arguments nommés ajustent la robustesse et le coût. x_stride et y_stride sautent des pixels durant l’ajustement – des pas plus grands rendent la régression moins coûteuse au prix d’un ajustement sur moins de pixels. area_threshold et pixels_threshold rejettent les lignes qui n’ont pas assez de pixels correspondants derrière elles. target_size redimensionne l’entrée à une taille plus petite avant l’ajustement – la régression s’exécute plus vite sur un substitut de 80 par 60 de l’image sans grande perte de précision sur la direction de la ligne.
Si aucune ligne acceptable n’a pu être ajustée – si le seuil n’a correspondu à aucun pixel, ou à un motif qui ne ressemble pas à une ligne – la méthode renvoie None. Un vrai code de suivi de ligne protège chaque appel à get_regression() par une vérification None avant d’accéder aux attributs de la ligne.
5.20.2. Similarité d’images¶
Un autre type de mesure : au lieu de demander « que contient l’image ? », demander « à quel point ces deux images se ressemblent-elles ? ». L’opération à utiliser est get_similarity(), qui calcule l”indice de similarité structurelle (SSIM) entre l’image source et une image de référence.
s = img.get_similarity(reference)
print(s.mean, s.stdev)
Le SSIM est la métrique de similarité d’images standard utilisée dans tout le traitement d’images, car il se comporte comme se comporte l’intuition humaine de la similarité – un petit décalage ou un petit changement de luminosité réduit légèrement le score, tandis qu’un grand changement structurel (objet manquant, scène différente) le réduit considérablement. Le score varie de -1 à +1 : +1 signifie que les deux images sont identiques, 0 qu’elles n’ont aucun rapport, et -1 qu’elles sont structurellement opposées. Un objet similarity renvoyé expose le SSIM moyen sur l’image, plus l’écart-type, le min et le max des scores par tuile.
Pour le type de comparaison où un petit nombre vaut mieux qu’un grand – un test de régression qui devrait indiquer zéro pour « rien n’a changé » et augmenter à mesure que les changements s’accumulent – l’option dssim=True renvoie la dissimilarité structurelle : le SSIM moyen soustrait de 1, de sorte que la valeur de retour vaut 0.0 pour des images identiques et augmente à mesure qu’elles diffèrent.
5.20.3. Cas d’usage du SSIM¶
Les deux applications courantes :
Test de régression par image de référence. Un cadre de test capture une trame de référence dans des conditions connues comme bonnes et la stocke comme image de référence. Les exécutions de test ultérieures capturent dans les mêmes conditions et comparent à l’image de référence avec le SSIM. Un score au-dessus d’un certain seuil (0.95 ou 0.98 selon la tolérance) est une réussite ; en dessous, c’est un échec. Le cadre de test n’a pas besoin de savoir ce qui a changé – le score SSIM est le signal.
Détection de changements grossiers. Une application qui veut une version plus grossière de la différenciation de trames – une version qui ignore les petits changements de luminosité mais réagit aux grands changements structurels – peut utiliser le SSIM par rapport à une trame de référence au lieu de la difference() par pixel suivie d’un seuil. Le SSIM est moins sensible à la dérive de l’éclairage que la différenciation par pixel, ce qui en fait le meilleur choix lorsque l’objectif est de détecter que « la scène a l’air sensiblement différente » plutôt que « un pixel individuel quelconque a changé ».
Les deux applications utilisent le même appel – img.get_similarity(reference) – et se déclenchent sur un seuil du score renvoyé. La différence tient seulement à savoir si le seuil est élevé (test de régression, recherche d’une correspondance quasi identique) ou faible (détection de changement, recherche de tout grand changement structurel).
5.20.4. La forme transformer-puis-comparer¶
Une subtilité utile : get_similarity() accepte les mêmes paramètres x, y, x_scale, y_scale, roi, rgb_channel, alpha, color_palette, alpha_palette, hint et transform que draw_image(). L’image de référence est positionnée, mise à l’échelle et transformée par ces paramètres avant l’exécution de la comparaison SSIM.
Cela signifie qu’une application peut demander « à quel point cette scène est-elle similaire à une trame de référence après un déplacement / une rotation / une mise à l’échelle connus » sans préparer d’image de référence pré-transformée. C’est la façon économique de construire un traqueur qui explore un espace de paramètres et indique quelle transformation de la référence correspond le mieux à la trame actuelle.