Abdul Fatir Abdul Fatir - 5 months ago 36
Python Question

Copy channels in Numpy array

I have a RGB image

img
which is of shape
(2560L, 1920L, 3L)
and another single channel image
mask
which is of shape
(2560L, 1920L)
. Now, I want to make this
mask
of shape
(2560L, 1920L, 3L)
i.e. I want to copy this single channel data into all the three channels.

I'm doing it as follows.

np.array([[[j,j,j] for j in i] for i in mask])


Is there a faster way of doing this using
numpy
?

val val
Answer

If you absolutely want to have the mask being (2560, 1920, 3), you can simply expand it along an axis (there are several ways to do that, but this one is quite straightforward):

>>> mask = np.random.random_integers(0, 255, (15, 12))
>>> mask_3d = mask[:, :, None] * np.ones(3, dtype=int)[None, None, :]
>>> mask.shape
(15L, 12L)
>>> mask_3d.shape
(15L, 12L, 3L)

However, in general, you can use these broadcasts directly. For instance, if you want to multiply your image by your mask:

>>> img = np.random.random_integers(0, 255, (15, 12, 3))
>>> img.shape
(15L, 12L, 3L)
>>> converted = img * mask[:, :, None]
>>> converted.shape
(15L, 12L, 3L)

So you never have to create the (n, m, 3) mask: broadcasting is done on the fly by manipulating the strides of the mask array, rather than creating a bigger, redundant one. Most of the numpy operations support this kind of broadcasting: binary operations (as above), but also indexing:

>>> # Take the lower part of the image
>>> mask = np.tri(15, 12, dtype=bool)
>>> # Apply mask to first channel
>>> one_channel = img[:, :, 0][mask]
>>> one_channel.shape
(114L,)
>>> # Apply mask to all channels
>>> pixels = img[mask]
>>> pixels.shape
(114L, 3L)
>>> np.all(pixels[:, 0] == one_channel)
True
Comments