1

I run the following code:

    colored = np.empty((299, 299, 3), dtype=float) # dtype=`uint16` doesn't work too!
    colored[:, :, 0] = image
    colored[:, :, 1] = image
    colored[:, :, 2] = image

If I plot image (2 dimensional array of uint16), I can see the correct picture. But if I plot colored array then I get the following trash image:

enter image description here

I plot with the following code:

    import matplotlib.pyplot as plt
    plt.imshow(colored, cmap='gray')
    plt.show()

When I plot image it works. When I plot colored it doesn't. What's going on here and how can I fix that?

5
  • 1
    What plot command are you using? Do the numbers look right ? Commented Oct 7, 2017 at 21:04
  • I use plt.imshow(colored, cmap='gray'). Numbers look right! So, something's wrong with plot function... Commented Oct 7, 2017 at 21:08
  • But I'm trying to plot colored and it should be array of float. When I'm plotting image (array of uint16) by the same way, it works! Commented Oct 7, 2017 at 21:11
  • 1
    How about imshow(colored[:,:,0])? When creating the 3d array, are you normalizing the values. imshow says the values should be in the 0.0 to 1.0 range. Commented Oct 7, 2017 at 22:23
  • Both 2D array and 3D array of 0.0-1.0 values work fine. But I thought that imshow can be used with 3-color images with values 0..255... Commented Oct 7, 2017 at 23:22

1 Answer 1

2

When the array passed to imshow is 3-dimensional and has floating-point dtype, plt.show() calls this piece of code:

if x.ndim == 3:
    ...    
    if xx.dtype.kind == 'f':
        if bytes:
            xx = (xx * 255).astype(np.uint8)
    return xx

So the values in colored are being multiplied by 255 and then astyped to np.uint8. This happens before the values are normalized to the interval [0, 1]. You can verify this by putting a print statement in your matplotlib/cm.py file:

if x.ndim == 3:
    ...    
    if xx.dtype.kind == 'f':
        if bytes:
            print(xx.max())
            xx = (xx * 255).astype(np.uint8)
    return xx

and running this script:

import numpy as np
import matplotlib.pyplot as plt

maxval = np.iinfo('uint16').max
uint16_image = np.linspace(0, maxval, (16**2)).astype('uint16')
uint16_image = uint16_image.reshape(16, 16)

colored = np.empty(uint16_image.shape + (3,), dtype=float)
colored[:, :, 0] = uint16_image
colored[:, :, 1] = uint16_image
colored[:, :, 2] = uint16_image

fig, ax = plt.subplots(nrows=2)
ax[0].imshow(uint16_image)
ax[1].imshow(colored)
plt.show()

which prints

65535.0
65535.0

and displays enter image description here

The moral of the story is that if you pass a 3D float array to plt.imshow, the values must be between 0 and 1 (or NaN) or else you will likely get (graphical) mojibake.

Sign up to request clarification or add additional context in comments.

2 Comments

Using your example above, what would cause the second plot gradient to be blank aside from the black square in the upper left?
The difference in behavior is caused by this change to the matplotlib source code. (See pull 10220). At this point in the code the dtype of self._A is float64 so the high is set to 1. self._A = np.clip(self._A, 0, high) now clips everything to 0 or 1.

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.