matplotlib imshow plots different if using colormap or RGB array

I find the right plot much more artistic...

matplotlib is rather complicated when it comes to interpreting images. It goes roughly as follows:

  • if the image is a NxM array of any type, it is interpreted through the colormap (autoscale, if not indicated otherwise). (In principle, if the array is a float array scaled to 0..1, it should be interpreted as a grayscale image. This is what the documentation says, but in practice this does not happen.)

  • if the image is a NxMx3 float array, the RGB components are interpreted as RGB components between 0..1. If the values are outside of this range, they are taken with positive modulo 1, i.e. 1.2 -> 0.2, -1.7 -> 0.3, etc.

  • if the image is a NxMx3 uint8 array, it is interpreted as a standard image (0..255 components)

  • if the image is NxMx4, the interpretation is as above, but the fourth component is the opacity (alpha)

So, if you give matplotlib a NxMx3 array of integers other than uint8 or float, the results are not defined. However, by looking at the source code, the odd behavour can be understood:

if A.dtype != np.uint8:
    A = (255*A).astype(np.uint8)

where A is the image array. So, if you give it uint16 values 0, 1, 2, 3, 4..., you get 0, 255, 254, 253, ... Yes, it will look very odd. (IMHO, the interpretation could be a bit more intuitive, but this is how it is done.)


In this case the easiest solution is to divide the array by 65535., and then the image should be as expected. Also, if your original image is truly linear, then you'll need to make the reverse gamma correction:

img1_corr = (img1 / 65535.)**(1/2.2)

Otherwise your middle tones will be too dark.