L'un des projets les plus intéressants sur lesquels j'ai travaillé ces dernières années était un projet sur le traitement d'image . L'objectif était de développer un système permettant de reconnaître les «canettes» de Coca-Cola (notez que j'insiste sur le mot «canettes», vous verrez pourquoi dans une minute). Vous pouvez voir un exemple ci-dessous, avec la boîte reconnue dans le rectangle vert avec échelle et rotation.
Quelques contraintes sur le projet:
- Le fond peut être très bruyant.
- La boîte peut avoir n'importe quelle échelle ou rotation ou même orientation (dans des limites raisonnables).
- L'image peut présenter un certain flou (les contours peuvent ne pas être entièrement droits).
- Il pourrait y avoir des bouteilles de Coca-Cola dans l'image, et l'algorithme ne devrait détecter que la boîte !
- La luminosité de l'image peut varier considérablement (vous ne pouvez donc pas vous fier "trop" à la détection des couleurs).
- La boîte peut être partiellement cachée sur les côtés ou au milieu et peut-être partiellement cachée derrière une bouteille.
- Il ne pouvait y avoir aucune boîte du tout dans l'image, auquel cas vous deviez ne rien trouver et écrire un message le disant.
Vous pourriez donc vous retrouver avec des choses délicates comme celle-ci (qui dans ce cas, mon algorithme a totalement échoué):
J'ai fait ce projet il y a quelque temps, et je me suis beaucoup amusé à le faire, et j'ai eu une mise en œuvre décente. Voici quelques détails sur ma mise en œuvre:
Langage : fait en C ++ à l'aide de la bibliothèque OpenCV .
Prétraitement : Pour le prétraitement de l'image, c'est-à-dire transformer l'image en une forme plus brute à donner à l'algorithme, j'ai utilisé 2 méthodes:
- Changement du domaine de couleur de RVB à HSV et filtrage basé sur la teinte "rouge", saturation au-dessus d'un certain seuil pour éviter les couleurs orange, et filtrage de faible valeur pour éviter les tons sombres. Le résultat final était une image binaire en noir et blanc, où tous les pixels blancs représenteraient les pixels correspondant à ce seuil. Évidemment, il y a encore beaucoup de merde dans l'image, mais cela réduit le nombre de dimensions avec lesquelles vous devez travailler.
- Filtrage du bruit utilisant le filtrage médian (en prenant la valeur médiane des pixels de tous les voisins et en remplaçant le pixel par cette valeur) pour réduire le bruit.
- Utilisation du filtre de détection Canny Edge pour obtenir les contours de tous les éléments après 2 étapes précédentes.
Algorithme : L'algorithme lui-même que j'ai choisi pour cette tâche est tiré de ce livre génial sur l'extraction de fonctionnalités et appelé Generalized Hough Transform (assez différent de la Hough Transform régulière). Cela dit essentiellement quelques choses:
- Vous pouvez décrire un objet dans l'espace sans connaître son équation analytique (ce qui est le cas ici).
- Il résiste aux déformations de l'image telles que la mise à l'échelle et la rotation, car il testera essentiellement votre image pour chaque combinaison de facteur d'échelle et de facteur de rotation.
- Il utilise un modèle de base (un modèle) que l'algorithme "apprendra".
- Chaque pixel restant dans l'image de contour votera pour un autre pixel qui sera censé être le centre (en termes de gravité) de votre objet, en fonction de ce qu'il a appris du modèle.
En fin de compte, vous vous retrouvez avec une carte thermique des votes, par exemple ici, tous les pixels du contour de la boîte voteront pour son centre de gravité, vous aurez donc beaucoup de votes dans le même pixel correspondant à la centre, et verra un pic dans la carte de chaleur comme ci-dessous:
Une fois que vous avez cela, une simple heuristique basée sur un seuil peut vous donner l'emplacement du pixel central, à partir duquel vous pouvez dériver l'échelle et la rotation, puis tracer votre petit rectangle autour d'elle (l'échelle finale et le facteur de rotation seront évidemment relatifs à votre modèle original). En théorie au moins ...
Résultats : Maintenant, bien que cette approche ait fonctionné dans les cas de base, elle faisait gravement défaut dans certains domaines:
- C'est extrêmement lent ! Je n'insiste pas assez sur cela. Il a fallu presque une journée entière pour traiter les 30 images de test, évidemment parce que j'avais un facteur d'échelle très élevé pour la rotation et la translation, car certaines des boîtes étaient très petites.
- Il était complètement perdu lorsque les bouteilles étaient dans l'image, et pour une raison quelconque, il a presque toujours trouvé la bouteille au lieu de la boîte (peut-être parce que les bouteilles étaient plus grandes, avaient donc plus de pixels, donc plus de votes)
- Les images floues n'étaient également pas bonnes, car les votes se sont retrouvés en pixels à des emplacements aléatoires autour du centre, se terminant ainsi par une carte thermique très bruyante.
- Un écart dans la translation et la rotation a été obtenu, mais pas dans l'orientation, ce qui signifie qu'une boîte qui n'était pas directement face à l'objectif de la caméra n'a pas été reconnue.
Pouvez-vous m'aider à améliorer mon algorithme spécifique , en utilisant exclusivement des fonctionnalités OpenCV , pour résoudre les quatre problèmes spécifiques mentionnés?
J'espère que certaines personnes en tireront également des leçons, après tout, je pense que non seulement les personnes qui posent des questions devraient apprendre. :)