Finding the (x,y) indexes of specific (R,G,B) color values from images stored in NumPy ndarrays

22,041

For some array colour array a and a colour tuple c:

indices = numpy.where(numpy.all(a == c, axis=-1))

indices should now be a 2-tuple of arrays, the first of which contains the indices in the first dimensions and the second of which contains the indices in the second dimension corresponding to pixel values of c.

If you need this as a list of coordinate tuples, use zip:

coords = zip(indices[0], indices[1])

For example:

import numpy
a = numpy.zeros((4, 4, 3), 'int')    

for n in range(4):
    for m in range(4):
        a[n, m, :] = n + m
        if (n + m) == 4:
            print n, m

c = (4, 4, 4)
indices = numpy.where(numpy.all(a == c, axis=-1))
print indices
print zip(indices[0], indices[1])

will output:

1 3
2 2
3 1
(array([1, 2, 3]), array([3, 2, 1]))
[(1, 3), (2, 2), (3, 1)]

which corresponds to all the pixels of value (4, 4, 4).

Share:
22,041
fish2000
Author by

fish2000

I've worked with a diverse array of organizations throughout much of my professional life: I designed and built a digital archive for the Merce Cunningham Dance Company in 2006 and 2007; before going to get my MFA, I built full-stack web apps for Rensselaer Polytechnic Institute as a one-man design/build team based out of the RPI Arts departments' iEAR Studios; I've designed and programmed sites for individual art and design practitioners, for MIT’s Sloan School of Business and for Sotheby’s, and for myriad entities at all scales in between. I personally have developed a taste for C++ in recent years, and I am quite proficient in Python, as well as its redheaded stepchild Cython. I love Objective-C – although I have learned Swift, and am eagerly awaiting a project upon which to cut my Swiftian teeth, specifically. If left to my own devices I will write image-analysis code (I enjoy the rather Quixotic task of porting novel algorithms from their sometimes let’s say undelinted academic origins to contemporary frameworks like numpy and halide) and send off myriad and sundry pull requests on GitHub to projects I like the looks of, but can’t compile.

Updated on August 28, 2020

Comments

  • fish2000
    fish2000 over 3 years

    I have an image stored in a numpy array, as yielded by imread():

    >>> ndim
    array([[[  0,   0,   0],
            [  4,   0,   0],
            [  8,   0,   0],
            ..., 
            [247,   0,  28],
            [251,   0,  28],
            [255,   0,  28]],
    
           [[  0, 255, 227],
            [  4, 255, 227],
            [  8, 255, 227],
            ..., 
            [247, 255, 255],
            [251, 255, 255],
            [255, 255, 255]]], dtype=uint8)
    >>> ndim.shape
    (512, 512, 3)
    

    I want to efficiently find the (x, y) coordinate (or coordinates) of pixels with a specific color value, e.g.

    >>> c
    array([ 32,  32, 109], dtype=uint8)
    
    >>> ndim[200,200]
    array([ 32,  32, 109], dtype=uint8)
    
    >>> ndim.T[0, 200, 200]
    32
    >>> ndim.T[1, 200, 200]
    32
    >>> ndim.T[2, 200, 200]
    109
    

    ... in this case, I know the pixel at (200, 200) has the RGB value (32, 32, 109) -- I can test for this.

    What I want to do is query the ndarray for a pixel value and get back the coordinates. In the above case, the putative function find_pixel(c) would return (200, 200).

    Ideally this find_pixel() function would return a list of coordinate tuples and not just the first value it finds.

    I've looked at numpy's "fancy indexing", which confused me greatly... Most of my attempts at figuring this out have been overwrought and unnecessarily baroque.

    I am sure there is a very simple method that I am overlooking here. What is the best way to do this -- is there an altogether better mechanism to get these values than that which I have outlined?

  • fish2000
    fish2000 over 11 years
    That worked flawlessly, thanks!... Incedentally, do you know if this method is vectorizable -- like, will it work on a list of RGB triples, or can it be adapted to do so?
  • Henry Gomersall
    Henry Gomersall over 11 years
    As it stands, it should work on any array in which the last axis contains the colour information. So you can create, for example, a 4-D array in which the first axis indexes the image - something like a = numpy.empty((5, 512, 512, 3), dtype='int'); a[0,:,:,:] = image0; a[1,:,:,:] = image1 .... indices will now contain an extra entry (at the beginning) which are the image indices. If you want to make the colour axis an axis other than the last, you will probably need to play around with the structure of c (raise its dimensionality or something).
  • Rishit Bansal
    Rishit Bansal almost 6 years
    Instead of zip(...), numpy.transpose(indices) can be used as mentioned in the docs. This might slightly benefit performance....
  • mLstudent33
    mLstudent33 about 5 years
    does this work as alternative syntax for the same thing?np.where((images[i] == (0, 255, 0)).all(axis=-1))