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 开发者_C百科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
Count nuclei
The code adapted from Python Image Tutorial. Input image with nuclei from the tutorial:
#!/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
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.
A simple Numpy / Scipy solution would be something like:
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
You could also use PIL to read the image.
EDIT: In light of comment, scipy.ndimage.measurements.label
would be useful, and also returns a value num_features
which gives you the count:
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'))
精彩评论