Discussion:
[Matplotlib-users] weird matplotlib imread question for png
oyster
2015-04-14 10:15:06 UTC
Permalink
I am using anaconda(Python 2.7.6 |Anaconda 1.9.2 (32-bit)| (default,
Nov 11 2013, 10:50:31) [MSC v.1500 32 bit (Intel)] on win32) on
windows 7 64 bits
And the matplotlib is 1.4.3, numpy is 1.9.2, and scipy is 0.15.1,
which are all been updated by 'conda update xx'

As http://matplotlib.org/api/pyplot_api.html says
[quote]
matplotlib.pyplot.imread(*args, **kwargs) Read an image from a file
into an array.

Return value is a numpy.array. For grayscale images, the return array
is MxN. For RGB images, the return value is MxNx3. For RGBA images the
return value is MxNx4.
[/quote]

But if I read a 128*128*8 BPP gray PNG file, the array.shape is (128,
128, 3); if I read a 128*128*24BPP color PNG file, the array.shape is
(128, 128, 4)

Why? Thanks

[code]
from pylab import *

imgGrayPng=imread('python-gray.png')
print (imgGrayPng.shape) #(128, 128, 3)


imgGrayJpg=imread('python-gray.jpg')
print (imgGrayJpg.shape) #(128, 128)


imgColorPng=imread('python-color.png')
print (imgColorPng.shape) #(128, 128, 4)


imgColorJpg=imread('python-color.jpg')
print (imgColorJpg.shape) #(128, 128, 3)


[/code]
Fabrice Silva
2015-04-14 12:31:54 UTC
Permalink
Post by oyster
I am using anaconda(Python 2.7.6 |Anaconda 1.9.2 (32-bit)| (default,
Nov 11 2013, 10:50:31) [MSC v.1500 32 bit (Intel)] on win32) on
windows 7 64 bits
And the matplotlib is 1.4.3, numpy is 1.9.2, and scipy is 0.15.1,
which are all been updated by 'conda update xx'
As http://matplotlib.org/api/pyplot_api.html says
[quote]
matplotlib.pyplot.imread(*args, **kwargs) Read an image from a file
into an array.
Return value is a numpy.array. For grayscale images, the return array
is MxN. For RGB images, the return value is MxNx3. For RGBA images the
return value is MxNx4.
[/quote]
But if I read a 128*128*8 BPP gray PNG file, the array.shape is (128,
128, 3); if I read a 128*128*24BPP color PNG file, the array.shape is
(128, 128, 4)
Are you sure your png "24bpp" does not have a transparency channel?
--
Fabrice
oyster
2015-04-16 14:51:55 UTC
Permalink
Firstly, thanks, Fabrice Silva

I have checked my picture files again.

For python-gray.png, now it is attacched here or can be downloaded
from Loading Image....
xnview says it is 128*128*8, but "print
imread('python-gray.png').shape" says (128, 128, 3), however I suppose
it should be (128, 128)!

For python-color.png, it is my fault. xnview says it is 128*128*32, so
it has alpha channel. Hence "imread().shape =(128, 128, 4)" is right

btw. imread return array which has value between 0 and 1 for PNG file.
But for other picture format, the value is 0~255. The manual says
matplotlib reads PNG only by it self, and other files via PIL.But I
think it is better to make the returned array consistent.
Fabrice Silva
2015-04-16 15:27:24 UTC
Permalink
Post by oyster
Firstly, thanks, Fabrice Silva
I have checked my picture files again.
For python-gray.png, now it is attacched here or can be downloaded
from http://bbs.blendercn.org/data/attachment/forum/201504/16/222351w3952n3o9968m9a5.png.
xnview says it is 128*128*8, but "print
imread('python-gray.png').shape" says (128, 128, 3), however I suppose
it should be (128, 128)!
Funnily (or not), the png is in fact 8-bits depth so you could infer it
is grayscale, but matplotlib is right : your file uses a color palette.
The 8-bits values refer to indices of the 256-length color palette.
These indices are then converted back to the colorspace, so the shape is
eventually (...,3). Unfortunately, the color palette is here the
grayscale...
--
Fabrice
Ryan Nelson
2015-04-16 15:24:24 UTC
Permalink
Post by oyster
xnview says it is 128*128*8, but "print
imread('python-gray.png').shape" says (128, 128, 3), however I suppose
it should be (128, 128)!
Not sure that this is true, but I guess that xnview is using the third
dimension here to refer to a number of bytes. In this case, it is two
bytes, one for the black/white level and the other for alpha level. When
you import this with imread, the png is converted into a Numpy array. The
default behavior in this case is to create an array which is 128*128*3
because the third dimmension is the (R,G,B) levels, which will all be equal
for a gray scale image. This behavior is probably intentional so that you
don't have to write different code to handle gray/color images.

For python-color.png, it is my fault. xnview says it is 128*128*32, so
Post by oyster
it has alpha channel. Hence "imread().shape =(128, 128, 4)" is right
If the third dimension from xnview is bytes, then yes, you are correct.

btw. imread return array which has value between 0 and 1 for PNG file.
Post by oyster
But for other picture format, the value is 0~255. The manual says
matplotlib reads PNG only by it self, and other files via PIL.But I
think it is better to make the returned array consistent.
That is most likely due to the way that PNG and e.g. older JPG are defined.
PNG defines each RGBA value using float32, while older JPG uses uint8.
Therefor, it would not make sense to change the dtype of the image on
import.

Hope that helps.
Ryan
Post by oyster
Firstly, thanks, Fabrice Silva
I have checked my picture files again.
For python-gray.png, now it is attacched here or can be downloaded
from
http://bbs.blendercn.org/data/attachment/forum/201504/16/222351w3952n3o9968m9a5.png
.
xnview says it is 128*128*8, but "print
imread('python-gray.png').shape" says (128, 128, 3), however I suppose
it should be (128, 128)!
For python-color.png, it is my fault. xnview says it is 128*128*32, so
it has alpha channel. Hence "imread().shape =(128, 128, 4)" is right
btw. imread return array which has value between 0 and 1 for PNG file.
But for other picture format, the value is 0~255. The manual says
matplotlib reads PNG only by it self, and other files via PIL.But I
think it is better to make the returned array consistent.
------------------------------------------------------------------------------
BPM Camp - Free Virtual Workshop May 6th at 10am PDT/1PM EDT
Develop your own process in accordance with the BPMN 2 standard
Learn Process modeling best practices with Bonita BPM through live
exercises
http://www.bonitasoft.com/be-part-of-it/events/bpm-camp-virtual-
event?utm_
source=Sourceforge_BPM_Camp_5_6_15&utm_medium=email&utm_campaign=VA_SF
_______________________________________________
Matplotlib-users mailing list
https://lists.sourceforge.net/lists/listinfo/matplotlib-users
Ryan Nelson
2015-04-16 15:29:32 UTC
Permalink
Oops. I meant bits not bytes in my earlier statements. Sorry.
Post by oyster
xnview says it is 128*128*8, but "print
Post by oyster
imread('python-gray.png').shape" says (128, 128, 3), however I suppose
it should be (128, 128)!
Not sure that this is true, but I guess that xnview is using the third
dimension here to refer to a number of bytes. In this case, it is two
bytes, one for the black/white level and the other for alpha level. When
you import this with imread, the png is converted into a Numpy array. The
default behavior in this case is to create an array which is 128*128*3
because the third dimmension is the (R,G,B) levels, which will all be equal
for a gray scale image. This behavior is probably intentional so that you
don't have to write different code to handle gray/color images.
For python-color.png, it is my fault. xnview says it is 128*128*32, so
Post by oyster
it has alpha channel. Hence "imread().shape =(128, 128, 4)" is right
If the third dimension from xnview is bytes, then yes, you are correct.
btw. imread return array which has value between 0 and 1 for PNG file.
Post by oyster
But for other picture format, the value is 0~255. The manual says
matplotlib reads PNG only by it self, and other files via PIL.But I
think it is better to make the returned array consistent.
That is most likely due to the way that PNG and e.g. older JPG are
defined. PNG defines each RGBA value using float32, while older JPG uses
uint8. Therefor, it would not make sense to change the dtype of the image
on import.
Hope that helps.
Ryan
Post by oyster
Firstly, thanks, Fabrice Silva
I have checked my picture files again.
For python-gray.png, now it is attacched here or can be downloaded
from
http://bbs.blendercn.org/data/attachment/forum/201504/16/222351w3952n3o9968m9a5.png
.
xnview says it is 128*128*8, but "print
imread('python-gray.png').shape" says (128, 128, 3), however I suppose
it should be (128, 128)!
For python-color.png, it is my fault. xnview says it is 128*128*32, so
it has alpha channel. Hence "imread().shape =(128, 128, 4)" is right
btw. imread return array which has value between 0 and 1 for PNG file.
But for other picture format, the value is 0~255. The manual says
matplotlib reads PNG only by it self, and other files via PIL.But I
think it is better to make the returned array consistent.
------------------------------------------------------------------------------
BPM Camp - Free Virtual Workshop May 6th at 10am PDT/1PM EDT
Develop your own process in accordance with the BPMN 2 standard
Learn Process modeling best practices with Bonita BPM through live
exercises
http://www.bonitasoft.com/be-part-of-it/events/bpm-camp-virtual-
event?utm_
source=Sourceforge_BPM_Camp_5_6_15&utm_medium=email&utm_campaign=VA_SF
_______________________________________________
Matplotlib-users mailing list
https://lists.sourceforge.net/lists/listinfo/matplotlib-users
oyster
2015-04-17 01:21:58 UTC
Permalink
Two 8bpp(Gimp, xnview say so) graylevel png files can be downloaded
The first (ramp-gray.png) which gives right array shape is
Loading Image...
The second one (python-gray.png) which gives 'wrong' array shape, at
least to me, is
http://bbs.blendercn.org/data/attachment/forum/201504/16/222351w3952n3o9968m9a5.png

[code]
from pylab import *

imgRampPng=imread('ramp-gray.png')
print (imgRampPng.shape) #(1, 255), that is right
print (imgRampPng.min(),imgRampPng.max()) #(0.0, 0.99607843)
print ()

imgGrayPng=imread('python-gray.png')
print (imgGrayPng.shape) #(128, 128, 3), *but I suppose it should
be (128, 128)*
print (imgGrayPng.min(),imgGrayPng.max()) #(0.0, 0.98823529)
print ()
Ch1=imgGrayPng[:,:,0]
Ch2=imgGrayPng[:,:,1]
Ch3=imgGrayPng[:,:,2]
print (Ch1.min(), Ch1.max()) #(0.0, 0.98823529)
print (Ch2.min(), Ch2.max()) #(0.0, 0.98823529)
print (Ch3.min(), Ch3.max()) #(0.0, 0.98823529) #that is to say,
Ch1/2/3 hold same data
print ()
[/code]
Fabrice Silva
2015-04-17 08:08:51 UTC
Permalink
Post by oyster
Two 8bpp(Gimp, xnview say so) graylevel png files can be downloaded
The first (ramp-gray.png) which gives right array shape is
http://bbs.blendercn.org/data/attachment/forum/201504/17/090627ejhixti8vdthdnnn.png
The second one (python-gray.png) which gives 'wrong' array shape, at
least to me, is
http://bbs.blendercn.org/data/attachment/forum/201504/16/222351w3952n3o9968m9a5.png
[code]
from pylab import *
imgRampPng=imread('ramp-gray.png')
print (imgRampPng.shape) #(1, 255), that is right
print (imgRampPng.min(),imgRampPng.max()) #(0.0, 0.99607843)
print ()
imgGrayPng=imread('python-gray.png')
print (imgGrayPng.shape) #(128, 128, 3), *but I suppose it should
be (128, 128)*
print (imgGrayPng.min(),imgGrayPng.max()) #(0.0, 0.98823529)
print ()
Ch1=imgGrayPng[:,:,0]
Ch2=imgGrayPng[:,:,1]
Ch3=imgGrayPng[:,:,2]
print (Ch1.min(), Ch1.max()) #(0.0, 0.98823529)
print (Ch2.min(), Ch2.max()) #(0.0, 0.98823529)
print (Ch3.min(), Ch3.max()) #(0.0, 0.98823529) #that is to say,
Ch1/2/3 hold same data
print ()
[/code]
Did you read my answer from yesterday ? your python-gray.png uses a
color palette, the integer values stored in file are indexes to the
(RGB) values given in the palette. Matplotlib is doing right in
converting the indexes to the RGB values.
The color palette represents here the grayscale, that's why all channel
are equal. But the data is stored in the compact palette way.

How were the two files produced?
--
Fabrice
Loading...