Quelles techniques de traitement d'image pourraient être utilisées pour implémenter une application qui détecte les arbres de Noël affichés dans les images suivantes?
Je recherche des solutions qui vont fonctionner sur toutes ces images. Par conséquent, les approches qui nécessitent une formation sur les classificateurs en cascade ou la mise en correspondance de modèles ne sont pas très intéressantes.
Je cherche quelque chose qui peut être écrit dans n'importe quel langage de programmation, tant qu'il n'utilise que des technologies Open Source . La solution doit être testée avec les images partagées sur cette question. Il y a 6 images d'entrée et la réponse doit afficher les résultats du traitement de chacune d'entre elles. Enfin, pour chaque image de sortie, il doit y avoir des lignes rouges dessinées pour entourer l'arbre détecté.
Comment procéderiez-vous pour détecter par programme les arbres de ces images?
la source
Réponses:
J'ai une approche qui me semble intéressante et un peu différente des autres. La principale différence dans mon approche, par rapport à certaines autres, réside dans la façon dont l'étape de segmentation de l'image est effectuée - j'ai utilisé le DBSCAN algorithme de clustering de scikit-learn de Python; il est optimisé pour trouver des formes quelque peu amorphes qui n'ont pas nécessairement un seul centroïde clair.
Au niveau supérieur, mon approche est assez simple et peut être décomposée en environ 3 étapes. D'abord j'applique un seuil (ou en fait, le "ou" logique de deux seuils séparés et distincts). Comme pour beaucoup d'autres réponses, j'ai supposé que l'arbre de Noël serait l'un des objets les plus brillants de la scène, donc le premier seuil n'est qu'un simple test de luminosité monochrome; tous les pixels avec des valeurs supérieures à 220 sur une échelle de 0 à 255 (où le noir est 0 et le blanc 255) sont enregistrés dans une image binaire en noir et blanc. Le deuxième seuil tente de rechercher des lumières rouges et jaunes, qui sont particulièrement importantes dans les arbres en haut à gauche et en bas à droite des six images, et se détachent bien sur le fond bleu-vert qui prévaut dans la plupart des photos. Je convertis l'image rgb en espace hsv, et exigent que la teinte soit inférieure à 0,2 sur une échelle de 0,0 à 1,0 (correspondant à peu près à la frontière entre le jaune et le vert) ou supérieure à 0,95 (correspondant à la frontière entre le violet et le rouge) et en outre, j'ai besoin de couleurs vives et saturées: la saturation et la valeur doivent toutes deux être supérieures à 0,7. Les résultats des deux procédures de seuil sont logiquement "ou" -ed ensemble, et la matrice résultante d'images binaires en noir et blanc est présentée ci-dessous:
Vous pouvez clairement voir que chaque image a un grand groupe de pixels correspondant approximativement à l'emplacement de chaque arbre, et quelques-unes des images ont également d'autres petits groupes correspondant soit à des lumières dans les fenêtres de certains bâtiments, soit à un scène de fond à l'horizon. L'étape suivante consiste à faire reconnaître à l'ordinateur qu'il s'agit de clusters distincts et à étiqueter correctement chaque pixel avec un numéro d'ID d'appartenance au cluster.
Pour cette tâche, j'ai choisi DBSCAN . Il existe une assez bonne comparaison visuelle de la façon dont DBSCAN se comporte généralement, par rapport aux autres algorithmes de clustering, disponibles ici . Comme je l'ai dit plus tôt, il se marie bien avec les formes amorphes. La sortie de DBSCAN, avec chaque cluster tracé dans une couleur différente, est affichée ici:
Il y a quelques points à prendre en compte lorsque l'on regarde ce résultat. Premièrement, DBSCAN oblige l'utilisateur à définir un paramètre de «proximité» afin de réguler son comportement, qui contrôle efficacement la séparation d'une paire de points pour que l'algorithme déclare un nouveau cluster séparé plutôt que d'agglomérer un point de test sur un cluster déjà préexistant. J'ai défini cette valeur à 0,04 fois la taille le long de la diagonale de chaque image. Étant donné que la taille des images varie d'environ VGA à environ HD 1080, ce type de définition relative à l'échelle est essentiel.
Un autre point à noter est que l'algorithme DBSCAN tel qu'il est implémenté dans scikit-learn a des limites de mémoire qui sont assez difficiles pour certaines des images plus grandes de cet exemple. Par conséquent, pour quelques-unes des images plus grandes, j'ai dû "décimer" (c'est-à-dire ne conserver que tous les 3 ou 4 pixels et supprimer les autres) chaque cluster afin de rester dans cette limite. À la suite de ce processus d'élimination, les pixels épars individuels restants sont difficiles à voir sur certaines des images plus grandes. Par conséquent, à des fins d'affichage uniquement, les pixels codés par couleur dans les images ci-dessus ont été effectivement "légèrement dilatés" juste de sorte qu'ils ressortent mieux. C'est purement une opération cosmétique pour le bien du récit; bien qu'il y ait des commentaires mentionnant cette dilatation dans mon code,
Une fois les clusters identifiés et étiquetés, la troisième et dernière étape est facile: je prends simplement le plus grand cluster de chaque image (dans ce cas, j'ai choisi de mesurer la "taille" en termes de nombre total de pixels membres, bien que l'on puisse ont tout aussi facilement utilisé à la place un type de métrique qui mesure l'étendue physique) et calculent la coque convexe pour ce cluster. La coque convexe devient alors la bordure de l'arbre. Les six coques convexes calculées via cette méthode sont représentées ci-dessous en rouge:
Le code source est écrit pour Python 2.7.6 et il dépend de numpy , scipy , matplotlib et scikit-learn . Je l'ai divisé en deux parties. La première partie est responsable du traitement réel de l'image:
et la deuxième partie est un script de niveau utilisateur qui appelle le premier fichier et génère tous les tracés ci-dessus:
la source
scipy.ndimage.filters.maximum_filter()
au même endroit où j'avais utilisé un seuil.MODIFIER LA NOTE: J'ai édité ce post pour (i) traiter chaque image d'arbre individuellement, comme demandé dans les exigences, (ii) pour prendre en compte la luminosité et la forme de l'objet afin d'améliorer la qualité du résultat.
Ci-dessous est présentée une approche qui prend en considération la luminosité et la forme de l'objet. En d'autres termes, il recherche des objets de forme triangulaire et de luminosité importante. Il a été implémenté en Java, en utilisant le cadre de traitement d'image Marvin .
La première étape est le seuillage des couleurs. L'objectif ici est de concentrer l'analyse sur des objets avec une luminosité importante.
images de sortie:
code source:
Dans la deuxième étape, les points les plus brillants de l'image sont dilatés afin de former des formes. Le résultat de ce processus est la forme probable des objets avec une luminosité importante. En appliquant une segmentation de remplissage, les formes déconnectées sont détectées.
images de sortie:
code source:
Comme le montre l'image de sortie, plusieurs formes ont été détectées. Dans ce problème, il y a juste quelques points lumineux dans les images. Cependant, cette approche a été mise en œuvre pour faire face à des scénarios plus complexes.
Dans l'étape suivante, chaque forme est analysée. Un algorithme simple détecte les formes avec un motif similaire à un triangle. L'algorithme analyse la forme de l'objet ligne par ligne. Si le centre de la masse de chaque ligne de forme est presque le même (étant donné un seuil) et que la masse augmente à mesure que y augmente, l'objet a une forme de triangle. La masse de la ligne de forme est le nombre de pixels de cette ligne qui appartiennent à la forme. Imaginez que vous coupez l'objet horizontalement et analysez chaque segment horizontal. S'ils sont centralisés les uns aux autres et que la longueur augmente du premier au dernier segment dans un motif linéaire, vous avez probablement un objet qui ressemble à un triangle.
code source:
Enfin, la position de chaque forme similaire à un triangle et avec une luminosité importante, dans ce cas un arbre de Noël, est mise en évidence dans l'image d'origine, comme illustré ci-dessous.
images de sortie finale:
code source final:
L'avantage de cette approche est qu'elle fonctionnera probablement avec des images contenant d'autres objets lumineux car elle analyse la forme de l'objet.
Joyeux Noël!
MODIFIER LA NOTE 2
Il y a une discussion sur la similitude des images de sortie de cette solution et de quelques autres. En fait, ils sont très similaires. Mais cette approche ne se contente pas de segmenter les objets. Il analyse également les formes des objets dans un certain sens. Il peut gérer plusieurs objets lumineux dans la même scène. En fait, l'arbre de Noël n'a pas besoin d'être le plus brillant. Je ne fais que l'aborder pour enrichir la discussion. Il y a un biais dans les échantillons qui, à la recherche de l'objet le plus brillant, vous trouverez les arbres. Mais, voulons-nous vraiment arrêter la discussion à ce stade? À ce stade, dans quelle mesure l'ordinateur reconnaît-il vraiment un objet qui ressemble à un arbre de Noël? Essayons de combler cet écart.
Ci-dessous est présenté un résultat juste pour élucider ce point:
image d'entrée
production
la source
Voici ma solution simple et stupide. Il est basé sur l'hypothèse que l'arbre sera la chose la plus lumineuse et la plus grande de l'image.
La première étape consiste à détecter les pixels les plus brillants de l'image, mais nous devons faire une distinction entre l'arbre lui-même et la neige qui réfléchit sa lumière. Ici, nous essayons d'exclure la neige en appliquant un filtre très simple sur les codes de couleur:
Ensuite, nous trouvons chaque pixel "lumineux":
Enfin, nous joignons les deux résultats:
Maintenant, nous recherchons le plus grand objet lumineux:
Maintenant, nous avons presque terminé, mais il y a encore quelques imperfections dues à la neige. Pour les couper, nous allons construire un masque en utilisant un cercle et un rectangle pour approximer la forme d'un arbre pour supprimer les pièces indésirables:
La dernière étape consiste à trouver le contour de notre arbre et à le dessiner sur l'image originale.
Je suis désolé mais pour le moment j'ai une mauvaise connexion donc il ne m'est pas possible de télécharger des photos. J'essaierai de le faire plus tard.
Joyeux Noël.
ÉDITER:
Voici quelques photos de la sortie finale:
la source
./christmas_tree ./*.png
. Ils peuvent être autant que vous le souhaitez, les résultats seront affichés l'un après l'autre en appuyant sur n'importe quelle touche. Est-ce mal?<img src="http://i.stack.imgur.com/nmzwj.png" width="210" height="150">
simplement le lien vers l'image;)J'ai écrit le code dans Matlab R2007a. J'ai utilisé k-means pour extraire grossièrement l'arbre de Noël. Je ne montrerai mon résultat intermédiaire qu'avec une seule image et les résultats finaux avec les six.
Tout d'abord, j'ai mappé l'espace RVB sur l'espace Lab, ce qui pourrait améliorer le contraste du rouge dans son canal b:
Outre la fonction dans l'espace colorimétrique, j'ai également utilisé une fonction de texture qui est pertinente avec le quartier plutôt qu'avec chaque pixel lui-même. Ici, j'ai combiné linéairement l'intensité des 3 canaux originaux (R, G, B). La raison pour laquelle j'ai formaté de cette façon est que les arbres de Noël sur l'image ont tous des lumières rouges et parfois un éclairage vert / parfois bleu.
J'ai appliqué un motif binaire local 3X3
I0
, utilisé le pixel central comme seuil et obtenu le contraste en calculant la différence entre la valeur d'intensité moyenne du pixel au-dessus du seuil et la valeur moyenne en dessous.Étant donné que j'ai 4 fonctionnalités au total, je choisirais K = 5 dans ma méthode de clustering. Le code pour k-means est indiqué ci-dessous (il provient du cours d'apprentissage automatique du Dr Andrew Ng. J'ai suivi le cours auparavant et j'ai écrit le code moi-même dans sa tâche de programmation).
Étant donné que le programme s'exécute très lentement sur mon ordinateur, je viens d'exécuter 3 itérations. Normalement, le critère d'arrêt est (i) un temps d'itération d'au moins 10, ou (ii) aucun changement sur les centroïdes. À mon avis, l'augmentation de l'itération peut différencier l'arrière-plan (ciel et arbre, ciel et bâtiment, ...) plus précisément, mais n'a pas montré de changements drastiques dans l'extraction des arbres de Noël. Notez également que k-means n'est pas à l'abri de l'initialisation aléatoire du centroïde, il est donc recommandé d'exécuter le programme plusieurs fois pour faire une comparaison.
Après les k-moyennes, la région marquée avec l'intensité maximale de a
I0
été choisie. Et le traçage des limites a été utilisé pour extraire les limites. Pour moi, le dernier arbre de Noël est le plus difficile à extraire car le contraste de cette image n'est pas assez élevé comme dans les cinq premiers. Un autre problème dans ma méthode est que j'ai utilisé labwboundaries
fonction dans Matlab pour tracer la frontière, mais parfois les frontières intérieures sont également incluses comme vous pouvez le constater dans les résultats des 3e, 5e et 6e. Le côté sombre à l'intérieur des arbres de Noël n'est pas seulement échoué à être agrégé avec le côté illuminé, mais il conduit également à de nombreuses minuscules traces de limites intérieures (imfill
ne s'améliore pas beaucoup). Dans l'ensemble, mon algorithme a encore beaucoup d'espace d'amélioration.Certaines publications indiquent que le décalage moyen peut être plus robuste que les moyennes k, et de nombreux algorithmes basés sur la coupe graphique sont également très compétitifs sur la segmentation complexe des frontières. J'ai écrit moi-même un algorithme de décalage moyen, il semble mieux extraire les régions sans assez de lumière. Mais le décalage moyen est un peu sur-segmenté et une stratégie de fusion est nécessaire. Il fonctionnait encore plus lentement que k-means sur mon ordinateur, je crains de devoir y renoncer. J'ai hâte de voir que d'autres soumettraient ici d'excellents résultats avec les algorithmes modernes mentionnés ci-dessus.
Pourtant, je crois toujours que la sélection des fonctionnalités est l'élément clé de la segmentation d'image. Avec une sélection de fonctionnalités appropriée qui peut maximiser la marge entre l'objet et l'arrière-plan, de nombreux algorithmes de segmentation fonctionneront certainement. Différents algorithmes peuvent améliorer le résultat de 1 à 10, mais la sélection des fonctionnalités peut l'améliorer de 0 à 1.
Joyeux Noël !
la source
Ceci est mon dernier article en utilisant les approches traditionnelles de traitement d'image ...
Ici, je combine en quelque sorte mes deux autres propositions, obtenant des résultats encore meilleurs . En fait, je ne vois pas comment ces résultats pourraient être meilleurs (surtout quand vous regardez les images masquées que la méthode produit).
Au cœur de l'approche se trouve la combinaison de trois hypothèses clés :
Avec ces hypothèses à l'esprit, la méthode fonctionne comme suit:
Voici le code dans MATLAB (encore une fois, le script charge toutes les images jpg dans le dossier actuel et, encore une fois, c'est loin d'être un morceau de code optimisé):
Résultats
Des résultats haute résolution toujours disponibles ici!
Encore plus d'expériences avec des images supplémentaires peuvent être trouvées ici.
la source
Mes étapes de solution:
Get R channel (from RGB) - toutes les opérations que nous effectuons sur ce canal:
Créer une région d'intérêt (ROI)
Canal de seuil R avec valeur minimale 149 (image en haut à droite)
Dilater la zone de résultat (image du milieu à gauche)
Détectez les eges dans le ROI calculé. L'arbre a beaucoup de bords (image du milieu à droite)
Résultat dilaté
Érode avec un rayon plus grand (image en bas à gauche)
Sélectionnez le plus grand objet (par zone) - c'est la région de résultat
Coque convexe (l'arbre est un polygone convexe) (image en bas à droite)
Boîte englobante (image en bas à droite - boîte grren)
Pas à pas:
Le premier résultat - le plus simple mais pas dans les logiciels open source - "Adaptive Vision Studio + Adaptive Vision Library": Ce n'est pas open source mais vraiment rapide à prototyper:
Algorithme complet pour détecter l'arbre de Noël (11 blocs):
L'étape suivante. Nous voulons une solution open source. Changer les filtres AVL en filtres OpenCV: ici, j'ai fait peu de changements, par exemple, la détection des bords utilise le filtre cvCanny, pour respecter le roi, j'ai multiplié l'image de la région par l'image des bords, pour sélectionner le plus grand élément que j'ai utilisé findContours + contourArea mais l'idée est la même.
https://www.youtube.com/watch?v=sfjB3MigLH0&index=1&list=UUpSRrkMHNHiLDXgylwhWNQQ
Je ne peux pas montrer d'images avec des étapes intermédiaires maintenant car je ne peux mettre que 2 liens.
Ok maintenant nous utilisons des filtres openSource mais ce n'est pas encore tout open source. Dernière étape - portez sur le code c ++. J'ai utilisé OpenCV dans la version 2.4.4
Le résultat du code c ++ final est:
Le code c ++ est également assez court:
la source
std::max_element()
appel? Je voudrais également récompenser votre réponse. Je pense que j'ai gcc 4.2.... une autre solution à l'ancienne - purement basée sur le traitement HSV :
Un mot sur l'heuristique dans le traitement HSV:
Bien sûr, on peut expérimenter de nombreuses autres possibilités pour affiner cette approche ...
Voici le code MATLAB pour faire l'affaire (avertissement: le code est loin d'être optimisé !!! J'ai utilisé des techniques non recommandées pour la programmation MATLAB juste pour pouvoir suivre quoi que ce soit dans le processus - cela peut être grandement optimisé):
Résultats:
Dans les résultats, je montre l'image masquée et le cadre de sélection.
la source
Une approche de traitement d'image à l'ancienne ...
L'idée est basée sur l' hypothèse que les images représentent des arbres éclairés sur des arrière-plans généralement plus sombres et plus lisses (ou au premier plan dans certains cas). La zone de l'arbre éclairé est plus "énergique" et a une intensité plus élevée .
Le processus est le suivant:
Vous obtenez un masque binaire et un cadre de sélection pour chaque image.
Voici les résultats de cette technique naïve:
Le code sur MATLAB suit: Le code s'exécute sur un dossier avec des images JPG. Charge toutes les images et renvoie les résultats détectés.
la source
En utilisant une approche assez différente de ce que j'ai vu, j'ai créé un phpscript qui détecte les arbres de Noël par leurs lumières. Le résultat est toujours un triangle symétrique, et si nécessaire des valeurs numériques comme l'angle ("gras") de l'arbre.
La plus grande menace pour cet algorithme est évidemment les lumières à côté (en grand nombre) ou devant l'arbre (le plus gros problème jusqu'à une optimisation plus poussée). Modifier (ajouté): Ce qu'il ne peut pas faire: savoir s'il y a un arbre de Noël ou non, trouver plusieurs arbres de Noël dans une image, détecter correctement un arbre de Noël au milieu de Las Vegas, détecter les arbres de Noël fortement pliés, à l'envers ou coupé ...;)
Les différentes étapes sont:
Explication des marquages:
Code source:
Images:
Bonus: un Weihnachtsbaum allemand, de Wikipedia http://commons.wikimedia.org/wiki/File:Weihnachtsbaum_R%C3%B6merberg.jpg
la source
J'ai utilisé python avec opencv.
Mon algorithme va comme ceci:
Le code:
Si je change le noyau de (25,5) en (10,5) j'obtiens de meilleurs résultats sur tous les arbres mais en bas à gauche,
mon algorithme suppose que l'arbre est éclairé, et dans l'arbre inférieur gauche, le haut a moins de lumière que les autres.
la source