Ce post a été le point de départ de ma solution, beaucoup de bonnes idées ici, alors j'ai pensé que je pourrais partager mes résultats. L'idée principale est que j'ai trouvé un moyen de contourner la lenteur de la correspondance d'images basée sur les points clés en exploitant la vitesse de phash.
Pour la solution générale, il est préférable d'employer plusieurs stratégies. Chaque algorithme est mieux adapté à certains types de transformations d'images et vous pouvez en tirer parti.
En haut, les algorithmes les plus rapides ; en bas, les plus lents (mais plus précis). Vous pouvez ignorer les algorithmes lents si vous trouvez une bonne correspondance au niveau le plus rapide.
- basé sur le hachage des fichiers (md5, sha1, etc.) pour les doublons exacts
- hachage perceptuel (phash) pour les images remises à l'échelle
- basé sur les caractéristiques (SIFT) pour les images modifiées
J'ai de très bons résultats avec phash. La précision est bonne pour les images redimensionnées. Elle n'est pas bonne pour les images modifiées (perceptuellement) (recadrées, tournées, reflétées, etc.). Pour gérer la vitesse de hachage, nous devons utiliser un cache disque/base de données pour maintenir les hachages de la meule de foin.
Ce qui est vraiment bien avec phash, c'est qu'une fois que vous avez construit votre base de données de hachage (qui pour moi est d'environ 1000 images/sec), les recherches peuvent être très, très rapides, en particulier lorsque vous pouvez tenir toute la base de données de hachage en mémoire. C'est assez pratique puisqu'un hash ne fait que 8 octets.
Par exemple, si vous avez 1 million d'images, il vous faudra un tableau de 1 million de valeurs de hachage de 64 bits (8 Mo). Sur certains processeurs, cela tient dans le cache L2/L3 ! Dans la pratique, j'ai vu un corei7 se comparer à plus de 1 Giga-hamm/sec, ce n'est qu'une question de bande passante mémoire vers le CPU. Une base de données d'un milliard d'images est réalisable sur un CPU 64-bit (8GB RAM nécessaire) et les recherches ne dépasseront pas 1 seconde !
Pour les images modifiées/cadrées, il semblerait qu'un détecteur de caractéristiques/de points clés invariant par transformation comme SIFT soit la solution. SIFT produira de bons points clés qui permettront de détecter les recadrages, les rotations, les miroirs, etc. Cependant, la comparaison des descripteurs est très lente par rapport à la distance de Hamming utilisée par Phash. C'est une limitation majeure. Il y a beaucoup de comparaisons à faire, puisqu'il y a un maximum de IxJxK comparaisons de descripteurs pour rechercher une image (I=nombre d'images de botte de foin, J=points clés cibles par image de botte de foin, K=points clés cibles par image d'aiguille).
Pour contourner le problème de vitesse, j'ai essayé d'utiliser le phash autour de chaque point clé trouvé, en utilisant la taille/rayon de l'élément pour déterminer le sous-rectangle. L'astuce pour que cela fonctionne bien, est d'augmenter/réduire le rayon pour générer différents niveaux de sous-rectangle (sur l'image de l'aiguille). En général, le premier niveau (non mis à l'échelle) correspond, mais il en faut souvent plusieurs. Je ne suis pas sûr à 100% de la raison pour laquelle cela fonctionne, mais j'imagine que cela permet d'obtenir des caractéristiques trop petites pour que phash puisse fonctionner (phash met à l'échelle les images jusqu'à 32x32).
Un autre problème est que SIFT ne distribue pas les points clés de manière optimale. Si une section de l'image comporte beaucoup de bords, les points clés s'y regrouperont et vous n'en aurez pas dans une autre zone. J'utilise le GridAdaptedFeatureDetector dans OpenCV pour améliorer la distribution. Je ne sais pas quelle taille de grille est la meilleure, j'utilise une petite grille (1x3 ou 3x1 selon l'orientation de l'image).
Vous voudrez probablement mettre à l'échelle toutes les images de la botte de foin (et de l'aiguille) à une taille plus petite avant la détection des caractéristiques (j'utilise 210px le long de la dimension maximale). Cela réduira le bruit dans l'image (toujours un problème pour les algorithmes de vision par ordinateur), et permettra également de concentrer le détecteur sur les caractéristiques les plus saillantes.
Pour les images de personnes, vous pouvez essayer la détection des visages et l'utiliser pour déterminer la taille de l'image à mettre à l'échelle et la taille de la grille (par exemple, le plus grand visage mis à l'échelle pour être de 100px). Le détecteur de visage prend en compte plusieurs niveaux d'échelle (en utilisant des pyramides) mais il y a une limite au nombre de niveaux qu'il utilisera (ceci est réglable bien sûr).
Le détecteur de points clés fonctionne probablement mieux lorsqu'il renvoie moins que le nombre de caractéristiques souhaitées. Par exemple, si vous demandez 400 et obtenez 300, c'est bien. Si vous obtenez 400 à chaque fois, il est probable que de bonnes caractéristiques ont dû être écartées.
L'image de l'aiguille peut avoir moins de points clés que les images de la botte de foin et obtenir quand même de bons résultats. L'ajout de points clés ne permet pas nécessairement d'obtenir des gains énormes. Par exemple, avec J=400 et K=40, mon taux de réussite est d'environ 92 %. Avec J=400 et K=400, le taux de réussite ne monte qu'à 96%.
Nous pouvons tirer parti de l'extrême rapidité de la fonction de Hamming pour résoudre les problèmes de mise à l'échelle, de rotation, de mise en miroir, etc. Une technique à passages multiples peut être utilisée. À chaque itération, on transforme les sous-rectangles, on les remet en mémoire et on exécute à nouveau la fonction de recherche.