royco
royco

Reputation: 5529

How to create 2-D array from 3-D Numpy array?

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.

Upvotes: 1

Views: 108

Answers (3)

Divakar
Divakar

Reputation: 221574

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

Upvotes: 2

seven7e
seven7e

Reputation: 818

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.

Upvotes: 1

Paul Panzer
Paul Panzer

Reputation: 53029

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)

Upvotes: 2

Related Questions