Search code examples
pythonnumpymatplotlibmasked-array

masked RGB image does not appear masked with imshow


I noticed that displaying a RGB masked image does not work as I would expect, i.e. the resulting image is not masked when displayed. Is it normal, is there a workaround?

The example bellow shows the observed behaviour:

import numpy as np
from matplotlib import pyplot as plt

img=np.random.normal(0,10,(20,20)) # create a random image
mask=img>0
ma_img=np.ma.masked_where(mask, img) # create a masked image

img_rgb=np.random.uniform(0,1,(20,20,3)) # create a randomRGB image
mask_rgb=np.broadcast_to(mask[...,np.newaxis],img_rgb.shape) # extend the mask so that it matches the RGB image shape
ma_img_rgb=np.ma.masked_where(mask_rgb, img_rgb) # create a masked RGB image

## Display:
fig, ax=plt.subplots(2,2)
ax[0,0].imshow(img)
ax[0,0].set_title('Image')
ax[0,1].imshow(ma_img)
ax[0,1].set_title('Masked Image')
ax[1,0].imshow(img_rgb)
ax[1,0].set_title('RGB Image')
ax[1,1].imshow(ma_img_rgb)
ax[1,1].set_title('Masked RGB Image')

enter image description here

Interestingly, when the mouse passes over masked pixels in the masked RBG image, the pixel value does not appear in the lower right corner of the figure window.


Solution

  • It seems the mask is ignored for RGB arrays, see also this question.

    From the doc the input for imshow() can be:

    • (M, N): an image with scalar data. The values are mapped to colors using normalization and a colormap. See parameters norm, cmap, vmin, vmax.
    • (M, N, 3): an image with RGB values (0-1 float or 0-255 int).
    • (M, N, 4): an image with RGBA values (0-1 float or 0-255 int), i.e. including transparency.

    Therefore one option would be to use ~mask as alpha values for the rgb array:

    img_rgb = np.random.uniform(0, 1, (20, 20, 3))
    ma_img_rgb = np.concatenate([img_rgb, ~mask[:, :, np.newaxis]], axis=-1)
    # ma_img_rgb = np.dstack([img_rgb, ~mask])  # Jan Kuiken