Finding number of colored shapes from picture using Python

My problem has to do with recognising colours from pictures. Doing microbiology I need to count the number of cell nuclei present on a picture taken with a microscope camera. I've used GIMP to tag the nuclei with dots of red colour. Now I'd need to make a script in python, which, given an image, would tell me how many red dots are present. There is no red in the picture except in the dots.

I've thought of a rather complicated solution which is probably not the best one: Take a picture and start iterating through pixels checking each one's colour. If that is red, check all 8 nearest pixels, recursively check each red one's neighbours again until no more neighbouring red pixels are found. Then increment nuclei count by one and mark traversed pixels so they won't be iterated through again. Then continue iteration from where it stopped. Seems kind of heavy so I thought I'd ask, maybe someone has already dealt with a similar problem more elegantly.

Regards, Sander


Solution 1:

Count nuclei

The code adapted from Python Image Tutorial. Input image with nuclei from the tutorial:

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()

Output

Number of objects is 17 

labeled nuclei

Solution 2:

I would do it like this:

  • use OpenCV (python bindings),
  • take only the R component of RGB image,
  • binary threshold the R component, so that it leaves only the reddest pixels,
  • use some object/feature detection to detect the dots, fe. ExtractSURF

Comments: it will not be fastest, it will not be always accurate. But it will be fun to do - as CV is always fun - and ready in 10 lines of code. Just a loose thought.

As for the more production-ready suggestions:

  • actually I think that your idea is very good, and it can be parallelized if given some thought;
  • use blob detection in OpenCV (cvBlobsLib).

But the most elegant solution would just be to count the tagged nuclei in GIMP, as Ocaso Protal has suggested above. Accurate and fastest. Everything else will be prone to mistakes and much much slower, hence mine are just loose ideas, more fun than anything.