evolved
evolved

Reputation: 2210

Matplotlib: Missing channel using imread

When I try to load an image that has three channels with matplotlib it only has one channel when I issue the numpy shape command. This shows the following image:

One channel image with matplotlib

Here is the code I used:

import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import numpy as np

img = mpimg.imread('dolphin.png')
plt.imshow(img)
plt.show()

img.shape
(320, 500)

I also followed the matplotlib image tutorial which uses the same commands as above.

Loading the image with opencv the result is an image with three channels, as expected.

import cv2
imgcv = cv2.imread('dolphin.png')
plt.imshow(imgcv)
plt.show()

imgcv.shape
(320, 500, 3)

Three channel image with cv2

I am using Python 3.5.6 with anaconda.

Here is a short output of the conda list command:

...
matplotlib                3.0.0
...
opencv3                   3.1.0
...
pillow                    5.2.0
...

The original image I used:

Original dolphin image

Am I missing a package or is there another command to load a *.png file? Everything seems to work with *.jpg images

Upvotes: 1

Views: 2089

Answers (1)

ImportanceOfBeingErnest
ImportanceOfBeingErnest

Reputation: 339300

As I see it, matplotlib's imread correctly reads in the image. If the image contains only a single channel, the resulting numpy array will be 2D. If the image contains 3 or 4 channels, the numpy array will be 3D.

Taking the dolphin image from the question you get

plt.imread("https://i.sstatic.net/cInHj.png").shape
> (320, 500)

Concerning the stinkbug image from the matplotlib documentation there is indeed a little problem. The image you see is a grey scale image as well,

plt.imread("https://matplotlib.org/_images/stinkbug.png").shape
> (375, 500)

However the tutorial claims it to be a 3 channel image. This is correct from the point of view of the tutorial, because it takes the image from the doc on the github repository folder.

plt.imread("https://raw.githubusercontent.com/matplotlib/matplotlib/master/doc/_static/stinkbug.png").shape
> (375, 500, 3)

The problem is that the documentation is built through sphinx and sphinx-gallery and in addition may use some other libraries. In the course of this, the image is not copied in its raw format to the output folder. This problem has been reported already here, the reason is not yet fully tracked down.

In any case, the remaining open question is then, why does cv2.imread give you a 3D array for a greyscale image?

From the OpenCV imread documentation:

Second argument is a flag which specifies the way image should be read.

  • cv2.IMREAD_COLOR : Loads a color image. Any transparency of image will be neglected. It is the default flag.
  • cv2.IMREAD_GRAYSCALE : Loads image in grayscale mode
  • cv2.IMREAD_UNCHANGED : Loads image as such including alpha channel

Note Instead of these three flags, you can simply pass integers 1, 0 or -1 respectively.

So here you need to specify yourself, which mode you want to use.

Let's verify:

import cv2
import urllib.request as req

dolphinurl ="https://i.sstatic.net/cInHj.png"
stinkbugweburl = "https://matplotlib.org/_images/stinkbug.png"
stinkbuggiturl = "https://raw.githubusercontent.com/matplotlib/matplotlib/master/doc/_static/stinkbug.png"

def printshape(url, **kw):
    req.urlretrieve(url, "image_name.png")
    im = cv2.imread("image_name.png", **kw)
    print(im.shape)

printshape(dolphinurl)
printshape(stinkbugweburl)
printshape(stinkbugweburl)

This prints

(320, 500, 3)
(375, 500, 3)
(375, 500, 3)

while if you specify greyscale,

printshape(dolphinurl,0)
printshape(stinkbugweburl,0)
printshape(stinkbugweburl,0)

it'll print

(320, 500)
(375, 500)
(375, 500)

In that sense it's up to the user to decide how they want to read in the image.

Upvotes: 2

Related Questions