Trouver le nombre de formes colorées de l'image en utilisant Python

mon problème a trait à la reconnaissance des couleurs à partir des photos. En microbiologie, je dois compter le nombre de noyaux de cellules présents sur une photo prise avec une caméra au microscope. J'ai utilisé GIMP pour marquer les noyaux avec des points de couleur rouge. Maintenant j'aurais besoin de faire un script en python, qui, avec une image, me dirait combien de points rouges sont présents. Il n'y a pas de rouge dans l'image, sauf dans les points.

j'ai pensé à une solution assez compliquée qui n'est probablement pas la meilleure un: prendre une photo et commencer à itérer à travers des pixels vérifiant la couleur de chacun. Si c'est Rouge, vérifiez les 8 pixels les plus proches, vérifiez à nouveau les voisins de chaque Rouge jusqu'à ce qu'il n'y ait plus de pixels rouges voisins. Ensuite, incrémentez le nombre de noyaux par un et marquez les pixels traversés afin qu'ils ne soient pas itérés à nouveau. Puis continuer l'itération d'où elle s'est arrêtée. Cela semble un peu lourd, alors j'ai pensé que je demanderais, peut-être que quelqu'un a déjà réglé un problème similaire plus élégamment.

ce qui Concerne, Sander

12
demandé sur Sander 2011-03-14 16:00:09

3 réponses

Nombre de noyaux

le code adapté de Tutorial D'Image Python. L'image d'entrée avec des noyaux à partir du tutoriel:

nuclei

#!/usr/bin/env python
import scipy
from scipy import ndimage

# read image into numpy array
# $ wget http://pythonvision.org/media/files/images/dna.jpeg
dna = scipy.misc.imread('dna.jpeg') # gray-scale image


# smooth the image (to remove small objects); set the threshold
dnaf = ndimage.gaussian_filter(dna, 16)
T = 25 # set threshold by hand to avoid installing `mahotas` or
       # `scipy.stsci.image` dependencies that have threshold() functions

# find connected components
labeled, nr_objects = ndimage.label(dnaf > T) # `dna[:,:,0]>T` for red-dot case
print "Number of objects is %d " % nr_objects

# show labeled image
####scipy.misc.imsave('labeled_dna.png', labeled)
####scipy.misc.imshow(labeled) # black&white image
import matplotlib.pyplot as plt
plt.imsave('labeled_dna.png', labeled)
plt.imshow(labeled)

plt.show()

Sortie

Number of objects is 17 

labeled nuclei

13
répondu jfs 2011-03-14 20:33:05

je voudrais faire comme ceci:

  • utiliser OpenCV (fixations python),
  • ne prendre que le composant R de l'image RVB,
  • seuil binaire le composant R, de sorte qu'il ne laisse que les pixels les plus rouges,
  • utilisez une détection d'objet ou de caractéristique pour détecter les points, fe. ExtractSURF

Commentaires: il ne sera pas plus rapide, il ne sera pas toujours exactes. Mais ce sera amusant à faire - car CV est toujours amusant - et prête en 10 lignes de code. Juste un lâche pensée.

en ce qui concerne les suggestions plus prêtes pour la production:

  • en fait je pense que votre idée est très bonne, et elle peut être mise en parallèle si on y réfléchit;
  • utiliser la détection blob dans OpenCV (cvBlobsLib).

mais la solution la plus élégante serait simplement de compter les noyaux marqués dans GIMP, comme Ocaso Protal l'a suggéré ci-dessus. Précis et plus rapide. Tout le reste être sujet à des erreurs et beaucoup plus lent, donc les miennes sont juste des idées lâches, plus amusant que n'importe quoi.

3
répondu Tomek Kopczuk 2011-03-14 18:00:24

une solution simple de Numpy / Scipy serait quelque chose comme:

import numpy, scipy
a = scipy.misc.imread("rgb.jpg") # Imports RGB to numpy array where a[0] is red, a[1] is blue, a[2] is green...
num_red = numpy.sum((a[:,:,0] == 255) * (a[:,:,1] == 0) * (a[:,:,2] == 0)) # Counts the number of pure red pixels

vous pouvez aussi utiliser PIL pour lire l'image.

EDIT: À la lumière des commentaires, scipy.ndimage.measurements.label serait utile, et aussi renvoie une valeur num_features ce qui donne le nombre:

import numpy, scipy
from scipy import ndimage
a = scipy.misc.imread("rgb.jpg")
b = ((a[:,:,0] == 255) * (a[:,:,1] == 0) * (a[:,:,2] == 0))*1
labeled_array, num_features = scipy.ndimage.measurements.label(b.astype('Int8'))
1
répondu Benjamin 2011-03-14 18:28:51