How to select all non-black pixels in a NumPy array?

21,683

Solution 1

You should use np.any instead of np.all for the second case of selecting all but black pixels:

np.any(image != [0, 0, 0], axis=-1)

Or simply get a complement of black pixels by inverting a boolean array by ~:

black_pixels_mask = np.all(image == [0, 0, 0], axis=-1)
non_black_pixels_mask = ~black_pixels_mask

Working example:

import numpy as np
import matplotlib.pyplot as plt


image = plt.imread('example.png')
plt.imshow(image)
plt.show()

enter image description here

image_copy = image.copy()

black_pixels_mask = np.all(image == [0, 0, 0], axis=-1)

non_black_pixels_mask = np.any(image != [0, 0, 0], axis=-1)  
# or non_black_pixels_mask = ~black_pixels_mask

image_copy[black_pixels_mask] = [255, 255, 255]
image_copy[non_black_pixels_mask] = [0, 0, 0]

plt.imshow(image_copy)
plt.show()

enter image description here


In case if someone is using matplotlib to plot the results and gets completely black image or warnings, see this post: Converting all non-black pixels into one colour doesn't produce expected output

Solution 2

Necessity: Need matrix with this shape = (any,any,3)

Solution:

COLOR = (255,0,0)
indices = np.where(np.all(mask == COLOR, axis=-1))
indexes = zip(indices[0], indices[1])
for i in indexes:
    print(i)

Solution 2:

get interval of specific color, for example RED:

COLOR1 = [250,0,0]
COLOR2 = [260,0,0] # doesnt matter its over limit

indices1 = np.where(np.all(mask >= COLOR1, axis=-1))
indexes1 = zip(indices[0], indices[1])

indices2 = np.where(np.all(mask <= COLOR2, axis=-1))
indexes2 = zip(indices[0], indices[1])

# You now want indexes that are in both indexes1 and indexes2

Solution 3 - PROVED to be WORKING

If previous doesnt work, then there is one solution that works 100%

Transform from RGB channel to HSV. Make 2D mask from 3D image. 2D mask will contain Hue value. Comparing Hues is easier than RGB as Hue is 1 value while RGB is vector with 3 values. After you have 2D matrix with Hue values, do like above:

HUE1 = 0.5
HUE2 = 0.7 

indices1 = np.where(HUEmask >= HUE1)
indexes1 = zip(indices[0], indices[1])

indices2 = np.where(HUEmask <= HUE2)
indexes2 = zip(indices[0], indices[1])

You can dothe same for Saturation and Value.

Share:
21,683
ofir dubi
Author by

ofir dubi

Updated on July 05, 2022

Comments

  • ofir dubi
    ofir dubi almost 2 years

    I am trying to get a list of an image's pixels that are different from a specific color using NumPy.

    For example, while processig the following image:

    enter image description here

    I've managed to get a list of all black pixels using:

    np.where(np.all(mask == [0,0,0], axis=-1))
    

    But when I try to do:

    np.where(np.all(mask != [0,0,0], axis=-1))
    

    I get a pretty strange result:

    enter image description here

    It looks like NumPy has returned only the indices were R, G, and B are non-0

    Here is a minimal example of what I'm trying to do:

    import numpy as np
    import cv2
    
    # Read mask
    mask = cv2.imread("path/to/img")
    excluded_color = [0,0,0]
    
    # Try to get indices of pixel with different colors
    indices_list = np.where(np.all(mask != excluded_color, axis=-1))
    
    # For some reason, the list doesn't contain all different colors
    print("excluded indices are", indices_list)
    
    # Visualization
    mask[indices_list] = [255,255,255]
    
    cv2.imshow(mask)
    cv2.waitKey(0)