Dans un billet précédent, nous avons vu comment (en théorie) une inter-corrélation pouvait permettre de localiser un objet dans une image. La conclusion était que l'inter-corrélation n'est pas très efficace car sa valeur dépend énormément du niveau de gris des images et assez peu de leur information spatiale. Nous allons voir comment corriger cela.
Le notebook sage de ce billet est : detecteur_de_motifs_phase.sws
Rappels
Il s'agit d'exploiter les propriétés de la transformée de Fourier, utilisée pour calculer l'inter-corrélation. La formule que nous avions utilisée était :
![]()
étant la transformée de Fourier discrète (TFD) de l'image
. Le calcul consiste donc à prendre la TFD de l'image référence
, la TFD de l'image motif
(moyennant les précautions décrites précédemment) et de multiplier pixel à pixel les deux images obtenues. Penchons nous d'un peu plus près sur les transformées de Fourier qui sont manipulées.
Répartition de l'information dans une transformée de Fourier
La transformée de Fourier d'une image réelle est une image dont les valeurs sont des nombres complexe. Un nombre complexe
peut s'exprimer de deux façons :
![]()
où
,
,
et
sont des nombres réels.
est la partie réelle,
la partie imaginaire.
est le module et
l'argument. Nous exploiter cette dernière écriture.
Puisque
est une image complexe, il est également possible de l'écrire sous la forme d'un module et d'un argument. L'argument étant en général appelé phase :
![]()
est alors une image contenant le module de chaque valeur de
,
est une image contenant la phase. Si nous cherchons à comprendre quelles informations sont contenue dans
et
, il est nécessaire de les isoler à partir de
:
![]()
Prenons un exemple illustratif. Voici le portrait de Joseph Fourier :
import pylab as pl def disp(img): pl.imshow(img, interpolation = 'nearest') pl.figure(); disp(fourier); pl.savefig('fourier')
![]()
Voici le module et la phase de la TFD de ce portrait :
import numpy as np import numpy.fft as fft tf_fourier = fft.fft2(fourier) module_fourier = abs(tf_fourier) phase_fourier = tf_fourier / abs(tf_fourier) pl.figure() pl.subplot(121) disp(np.log(int(1)+fft.fftshift(module_fourier))) pl.title('Module') pl.subplot(122) disp(fft.fftshift(abs(phase_fourier))) pl.title('Phase') pl.savefig('tf_fourier')
![]()
Le module contient beaucoup d'informations sur la répartition fréquentielle de l'image et sur les valeurs (en niveaux de gris) de l'image, mais ne contient que peu d'information sur les structures de l'image. C'est la phase qui contient l'information de position des structures de l'image. Cela devient clair lorsque l'on prend la TFD inverse de l'image module et de l'image phase :
phase = abs(fft.ifft2(phase_fourier)) module = np.log(int(1)+abs(fft.ifft2(module_fourier))) pl.figure() pl.subplot(121) disp(m) pl.title('Module') pl.subplot(122) disp(p) pl.title('Phase') pl.savefig('module_phase')
![]()
Il est alors clair que la phase contient les contours de l'image, donc ses structures.
Retour sur l'inter-corrélation
Pour améliorer le détecteur de motif, il est donc nécessaire de :
- supprimer l'information du module, car il contient des informations sur les niveaux de gris des images
- conserver la phase, car elle contient les structures de l'image.
Le détecteur amélioré
Ainsi le détecteur est modifié pour ne conserver que la phase des images :
![]()
Dans la littérature, cette détection est connue sous la dénomination SPOMF (Symmetric Phase Only Matched Filter) :
- [1994,article] bibtexQ. Chen, M. Defrise, and F. Deconick, "Symmetric phase-only matched filtering of Fourier-Mellin transforms for image registration and recognition"," IEEE Trans. on Pattern Analysis and Machine Intelligence, vol. 16, pp. 1156-1168, 1994.
@ARTICLE{Chen1994,
author = {Q. Chen and M. Defrise and F. Deconick},
title = {Symmetric phase-only matched filtering of Fourier-Mellin transforms for image registration and recognition"},
journal = {IEEE Trans. on Pattern Analysis and Machine Intelligence},
year = {1994},
volume = {16},
pages = {1156-1168},
owner = {fredn},
timestamp = {2008.12.18} }
Les résultats
Si l'on applique le nouveau détecteur à la recherche d'un ourson dans une image, le résutat est bien meilleur. Voici à nouveau l'image référence et le motif :
![]()
Le code sage permettant de réaliser la détection :
def phase(s): return s / abs(s) def SPOMF(img, query): pattern = center_and_extend(query, img.shape) tf_pattern = fft.rfft2(pattern).conj() tf_img = fft.rfft2(img) ret = phase(tf_img) * phase(tf_pattern) return fft.irfft2(ret) testspomf = SPOMF(ref, bear)
L'image obtenue est la suivante :
pl.figure() disp(testspomf.max() - testspomf) pl.savefig('testspomf')
![]()
Cette fois-ci, le maximum local se distingue clairement dans l'image et permet une localisation facile de l'ourson.
Localisation du motif dans l'image
Dans notre exemple, l'image obtenue est propre et comme il n'y a qu'une seule instance du motif, il n'y a qu'une seule position à trouver. Il suffit donc de chercher la position du maximum dans l'image :
def localise_max(img): m = img[0,0] for r in range(img.shape[0]): for c in range(img.shape[1]): if img[r, c] > m: m = img[r, c] pos = (r, c) return pos localise_max(testspomf)
La position trouvée est (45, 69), ce qui correspond bien à la position de l'ourson dans l'image.
Localisation avec une précision sous-pixel
La méthode est la même, il s'agit toujours de détecter un maxmim dans l'image. Mais nous allons interpoler l'image pour améliorer la précision de la localisation. Pour accélérer les calculs, nous ne travaillerons qu'avec une petite image centrée autour du maximum détecté (45, 69).
import scipy import scipy.interpolate as ip part = testspomf[44:47, 68:71]
![]()
Cette imagette 3x3 est alors interpolée sur une grille plus fine (ici dix fois plus précise). Entre chaque pixel de l'ancienne grille, une interpolation linéaire permet de trouver la valeur des pixels sur la nouvelle grille.
xrange = np.arange(part.shape[0]) yrange = np.arange(part.shape[1]) X, Y = np.meshgrid(xrange, yrange) outgrid = ip.interp2d(X,Y, part , kind='linear') xi = np.arange(0, 2.1, .1, float) yi = xi z = outgrid(xi, yi) pl.figure() disp(z) pl.savefig('interp')
![]()
Il suffit alors de rechercher la position du maximum dans l'image z, en n'oubliant pas de translater le résultat :
(r, c) = localise_max(testspomf) (dr, dc) = localise_max(z) (dr, dc) = dr/10., dc/10. (R, C) = r + dr - 1, c + dc - 1
On obtient alors R = 45.0 et C = 69.2.
Pour obtenir une précision encore plus grande, il est possible :
- d'interpoler plus finement la grille,
- ou de choisir une autre méthode d'interpolation : spline, quadratique, ...
Conclusion
Ne conserver que la phase des transformées de Fourier des images à comparer permet d'obtenir une bonne localisation du motif. Cependant, si dans la référence, les instances possèdent des orientation et des tailles différentes de l'image motif, la méthode ne peut plus fonctionner. Ou alors si les variations d'orientation et d'échelle sont faibles. Dans un prochain billet nous verrons comment encore améliorer le détecteur pour le rendre robuste à ces variations
FMN.
- Une sélection (automatique) de billets similaires :
- Détection de motifs par intercorrélation
- Aggrégateur de blogs sur l'analyse et le traitement d'images
- Un nouveau blog en analyse et traitement d'image, par Olivier Augereau
- Le jour d'Ada Lovelace : les femmes et la technologie
- L'image numérique nobélisée, l'occasion d'expliquer le fonctionnement des CCDs
Bonjour,
Félicitations pour ces articles !!
Partager la connaissance comme vous le faites est digne d'éloge, surtout dans un domaine aussi "négligé" que le traitement du signal.
Bonjour
Tres intéressant... j'espaire que je m'en sortirai avec les notion mathematique.Je vais tante de faire un implementation en C++...On peu surement trouve des application simpas.
@Olivier Huet
Si vous avez besoin de quelques compléments, n'hésitez pas.
Bonjour,
Effectivement très intéressant. Félicitations pour votre blog. Actuellement j'essaye de trouver un algorithme assez simple pour la reconnaissance de panneau routier...(projet personnel)..
j'ai essayer quelques méthodes, notamment une détection de contour (pour finalement traiter une image binaire), puis une inter-corrélation entre l'image bin et ce que je recherche, mais les résultats ne me conviennent pas... J'aimerais alors d'autre voie de recherche, que puis-je utiliser?
Mon seul support de dev aujourd'hui est matlab...
cordialement
@Wedajo Brouk,
merci pour les félicitations, cela fait toujours plaisir.
L'inter-corrélation est malheureusement rarement efficace avec des images binaires. Je compte prochainement faire un billet sur ce point. Une des méthodes assez simple qui donne d'assez bons résultats est le Chamfer matching. Si les motifs recherchés ne présentent pas trop de variations en échelle et rotation, cela peut fonctionner. Une description du principe peut être trouvée ici . La méthode est basée sur des transformée en distance, disponible avec Matlab si ma mémoire est bonne. Je travaille actuellement sur des évolutions de cette méthode. Voir par exemple mon papier : "détection d’objet par mesure de dissimilarités locales" présenté au gretsi (tu peux télécharger le pdf).
Pour une méthode vraiment robuste en échelle et rotation, il faudrait se tourner vers quelque chose de plus évolué : le SIFT est à la mode en se moment.
J'ai abandonné Matlab il y a quelques années, vraiment dégouté par leur politique de non compatibilité entre les versions. Et puis pour de gros projets, les choses deviennent vite ingérable.
bon courage, et tiens moi au courant de l'évolution du projet.
Bonjour, peut on utiliser ces techniques afin de déterminer parmi une liste d'image celle qui est la plus proche d'une image de référence ?
Bonjour,
oui cette méthode est utilisable dans ce sens. Cependant ce n'est pas la plus efficace. La difficulté provient de ce que l'on entend par "plus proche". Est-ce au niveau sémantique? Veut-ton comparer les informations structurelles? De bonne méthodes actuellement utilisées sont : le SSIM, des comparaisons à base de descripteurs SIFT (ou variantes), une inter-corrélation normalisée (qui se rapproche dans l'esprit de la méthode du billet). Je suis également obligé de parler de la LDMAP (méthode proposée par mon équipe), dont je parle ici, si les images sont binaires.
Plutôt au niveau de la structure et non ce ne sont pas des images binaires. Je ne suis pas un expert dans ce domaine donc je suis plutôt à la recherche de librairies qui implémenteraient les techniques citées.
Pour comparer deux images au niveau structure, l'approche phase seule (décrite dans le billet) est correcte. Je vous conseille également de tester le SSIM, dont vous trouverez facilement des implémentations sur le net.