web-dev-qa-db-fra.com

Traitement des images: Amélioration de l'algorithme pour la reconnaissance 'Coca-Cola Can'

L'un des projets les plus intéressants sur lesquels j'ai travaillé au cours des deux dernières années était un projet sur le traitement d'images . Le but était de développer un système capable de reconnaître Coca-Cola 'canettes' (notez que je souligne le mot 'canettes', vous verrez pourquoi dans une minute). Vous pouvez voir un exemple ci-dessous, avec la canette reconnue dans le rectangle vert avec échelle et rotation.

Template matching

Quelques contraintes sur le projet:

  • Le fond pourrait être très bruyant.
  • Le peut pourrait avoir n'importe quelle échelle ou rotation ou même une orientation (dans des limites raisonnables).
  • L'image peut avoir un certain flou (les contours peuvent ne pas être tout à fait droits).
  • Il pourrait y avoir des bouteilles de Coca-Cola dans l’image, et l’algorithme ne devrait détecter que le can!
  • La luminosité de l'image peut varier beaucoup (vous ne pouvez donc pas vous fier trop à la détection des couleurs).
  • Le can pourrait être en partie caché sur les côtés ou au centre et éventuellement en partie caché derrière une bouteille.
  • Il ne peut y avoir aucun peut dans l'image, auquel cas vous devez ne rien trouver et écrire un message vous le signalant.

Donc, vous pourriez vous retrouver avec des choses difficiles comme celle-ci (dans laquelle mon algorithme échouait totalement dans ce cas):

Total fail

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:

Language: Fait en C++ avec OpenCV library.

Pré-traitement: pour le pré-traitement de l’image, c’est-à-dire pour transformer l’image en une forme plus brute à donner à l’algorithme, j’ai utilisé 2 méthodes:

  1. Modification du domaine de couleur de RVB à HSV et filtrage en fonction de la teinte «rouge», saturation au-dessus d'un certain seuil pour éviter les couleurs semblables à l'orange et filtrage par faible valeur pour éviter les tons sombres. Le résultat final est une image binaire en noir et blanc, où tous les pixels blancs représentent les pixels correspondant à ce seuil. De toute évidence, il y a encore beaucoup de merde dans l'image, mais cela réduit le nombre de dimensions avec lesquelles vous devez travailler .Binarized image
  2. Filtrage du bruit utilisant le filtrage médian (prenant la valeur de pixel médiane de tous les voisins et remplaçant le pixel par cette valeur) pour réduire le bruit.
  3. Utilisation de Filtre de détection Canny Edge pour obtenir les contours de tous les éléments après 2 étapes précédentes .Contour detection

Algorithm: L'algorithme que j'ai choisi pour cette tâche a été pris à partir de this livre génial sur l'extraction de fonctionnalités et appelé Generalized Hough Transform (assez différent de la transformation de Hough standard). Il 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 va "apprendre".
  • 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.

Au final, vous obtenez une carte thermique des votes. Par exemple, ici, tous les pixels du contour de la boîte peuvent voter pour son centre de gravité, de sorte que vous disposerez de nombreux votes dans le même pixel, ce qui correspond au centre, et verra un pic dans la carte de chaleur comme ci-dessous:

GHT

Une fois que vous avez cela, une simple heuristique basée sur des seuils 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 de lui (l’échelle finale et le facteur de rotation seront évidemment relatifs à votre image. modèle d'origine). En théorie au moins ...

Résultats: Alors que cette approche fonctionnait dans les cas de base, elle manquait cruellement dans certains domaines:

  • C'est extrêmement lent! Je ne le souligne pas assez. Il a fallu presque une journée entière pour traiter les 30 images test, évidemment parce que mon facteur d'échelle pour la rotation et la traduction était très élevé, car certaines des boîtes étaient très petites.
  • Il était complètement perdu lorsque les bouteilles figuraient dans l'image et, pour une raison quelconque, presque toujours trouvé la bouteille à la place de la canette (peut-être parce que les bouteilles étaient plus grandes, donc plus de pixels, donc plus de votes)
  • Les images floues ne sont pas bonnes non plus, puisque les votes se sont terminés en pixels à des emplacements aléatoires autour du centre, se terminant ainsi avec une carte de chaleur très bruyante.
  • Une différence de translation et de rotation a été obtenue, mais pas d’orientation, ce qui signifie qu’une canette qui ne faisait pas directement face à l’objectif de la caméra n’était pas reconnue.

Pouvez-vous m'aider à améliorer mon algorithme spécifique, en utilisant les fonctionnalités exclusivement OpenCV, afin de résoudre les problèmes quatre spécifiques mentionnés?

J'espère que certaines personnes apprendront également quelque chose, après tout, je pense que non seulement les personnes qui posent des questions devraient apprendre. :)

1485
Charles Menguy

Une autre approche consisterait à extraire des entités (points-clés) à l'aide de transformation d'entité invariante à l'échelle } (SIFT) ou fonctionnalités robustes accélérées (SURF).

Il est implémenté dans OpenCV 2.3.1.

Vous pouvez trouver un exemple de code Nice utilisant des fonctionnalités dans FEATURES2D + HOMOGRAPHIE POUR RECHERCHER UN OBJET CONNU }

Les deux algorithmes sont invariants pour la mise à l'échelle et la rotation. Comme ils fonctionnent avec des fonctionnalités, vous pouvez également gérer occlusion (tant que suffisamment de points-clés sont visibles).

Enter image description here

Source de l'image: exemple de tutoriel

Le traitement prend quelques centaines de ms pour SIFT, SURF est un peu plus rapide, mais il ne convient pas aux applications en temps réel. ORB utilise FAST, qui est plus faible en ce qui concerne l'invariance de rotation.

Les papiers originaux

604
stacker

Pour accélérer les choses, je voudrais tirer parti du fait qu'il ne vous est pas demandé de trouver une image/un objet quelconque, mais en particulier un avec le logo Coca-Cola. Cela est significatif car ce logo est très distinctif et il devrait avoir une signature caractéristique, invariante à l'échelle dans le domaine fréquentiel, en particulier dans le canal rouge de RVB. C'est-à-dire que le motif alterné de rouge à blanc à rouge rencontré par une ligne de balayage horizontale (formée sur un logo aligné horizontalement) aura un "rythme" distinctif lorsqu'il passera par l'axe central du logo. Ce rythme "accélérera" ou "ralentira" à différentes échelles et orientations, mais restera proportionnellement équivalent. Vous pouvez identifier/définir quelques dizaines de lignes de balayage de ce type, à la fois horizontalement et verticalement à travers le logo et plusieurs autres en diagonale, selon un motif étoilé. Appelez cela les "lignes de balayage de signature".

Signature scan line

La recherche de cette signature dans l’image cible consiste simplement à numériser l’image en bandes horizontales. Recherchez une fréquence élevée dans le canal rouge (indiquant le passage d'une région rouge à une région blanche). Une fois la recherche effectuée, vérifiez si elle est suivie d'un des rythmes de fréquence identifiés lors de la séance d'entraînement. Une fois qu'une correspondance est trouvée, vous saurez instantanément l'orientation et la position de la ligne de balayage dans le logo (si vous gardez une trace de ces éléments pendant l'entraînement), ainsi l'identification des limites du logo à partir de là est triviale. 

Je serais surpris que ce ne soit pas un algorithme linéairement efficace, ou presque. Cela ne traite évidemment pas de votre discrimination, mais au moins, vous aurez vos logos. 

(Mise à jour: pour la reconnaissance de la bouteille, je rechercherais du coke (le liquide brun) à côté du logo, c’est-à-dire, la bouteille à {à l'intérieur}. Ou, dans le cas d'une bouteille vide, je rechercherais cap qui aura toujours la même forme de base, la même taille et la même distance par rapport au logo et sera généralement tout blanc ou rouge. Recherchez une forme elliptique de couleur unie dans laquelle un bonnet devrait être , par rapport au logo. Pas infaillible bien sûr, mais votre objectif ici devrait être de trouver les faciles ceux (rapides.)

(Cela fait quelques années que je ne traite plus les images, j'ai donc gardé cette suggestion de haut niveau et conceptuelle. Je pense que cela pourrait donner une idée approximative de la façon dont un œil humain pourrait fonctionner - ou du moins de la façon dont mon cerveau fonctionne!)

349
kmote

Problème amusant: quand j'ai jeté un coup d'œil sur votre image de bouteille, j'ai pensé que c'était aussi une canette. Mais, en tant qu'être humain, ce que j'ai fait pour faire la différence, c'est que j'ai alors remarqué que c'était aussi une bouteille ...

Alors, pour distinguer les canettes et les bouteilles, pourquoi ne pas simplement commencer par chercher des bouteilles? Si vous en trouvez un, masquez l'étiquette avant de chercher des canettes.

Pas trop difficile à mettre en œuvre si vous faites déjà des canettes. Le véritable inconvénient est qu'il double votre temps de traitement. (Mais si vous envisagez des applications réelles, vous finirez par vouloir faire des bouteilles de toute façon ;-)

142
Darren Cook

N'est-il pas difficile, même pour l'homme, de faire la distinction entre une bouteille et une canette dans la seconde image (à condition que la zone transparente de la bouteille soit masquée)?

Ils sont presque les mêmes sauf pour une très petite région (c’est-à-dire que la largeur au sommet de la boîte est un peu petite alors que l’emballage de la bouteille a la même largeur, mais un changement mineur n’est pas vrai?)

La première chose qui me vint à l’esprit fut de vérifier le haut de la bouteille rouge. Mais le problème persiste s’il n’ya pas de bouchon pour la bouteille ou si elle est partiellement cachée (comme mentionné ci-dessus).

La deuxième chose à laquelle je pensais concernait la transparence de la bouteille. OpenCV a quelques travaux pour trouver des objets transparents dans une image. Vérifiez les liens ci-dessous.

Regardez particulièrement ceci pour voir avec quelle précision ils détectent le verre:

Voir leur résultat d'implantation:

Enter image description here

Ils disent que c'est la mise en œuvre du document "Un cadre de contour actif géodésique pour trouver du verre" de K. McHenry et J. Ponce, CVPR 2006 .

Cela peut être utile dans votre cas un peu, mais le problème se pose à nouveau si la bouteille est remplie.

Je pense donc que vous pouvez rechercher d’abord le corps transparent des bouteilles ou une zone rouge connectée à deux objets transparents latéralement, qui est évidemment la bouteille. (Lorsque vous travaillez idéalement, une image comme suit.)

Enter image description here

Vous pouvez maintenant supprimer la région jaune, c'est-à-dire l'étiquette du flacon, et exécuter votre algorithme pour rechercher la canette.

Quoi qu'il en soit, cette solution pose également différents problèmes, comme dans les autres solutions.

  1. Cela ne fonctionne que si votre bouteille est vide. Dans ce cas, vous devrez rechercher la région rouge entre les deux couleurs noires (si le liquide Coca Cola est noir).
  2. Un autre problème si la partie transparente est couverte.

Quoi qu'il en soit, s'il n'y a aucun des problèmes ci-dessus dans les images, cela semble être une meilleure solution.

113
Abid Rahman K

J'aime beaucoup (Darren Cook) et les réponses de l'empileur à ce problème. J'étais en train d'exprimer mes commentaires sur ces remarques, mais je crois que mon approche est trop en forme de réponse pour ne pas partir d'ici.

En résumé, vous avez identifié un algorithme permettant de déterminer qu'un logo Coca-Cola est présent à un endroit particulier de l'espace. Vous essayez maintenant de déterminer, pour des orientations arbitraires et des facteurs d'échelle arbitraires, une heuristique permettant de distinguer Coca-Cola canettes des autres objets, notamment: bouteilles, panneaux publicitaires, publicités, et des accessoires Coca-Cola, tous associés à ce logo emblématique. Vous ne mentionnez pas beaucoup de cas supplémentaires dans votre énoncé de problème, mais j'estime qu'ils sont essentiels au succès de votre algorithme.

Le secret consiste à déterminer quelles caractéristiques visuelles un can contient ou, à travers l’espace négatif, quelles sont les fonctionnalités présentes pour les autres produits Coca-Cola qui ne le sont pas pour les canettes. À cette fin, la réponse actuelle la plus récente _ _ esquisse une approche de base pour sélectionner «peut» si et seulement si «bouteille» n'est pas identifié, soit par la présence d'un bouchon de bouteille, d'un liquide ou d'un autre visuel similaire. heuristiques.

Le problème est que cela tombe en panne. Une bouteille peut, par exemple, être vide et ne pas comporter de bouchon, ce qui donnerait un faux positif. Ou bien, cela pourrait être une bouteille partielle avec des fonctionnalités supplémentaires mutilées, conduisant à nouveau à une fausse détection. Inutile de dire que cela n’est ni élégant ni efficace pour nos objectifs.

À cette fin, les critères de sélection les plus corrects pour les canettes semblent être les suivants:

  • La forme de la silhouette de l'objet, comme vous avez esquissé votre question }, est-elle correcte? Si oui, +1.
  • Si nous supposons la présence de lumière naturelle ou artificielle, détectons-nous un contour chromé sur la bouteille qui indique si celle-ci est en aluminium? Si oui, +1.
  • Déterminons-nous que les propriétés spéculaires de l'objet sont correctes, par rapport à nos sources de lumière ( lien vidéo illustratif sur détection de source de lumière )? Si oui, +1.
  • Pouvons-nous déterminer d’autres propriétés de l’objet qui l’identifient comme une canette, y compris, mais sans y être limité, l’asymne topologique du logo, l’orientation de l’objet, la juxtaposition de l’objet (par exemple, sur une surface plane comme une table ou dans le contexte des autres canettes), et la présence d'une tirette? Si oui, pour chacun, +1.

Votre classification pourrait alors ressembler à ceci:

  • Pour chaque correspondance, si un logo Coca Cola était détecté, tracez une bordure grise.
  • Pour chaque match au-dessus de +2, tracez une bordure rouge.

Ceci montre visuellement à l'utilisateur ce qui a été détecté, en insistant sur les positifs faibles qui peuvent, correctement, être détectés comme des boîtes de conserve mutilées.

La détection de chaque propriété entraîne une complexité temporelle et spatiale très différente et, pour chaque approche, un passage rapide à travers http://dsp.stackexchange.com est plus que raisonnable pour déterminer la solution la plus correcte et la plus efficace. algorithme pour vos besoins. Mon intention ici est, purement et simplement, de souligner que détecter si quelque chose est une boîte de conserve en invalidant une petite partie de l’espace de détection candidat n’est pas la solution la plus robuste ou la plus efficace à ce problème et, idéalement, vous devriez: prendre les mesures appropriées en conséquence.

Et hé, félicitations pour le le post de Hacker News! Dans l’ensemble, c’est une question plutôt terrible digne de la publicité qu’elle a reçue. :)

47
MrGomez

Regardant la forme

Prenez un coup d'oeil à la forme de la partie rouge de la canette/bouteille. Remarquez comment la canette s’efface légèrement au sommet alors que l’étiquette de la bouteille est droite. Vous pouvez faire la distinction entre ces deux types en comparant la largeur de la partie rouge sur toute sa longueur.

Regard sur les faits saillants

Le matériau permet de distinguer les bouteilles des canettes. Une bouteille est en plastique alors qu'une canette est en aluminium. Dans des situations suffisamment éclairées, examiner la spécularité serait un moyen de distinguer une étiquette de bouteille d’une étiquette de boîte de conserve.

Autant que je sache, c’est ainsi qu’un humain ferait la différence entre les deux types d’étiquettes. Si les conditions d’éclairage sont mauvaises, il y aura certainement une certaine incertitude à distinguer les deux. Dans ce cas, vous devez pouvoir détecter la présence du flacon transparent/translucide lui-même.

39
tskuzzy

S'il vous plaît jeter un oeil à Zdenek Kalal Tracker Predator . Cela nécessite un peu de formation, mais il peut apprendre activement comment l’objet suivi considère différentes orientations et échelles et le fait en temps réel!

Le code source est disponible sur son site. C'est dans MATLAB , mais peut-être qu'un membre de la communauté a déjà implémenté Java. J'ai ré-implémenté avec succès la partie traqueur de TLD en C #. Si je me souviens bien, TLD utilise Ferns comme détecteur de points-clés. J'utilise soit SURF ou SIFT (déjà suggéré par @stacker) pour réacquérir l'objet s'il était perdu par le suivi. Les commentaires du traqueur facilitent la construction, avec le temps, d’une liste dynamique de modèles de tamisage/surf permettant de réacquérir l’objet avec une très grande précision.

Si mon implémentation C # du tracker vous intéresse, n'hésitez pas à demander.

35
user1222021

Si vous n'êtes pas limité à une caméra qui ne fait pas partie de vos contraintes, vous pouvez peut-être utiliser un capteur de distance comme la Xbox Kinect . Avec cela, vous pouvez effectuer une segmentation de l'image basée sur la couleur et la profondeur. Cela permet une séparation plus rapide des objets dans l'image. Vous pouvez ensuite utiliser la mise en correspondance ICP ou des techniques similaires pour même épouser la forme de la boîte plutôt que simplement son contour ou sa couleur. Étant donné qu’elle est cylindrique, cette option peut être valide pour toute orientation si vous avez déjà effectué une numérisation 3D de la cible. Ces techniques sont souvent assez rapides, surtout lorsqu'elles sont utilisées à des fins spécifiques, ce qui devrait résoudre votre problème de vitesse. 

Je pourrais également suggérer, pas nécessairement pour des raisons de précision ou de rapidité, mais pour le plaisir, vous pouvez utiliser un réseau de neurones formé sur votre image segmentée de teinte pour identifier la forme de la boîte. Celles-ci sont très rapides et peuvent souvent être précises à 80/90%. La formation serait un peu un long processus, car il vous faudrait identifier manuellement la boîte de conserve dans chaque image. 

30
Fantastic Mr Fox

Je détecte les rectangles rouges: RVB -> HSV, filtre rouge -> image binaire, proche (dilate puis érode, appelée imclose dans matlab)

Regardez ensuite dans les rectangles du plus grand au plus petit. Les rectangles qui ont des rectangles plus petits dans une position/une échelle connue peuvent être supprimés (en supposant que les proportions des bouteilles soient constantes, le rectangle plus petit serait un bouchon de bouteille). 

Cela vous laisserait avec des rectangles rouges, alors vous devrez d'une manière ou d'une autre détecter les logos pour indiquer s'ils sont un rectangle rouge ou une canette de coca. Comme OCR, mais avec un logo connu?

21
Alex L

Cela peut être une idée très naïve (ou peut ne pas fonctionner du tout), mais les dimensions de toutes les canettes de coke sont fixes. Si la même image contient à la fois une canette et une bouteille, vous pouvez les distinguer en fonction de leur taille (les bouteilles seront plus grandes). Maintenant, à cause de la profondeur manquante (c'est-à-dire de la cartographie 3D à la cartographie 2D), il est possible qu'une bouteille apparaisse réduite et qu'il n'y ait pas de différence de taille. Vous pouvez récupérer des informations de profondeur à l’aide de stereo-imaging , puis récupérer la taille originale. 

20
Sharad

Je ne suis pas au courant d'OpenCV, mais si je regarde le problème de manière logique, je pense que vous pouvez faire la différence entre une bouteille et une autre en modifiant l'image que vous recherchez, à savoir Coca Cola. Vous devez incorporer jusqu’à la partie supérieure de la canette car dans le cas d’une canette, il ya une doublure argentée au sommet de la coca-cola et en cas de bouteille, cette doublure ne sera pas argentée.

Mais évidemment, cet algorithme échouera dans les cas où le haut de la canette est caché, mais dans ce cas, même l’être humain ne pourra pas différencier les deux (si seule la portion de bouteille/canette de coca-cola est visible)

15
techExplorer

J'aime le défi et je voulais donner une réponse qui résout le problème, je pense. 

  1. Extraire les caractéristiques (points-clés, descripteurs tels que SIFT, SURF) du logo 
  2. Faites correspondre les points avec une image modèle du logo (en utilisant Matcher tel que Brute Force)
  3. Estimer les coordonnées du corps rigide (problème PnP - SolvePnP)
  4. Estimer la position du capuchon en fonction du corps rigide 
  5. Effectuez une rétro-projection et calculez la position du pixel de l'image (ROI) du bouchon de la bouteille (je suppose que vous avez les paramètres intrinsèques de la caméra)
  6. Vérifiez avec une méthode si le plafond est là ou non. Si c'est le cas, c'est la bouteille 

La détection du bouchon est un autre problème. Cela peut être compliqué ou simple. Si j'étais vous, je vérifierais simplement l'histogramme de couleur dans le retour sur investissement pour prendre une décision simple. 

S'il vous plaît, donnez les commentaires si je me trompe. Merci. 

13
edayangac

Vous avez besoin d'un programme qui apprend et améliore la précision de la classification de manière organique à partir de votre expérience. 

Je proposerai un apprentissage en profondeur, ce qui devient un problème trivial. 

Vous pouvez recycler le modèle Inception v3 sur Tensorflow:

Comment recycler la couche finale de Inception pour les nouvelles catégories .

Dans ce cas, vous entraînerez un réseau de neurones de convolution pour classer un objet dans une boîte de conserve ou non.

10
Nuelsian

De nombreux descripteurs de couleurs sont utilisés pour reconnaître les objets. Le document ci-dessous en compare beaucoup. Ils sont particulièrement puissants lorsqu'ils sont combinés avec SIFT ou SURF. SURF ou SIFT seuls ne sont pas très utiles dans une image de coca-cola car ils ne reconnaissent pas beaucoup de points d’intérêt, vous avez besoin des informations de couleur pour vous aider. J'utilise BIC (classi fi cation de bordures/pixels intérieurs) avec SURF dans un projet et cela a très bien fonctionné pour reconnaître des objets.

Descripteurs de couleur pour la récupération d'images Web: une étude comparative

10

J'aime votre question, que ce soit hors sujet ou non: P

Un aparté intéressant; Je viens de terminer une matière de mon diplôme où nous avons abordé la robotique et la vision par ordinateur. Notre projet pour le semestre était incroyablement similaire à celui que vous décrivez.

Nous avons dû développer un robot utilisant une Xbox Kinect pour détecter les bouteilles et les canettes de coke, quelle que soit leur orientation, dans diverses conditions d'éclairage et d'environnement. Notre solution consistait à utiliser un filtre passe-bande sur le canal Hue en combinaison avec la transformation hough circle. Nous avons pu contraindre un peu l'environnement (nous pouvions choisir où et comment positionner le robot et le capteur Kinect), sinon nous allions utiliser les transformations SIFT ou SURF.

Vous pouvez lire sur notre approche sur mon blog sur le sujet :)

9
aaronsnoswell

J'ai quelques années de retard dans ma réponse à cette question. Avec l'état de l'art poussé à l'extrême par CNN au cours des 5 dernières années, je n'utiliserais plus OpenCV pour cette tâche maintenant! ( Je sais que vous vouliez spécifiquement les fonctionnalités OpenCv dans la question ) Je pense que des algorithmes de détection d’objets tels que Faster-RCNN, YOLO, SSD, etc. permettraient de résoudre ce problème avec une marge significative par rapport aux fonctionnalités OpenCV. Si je devais aborder ce problème maintenant (après 6 ans !!), j'utiliserais certainement Faster-RCNN .

8
Abhijit Balaji

L'apprentissage en profondeur

Rassemblez au moins quelques centaines d’images contenant des boîtes de cola, annotez-les comme des classes positives dans le cadre de sélection, incluez des bouteilles de cola et d’autres produits contenant des étiquettes de cola. 

Sauf si vous collectez un très grand ensemble de données, utilisez des fonctionnalités d'apprentissage approfondi pour de petits ensembles de données. Idéalement, utilisez une combinaison de machines à vecteurs de support (SVM) avec des réseaux de neurones profonds.

Une fois que vous avez inséré les images dans un modèle d’apprentissage en profondeur déjà formé (par exemple, GoogleNet), au lieu d’utiliser la couche décision (réseau final) du réseau de neurones pour effectuer des classifications, utilisez les données des couches précédentes comme fonctionnalités pour former votre classifieur.

OpenCV et Google Net: http://docs.opencv.org/trunk/d5/de7/tutorial_dnn_googlenet.html

OpenCV et SVM: http://docs.opencv.org/2.4/doc/tutorials/ml/introduction_to_svm/introduction_to_svm.html

8
Semih Korkmaz

Comme alternative à toutes ces solutions de Nice, vous pouvez former votre propre classificateur et rendre votre application robuste aux erreurs. Par exemple, vous pouvez utiliser Haar Training , en fournissant un bon nombre d'images positives et négatives de votre cible.

Il peut être utile d'extraire uniquement des boîtes de conserve et peut être combiné à la détection d'objets transparents.

6
madduci

Il existe un paquet de vision par ordinateur appelé HALCON de MVTec dont les démos peuvent vous donner de bonnes idées d’algorithme. Il existe de nombreux exemples similaires à votre problème que vous pouvez exécuter en mode démonstration, puis consulter les opérateurs du code et voir comment les implémenter à partir d'opérateurs OpenCV existants. 

J'ai utilisé ce package pour prototyper rapidement des algorithmes complexes pour des problèmes de ce type, puis trouver comment les implémenter à l'aide des fonctionnalités OpenCV existantes. Dans votre cas, vous pourriez notamment essayer de mettre en œuvre dans OpenCV la fonctionnalité intégrée dans l'opérateur find_scaled_shape_model . Certains opérateurs font référence au document scientifique concernant la mise en œuvre d'un algorithme, qui peut aider à déterminer comment faire quelque chose de similaire dans OpenCV. J'espère que cela t'aides...

2
Darien Pardinas

Les premières choses que je voudrais rechercher sont les couleurs - comme le ROUGE, lors de la détection des yeux rouges dans une image - il y a une certaine plage de couleurs à détecter, certaines caractéristiques la considérant en fonction de la zone environnante et telle que la distance qui le sépare de l'autre œil. est bien visible dans l'image.

1: La première caractéristique est la couleur et le rouge est très dominant. Après avoir détecté le rouge Coca-Cola, plusieurs éléments d’intérêt vous intéressent. 1 .1B: Contient-il la couleur de l'étiquette - "Coca-Cola" ou vague? 1B1: Y a-t-il suffisamment de risques de considérer qu'il s'agit d'une étiquette?.

L'élément 1 est une sorte de raccourci - pré-processus si cette morue n'existe pas dans l'image - passez à autre chose.

Donc, si tel est le cas, je peux ensuite utiliser ce segment de mon image et commencer à regarder un peu plus le zoom sur la zone en question - regardez essentiellement la région/les bords environnants ...

2: Etant donné que la zone d’image ci-dessus est identifiée en 1 - vérifiez les points [bords] environnants de l’article en question . A: Existe-t-il ce qui semble être une canette en haut ou en bas - argent??. B: Une bouteille peut sembler transparente, mais une table en verre l'est aussi - y a-t-il une table/étagère en verre ou une zone transparente - le cas échéant, plusieurs sorties sont possibles. Une bouteille PEUT avoir un bouchon rouge, ce n’est peut-être pas le cas, mais elle devrait avoir soit la forme du bouchon du bouchon/des vis à filetage, soit un bouchon. C: Même si cela échoue A et B, cela peut toujours être une possibilité - partielle .. C’est plus complexe quand elle est partielle parce qu’une bouteille partielle/partielle peut avoir le même aspect, la mesure de la région rouge bord à bord .. petite bouteille pourrait être similaire en taille ..

3: Après l'analyse ci-dessus, c'est à ce moment-là que je regarderais le lettrage et le logo de la vague - parce que je peux orienter ma recherche pour certaines des lettres des mots Comme vous pourriez ne pas avoir tout le texte à cause du manque de tout le peut, la vague s’alignera à certains points sur le texte (distance) afin que je puisse rechercher cette probabilité et savoir quelles lettres doivent exister à ce point de la vague à la distance x.

0
Ken

C'est un vieux projet sur lequel j'ai travaillé. Les images MAP sont très faciles à utiliser avec javascript. Je vous offre l'objet, vous le lisez et vous savez vous en servir. JQuery et les autres systèmes ne sont pas nécessaires pour utiliser les images MAP.

    //Copyright Cherif yahiaoui, by ELEBAN.FR

//variables de flottement.
var myInstOne = null;
var globalize = null;

var eleban_preload_images = function (name, imgs, url){
try{
    var oThis = this;
    this.images = new Array();
    this.imageshover = new Array();
    this.imagesNames = new Array(imgs.split(";"));


        for(var i=0; i < this.imagesNames[0].length; i++){
            this.images[i] = new Image();
            this.imageshover[i] = new Image();
        }

    this.url = url;

    this.GetAbsoluteurl = function () {

    var img = new Image(); img.src = url;
    url = img.src; img = null; 
        this.url = url; 

    };

    this.Preload = function () {

        for(var i=0; i < this.imagesNames[0].length; i++){
            this.images[i].src = this.url+("btn-"+this.imagesNames[0][i]+".png");
            this.imageshover[i].src = this.url+("btn-"+this.imagesNames[0][i]+"-hover.png");
        }

    };
    this.GetAbsoluteurl();
    this.Preload();
}
finally {return;}
}

var g_preloaderhover = new eleban_preload_images("loaderhover","menu;malette;reservation;cabine;facebook;map;amis","./images/");


//variable arret flottement
var g_stopflo = false;

var myObjfloater = function(name, idname, itop, differ ) {
var oThis = this; // création d'une référence vers l'objet courant
this.name = name;
this.id =idname;
this.xstep= 0.3;
this.itime = 30;
this.obj = null;
this.y = itop;
this.yadd = 0;
this.up = true;
this.pause = false;
this.differ = differ;
this.coordsimage = null;
this.objimg = null;
this.initimages = false;
this.compteur = 0;
this.over = false;
this.timeoutstop = null;
try{
this.initimage = function(){
var img = this.obj.getElementsByTagName('img')[0];
this.coordsimage = new Array(img.width, img.height);
this.objimg = img;
this.initimages = true;
};


this.myMethod = function() {
if(!g_stopflo){
    if(this.differ != 0){ 
this.differ=this.differ-0.1; 
}else{

if(this.obj){
if(this.over == false){
    this.yadd=this.yadd+0.1; this.itime = this.itime + 10;
this.obj.style.visibility = "hidden";
this.y = ((this.up)? this.y - this.yadd : this.y + this.yadd);
this.obj.style.marginTop = this.y +"%" ;
this.obj.style.visibility = "visible";

if (this.yadd > this.xstep){ 
    this.up = (this.up)? false : true;
    this.yadd = -0.1; this.itime=180;
}
}
}else{
    if (document){
        if(document.getElementById) {
         this.obj = document.getElementById(this.id); 
        //this.y = this.obj.offsetTop;
        }else{
        if(document.getElementByTagName) { this.obj = document.getElementByTagName(this.id); this.y = this.obj.offsetTop;}
        }

    }
}
}
this.timeoutstop=setTimeout(function() { oThis.myMethod(); }, this.itime);
}    
};

this.callDelayed = function() {
    // utilisation de la référence vers l'objet
if(!g_stopflo){
    this.timeoutstop=setTimeout(function() { oThis.myMethod(); }, this.itime);
}
};
}
finally {return;}
};

// special creation des zones AREA
function eleban_createallarea(){
try{
var measur = new Array("w", "h");
measur["w"] = new Array(330,570,185,300,115,390,225);
measur["h"] = new Array(460,570,295,450,100,190,115);
var ititle = new Array("Voir les menus  et nos suggestions","Repas &agrave; emporter","R&eacute;servation d&rsquo;une table","Nous contacter","Nous rejoindre sur FaceBook","Calculer votre trajet","liste des amis");
var ihref = new Array("menus.html","emporter.html","reservation.html","contact.html","likebox.html","google.html","amis.html");
var b_map = new Array(0,1,2,3,4,5,6);
b_map[0] = "71,32,240,32,249,43,289,352,280,366,102,385,90,371,51,38";
b_map[1] = "66,52,95,14,129,56,115,91,100,93,112,273,128,284,122,366,176,343,193,296,191,194,147,189,145,166,201,111,199,84,545,105,532,354,509,388,412,478,32,401,77,383,87,375,82,286,95,269,94,221,24,195,11,165,9,120,89,123,89,94,78,92,77,92,77,93,75,93,77,93,76,93,79,92";
b_map[2] = "19,25,169,38,173,112,161,113,105,103,90,125,91,262,121,269,124,281,96,293,62,289,49,281,56,268,83,264,84,121,71,98,16,90";
b_map[3] = "60,0,216,1,226,20,225,403,168,421,42,410,45,10";
b_map[4] = "31,7,72,10,82,18,88,45,88,71,76,81,29,80,17,68,16,18";
b_map[5] = "91,40,141,38,178,27,184,4,211,5,223,24,240,23,386,135,229,121,103,180,6,156,49,94";
b_map[6] = "6,32,69,18,79,6,118,7,141,2,149,10,211,17,202,28,209,30,189,62,195,70,178,74,180,90,164,90,154,107,68,101,34,104,34,98,18,97,28,84,15,84,30,65";

if (document.getElementById){
for (var i=0; i<b_map.length;i++){
var obj = document.getElementById("pc_menu"+i);
    if(obj){
    var ct = '<img class=\"pc_menu\" src=\"'+g_preloaderhover.images[i].src+'\" alt=\"\" width=\"'+measur["w"][i]+'\" height=\"'+measur["h"][i]+'\" usemap=\"#MAP_INDEX'+i+'\" \/>';
    ct+='<map name=\"MAP_INDEX'+i+'\">';
    ct+='<area shape=\"poly\" coords=\"'+b_map[i]+'\" title=\"'+ititle[i]+'\" href=\"'+ihref[i]+'\" \/>';
    ct+='<\/map>';
    obj.innerHTML = ct;
    }
}
}
}
finally {return;}
}

//preload, creation et gestion de tous les evenements


var image_resizer = function(g_layer){


    b_org_Elm = new Array("w",  "h");
    b_org_Elm["w"] = new Array(330,570,185,300,115,390,225);
    b_org_Elm["h"] = new Array(460,570,295,450,100,190,115);

    b_map = new Array(0,1,2,3,4,5,6);
    b_map[0] = new Array(71,32,240,32,249,43,289,352,280,366,102,385,90,371,51,38);
    b_map[1] = new Array(66,52,95,14,129,56,115,91,100,93,112,273,128,284,122,366,176,343,193,296,191,194,147,189,145,166,201,111,199,84,545,105,532,354,509,388,412,478,32,401,77,383,87,375,82,286,95,269,94,221,24,195,11,165,9,120,89,123,89,94,78,92,77,92,77,93,75,93,77,93,76,93,79,92);
    b_map[2] = new Array(19,25,169,38,173,112,161,113,105,103,90,125,91,262,121,269,124,281,96,293,62,289,49,281,56,268,83,264,84,121,71,98,16,90);
    b_map[3] = new Array(60,0,216,1,226,20,225,403,168,421,42,410,45,10);
    b_map[4] = new Array(31,6,70,10,78,18,84,23,88,44,88,70,78,80,75,81,33,82,23,76,18,69,16,22,21,13);
    b_map[5] = new Array(91,40,141,38,178,27,184,4,211,5,223,24,240,23,386,135,229,121,103,180,6,156,49,94);
    b_map[6] = new Array(6,32,69,18,79,6,118,7,141,2,149,10,211,17,202,28,209,30,189,62,195,70,178,74,180,90,164,90,154,107,68,101,34,104,34,98,18,97,28,84,15,84,30,65);


    b_layer = g_layer;

//gere mouseover
    this.mouseover = function(e){
        if (!e) var e = window.event;
        var tg = (window.event) ? e.srcElement : e.target
            if (tg.nodeName){
                if(tg.nodeName == "AREA"){
                var divpar = (tg.parentNode)? tg.parentNode.parentNode : tg.parentElement.parentElement;
                    if (divpar){
                        if(divpar.nodeName == "DIV"){
                            var iiobjimg = divpar.getElementsByTagName('img');
                                if (iiobjimg){
                                    ii = parseInt(divpar.id.substring(divpar.id.length-1,divpar.id.length));
                                    iiobjimg[0].src = g_preloaderhover.imageshover[ii].src;
                                }
                        }
                    }
                }
            }
    };

//gere mouseout
    this.mouseout = function(e){
        if (!e) var e = window.event;
        tg = (window.event) ? e.srcElement : e.target
            if (tg.nodeName){
                if(tg.nodeName == "AREA"){
                divpar = (tg.parentNode)? tg.parentNode.parentNode : tg.parentElement.parentElement;
                    if (divpar){
                        if(divpar.nodeName == "DIV"){
                            var iiobjimg = divpar.getElementsByTagName('img');
                                if (iiobjimg){
                                    ii = parseInt(divpar.id.substring(divpar.id.length-1,divpar.id.length));
                                    iiobjimg[0].src = g_preloaderhover.images[ii].src;
                                }
                        }
                    }
                }
            }
    };

//ajout evenements entree sortie à la page web lors du chargement de la page
    this.init = function () {

        for(var i=0; i<b_org_Elm["w"].length;i++){
            w = document.getElementById("pc_menu"+i).offsetWidth;
            h = document.getElementById("pc_menu"+i).offsetHeight;

            xa = w/parseFloat(b_org_Elm["w"][i]);
            ya = h/parseFloat(b_org_Elm["h"][i]);

            area = document.getElementById("pc_menu"+i).getElementsByTagName('area')[0];

            b_map2 = area.coords.split(",");
            yswitch = true;
                for(m=0; m<b_map2.length;m++){
                b_map2[m] = Math.round(parseFloat(b_map[i][m]) * ((yswitch)? xa: ya));
                yswitch = (yswitch)? false :  true;
                }
            area.coords = b_map2.join(',');
        }
    }; 


    this.resize = function () {
    clearTimeout(myInstOne.timeoutstop);
    g_stopflo=true;

    globalize.init();
    g_stopflo=false;
    myInstOne.obj = null;
    myInstOne.callDelayed();
    };


    nar = document.getElementsByTagName('area').length;

        for(var i=0; i<nar;i++){
            var elem = document.getElementsByTagName('area')[i];
            if (elem.addEventListener){
                    elem.addEventListener("onmouseover",this.mouseover,true);
                elem.addEventListener("onmouseout",this.mouseout,true);
            }else if (elem.attachEvent) {
                    elem.attachEvent("onmouseover", this.mouseover);
                    elem.attachEvent("onmouseout", this.mouseout);
            }else{
                    elem["onmouseover"] = this.mouseover;
                    elem["onmouseout"] = this.mouseout;
            }
        }

            window.onresize = this.resize;
        window.onmouseover = this.mouseover;
        window.onmouseout = this.mouseout;
}


//permet de temporiser et éviter les erreurs de chargement des objets
function temporise_Init(Lastdiv){
if(document.getElementById){
    if(document.getElementById(Lastdiv)){

    eleban_createallarea();

    myInstOne = new myObjfloater('b_menumap11', 'pc_menu1', 1, 0);

    globalize = new image_resizer(document.getElementById('pc_redim'));
    globalize.init();
        globalize.resize();



    }else{
    setTimeout(temporise_Init(Lastdiv), 30);
    }
}
}


window.onload = function () {
temporise_Init("pc_bandeau");
}
0
Cherif

Si cela vous intéresse d’être en temps réel, vous avez besoin d’ajouter un filtre de pré-traitement pour déterminer ce qui doit être numérisé avec le matériel lourd. Un bon filtre de prétraitement rapide et très réel, qui vous permettra de numériser des éléments susceptibles de devenir une canette de coca-cola avant de passer à des éléments plus discordants, ressemble à ceci: recherchez dans l'image les plus gros correctifs de couleur qui sont une certaine tolérance par rapport au sqrt(pow(red,2) + pow(blue,2) + pow(green,2)) de votre canette de coca-cola. Commencez avec une tolérance de couleur très stricte et réduisez-vous à des tolérances de couleur moins sévères. Ensuite, lorsque votre robot ne disposera plus du temps imparti pour traiter la trame actuelle, il utilisera les bouteilles actuellement trouvées pour vous aider. Veuillez noter que vous devrez ajuster les couleurs RVB dans sqrt(pow(red,2) + pow(blue,2) + pow(green,2)) pour les obtenir correctement.

En outre, cela semble vraiment stupide, mais vous êtes-vous assuré d'activer les optimisations du compilateur -oFast lors de la compilation de votre code C?

0
user7892745

Peut-être trop d'années de retard, mais néanmoins une théorie à essayer.

Le rapport entre le rectangle de délimitation de la région du logo rouge et la dimension globale de la bouteille/boîte est différent. Dans le cas de Can, devrait être 1: 1, alors que sera différent dans celui de la bouteille (avec ou sans bouchon). Cela devrait faciliter la distinction entre les deux.

Mise à jour: La courbure horizontale de la région du logo sera différente entre la canette et la bouteille en raison de leur taille respective. Cela peut être particulièrement utile si votre robot doit prélever une canette/bouteille et que vous décidez de la poignée en conséquence.

0
K B