0

I know this has been asked before but there doesn't seem to be anything for my specific use-case.

I have a numpy array obs which represents a color image and has shape (252, 288, 3).

I want to convert every pixel that is not pure black to pure white.

What I have tried is obs[obs != [0, 0, 0]] = [255, 255, 255] but it gives the following exception:

ValueError: NumPy boolean array indexing assignment cannot assign 3 input values to the 807 output values where the mask is true

The result is the same withobs[obs[:, :] != [0, 0, 0]] = [255, 255, 255]. Also, (obs[:, :] != [0, 0, 0]).shape is (252, 288, 3) and I do not understand why it isnt simply (252, 288) (a matrix of bools).

I thought about using obs[obs != 0] = 255 but that would not have the effect I want since a pixel that is pure green ([0, 255, 0]) would be processed component wise and would still be [0, 255, 0] after the filtering, instead of being actually white ([255, 255, 255]).

Why isn't what I have tried up until now working and how should I go about this?

3
  • is not this what you want? obs[obs != 0] = 255
    – Stepan
    CommentedJan 12, 2021 at 9:02
  • @Stepan I have literally explained that in the question. I have corrected a few typos, it should be more clear now.CommentedJan 12, 2021 at 14:39
  • Surely a single-channel (greyscale) or even a Boolean (True/False) result is enough to represent your desired black/white output without needing 3x the RAM as you would for an RGB result containing only black and white?CommentedJan 12, 2021 at 17:51

2 Answers 2

5

Boolean indexing like obs[obs != [0, 0, 0]] return a 1D array with all the elements from obs that satisfy the given condition. Look at the follwoing example:

obs = np.array([ [[88, 0,99], [ 0, 0, 0]], [[ 0, 0, 0], [88,77,66]] ]) 

obs != [0, 0, 0] returns a boolean array:

array([[[ True, False, True], [False, False, False]], [[False, False, False], [ True, True, True]]]) 

and obs[obs != [0, 0, 0]] then returns a 1D array with all the elements where the mask is True: array([88, 99, 88, 77, 66]).

So what you need is where to test if there's any color component not equal 0:

np.where(obs.any(axis=-1, keepdims=True), 255, obs) 

Result:

array([[[255, 255, 255], [ 0, 0, 0]], [[ 0, 0, 0], [255, 255, 255]]]) 

Note that you need keepdims=True to enable broadcasting to the original shape of obs. Otherwise you'd have to add the lost dimension by np.where(obs.any(-1)[...,np.newaxis], 255, obs) or np.where(np.atleast_3d(obs.any(-1)), 255, obs) which is less elegant.

0
    0

    There are a number of possibilities depending what you actually want to do. Let's do the set-up code (which is common to all possibilities) first so you can see what I mean.

    #!/usr/bin/env python3 import numpy as np # Make a repeatable random image np.random.seed(764) obs = np.random.randint(0,32,(252,288,3), dtype=np.uint8) 

    This image happens to have pure black pixels at the following locations for test purposes:

    obs[ 21, 267] obs[ 28, 252] obs[ 69, 127] obs[ 98, 0] obs[124, 210] obs[133, 98] obs[160, 81] obs[167, 48] obs[217, 237] 

    Now, suppose you want a new, pure True/False boolean mask of black pixels, you can use:

    mask = obs.any(axis=-1) 

    That solution has the following characteristics:

    time: 876 µs mask.shape: (252,288) mask.nbytes: 72576 mask.dtype: 'bool' 

    You can subsequently use and re-use that mask like this:

    # Make masked pixels red obs[mask,:] = [255,0,0] # Make unmasked pixels cyan obs[~mask,:] = [0,255,255] 

    enter image description here


    Now let's suppose you want a new, greyscale image, with black and white pixels, you can use:

    grey = obs.any(axis=-1) * np.uint8(255) 

    That solution has the following characteristics:

    time: 887 µs grey.shape: (252,288) grey.nbytes: 72576 grey.dtype: np.uint8 

    Now suppose you want in-place alteration of your already existing "obs" to pure black and white (but still RGB):

    obs[obs.any(axis=-1),:] = [255,255,255] 

    That solution has the following characteristics:

    time: 1.98 ms obs.shape: (252,288,3) obs.nbytes: 217728 obs.dtype: np.uint8 

      Start asking to get answers

      Find the answer to your question by asking.

      Ask question

      Explore related questions

      See similar questions with these tags.