1

I have a 3 dimensional Numpy array corresponding to an RGB image. I need to create a 2 dimensional Numpy array from it such that if any pixel in the R, G, or B channel is 1, then the corresponding pixel in the 2-D array is 255.

I know how to use something like a list comprehension on a Numpy array, but the result is the same shape as the original array. I need the new shape to be 2-D.

3 Answers 3

2

Ok, assuming you want the output pixel to be 0 where it shouldn't be 255 and your input is MxNx3.

RGB = RGB == 1 # you can skip this if your original (RGB) contains only 0's and 1's anyway
out = np.where(np.logical_or.reduce(RGB, axis=-1), 255, 0)
Sign up to request clarification or add additional context in comments.

Comments

2

One approach could be with using any() along the third dim and then multiplying by 255, so that the booleans are automatically upscaled to int type, like so -

(img==1).any(axis=2)*255

Sample run -

In [19]: img
Out[19]: 
array([[[1, 8, 1],
        [2, 4, 7]],

       [[4, 0, 6],
        [4, 3, 1]]])

In [20]: (img==1).any(axis=2)*255
Out[20]: 
array([[255,   0],
       [  0, 255]])

Runtime test -

In [45]: img = np.random.randint(0,5,(1024,1024,3))

# @Paul Panzer's soln
In [46]: %timeit np.where(np.logical_or.reduce(img==1, axis=-1), 255, 0)
10 loops, best of 3: 22.3 ms per loop

# @nanoix9's soln    
In [47]: %timeit np.apply_along_axis(lambda a: 255 if 1 in a else 0, 0, img)
10 loops, best of 3: 40.1 ms per loop

# Posted soln here    
In [48]: %timeit (img==1).any(axis=2)*255
10 loops, best of 3: 19.1 ms per loop

Additionally, we could convert to np.uint8 and then multiply it with 255 for some further performance boost -

In [49]: %timeit (img==1).any(axis=2).astype(np.uint8)*255
100 loops, best of 3: 18.5 ms per loop

And more, if we work with individual slices along the third dim -

In [68]: %timeit ((img[...,0]==1) | (img[...,1]==1) | (img[...,2]==1))*255
100 loops, best of 3: 7.3 ms per loop

In [69]: %timeit ((img[...,0]==1) | (img[...,1]==1) | (img[...,2]==1)).astype(np.uint8)*255
100 loops, best of 3: 5.96 ms per loop

Comments

1

use apply_along_axis. e.g.

In [28]: import numpy as np
In [29]: np.random.seed(10)
In [30]: img = np.random.randint(2, size=12).reshape(3, 2, 2)
In [31]: img
Out[31]: 
array([[[1, 1],
        [0, 1]],
       [[0, 1],
        [1, 0]],
       [[1, 1],
        [0, 1]]])
In [32]: np.apply_along_axis(lambda a: 255 if 1 in a else 0, 0, img)
Out[32]: 
array([[255, 255],
       [255, 255]])

see the doc of numpy for details.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.