1

I'm trying to filter an image with shape (224, 224, 3) in RGB which has been loaded into a numpy array, where the last axis is the channels.

The logic is simple: look for specific pixel values across the 3 channels and assign a label to a new 1-Dim/1-Channel array. This is used for Segmentation Networks, where a pixel-wise label is assigned to represent the area of the object in the image.

The current loop looks like this:

mask     = Image.open(args.input).convert('RGB')
array    = np.array(img_mask)

h, w, c = array.shape
bg = np.zeros((w, h))
fg = np.zeros((w, h))

for i in range(0, h):
    for k in range(0, w):
        if np.array_equal(array[i,k], [0, 0, 0]):
            bg[i,k] = 1
        elif np.array_equal(array[i,k], [255, 200, 0]):
            fg[i,k] = 2

label = np.stack((bg, fg), axis=0)

This produces a (2, 224, 224) where axis = 0 is the channels and then axis=1 has the pixel labels.

I have tried to replace the two for loops using np.where however, the result is still a 3D array, whereas what I want is a 1D array, created for each pixel coordinate which matches the condition:

bg    = np.where(array == [0, 0, 0],     1, 0)
fg    = np.where(array == [255, 200, 0], 2, 0)
label = np.stack((bg, fg), axis=0)

However here I get: (2, 224, 224, 3)

The current for loop implementation is painfully slow, and I suspect this can be done using built-in numpy functions, but I've failed to achieve the same result so far.

2
  • Did you try an intermediate solution : first reshape in (224x224, 3) with native numpy function (C speed), then use where on the last dimension, then reshape again.? Personnaly I'm not a big fan of too many dimensions array, it's always create a lot of problems. Commented Feb 11, 2020 at 11:35
  • @GuilhemL. No I didn't because depending on the channel colors I'd have to be careful which dimensions I'm reducing? Unless I've not understood this well; if the same values are broadcast across all 3 axes, then I could just reduce/remove to only one. Commented Feb 11, 2020 at 11:44

1 Answer 1

2

I'm sure you can use select for masking, and ravel to get 1-D array:

array = np.array([[[0,0,0],[128,128,128]],
                  [[128,128,128],[255,255,0]]
                 ])

label = np.select([(array==(0,0,0)).all(-1),      # all make sure all channels are identical
                   (array==(255,255,0)).all(-1)],
                  [1,2], 0)

print(label.ravel())

Output:

array([1, 0, 0, 2])
Sign up to request clarification or add additional context in comments.

11 Comments

Is there a way to do the opposite? E.g., where the condition doesn't match, to select.
Not sure I understand your question, wouldn't array != (0,0,0) work?
or use the default (0 here), if you just want to select everything that doesn't match the other queries.
yes, so I suppose it would be label = np.select([(array==(0,0,0)).all(-1),((array!=(0,0,0)).all(-1)], [1,2], 0) ?
Yes, either at assignment of fg or of label.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.