how to save pseudo-colorized images as 8-bit PNG files

Hello,

Apologies for reposting my question from yesterday (“save image as
color-mapped 8-bit rather than true-color”). I am hoping this
reposting clarifies what I am trying to accomplish.

The attachment is a simple script that creates a 2D array of unsigned,
8-bit integers and uses matplotlib to save it as a PNG file.

Unfortunately, the PNG file is much larger than expected – apparently
because it is True-Color; on my MS Windows machine, bit depth, for the
file, is listed as 32 rather than the expected 8.

In the attached script, the
DNs array represents a single-channel, gray-scale, luminosity image
which is to be pseudo-colorized as discussed in the tutorial.

Can matplotlib be used to accomplish this? If so, could someone
direct me to where this is discussed?

Thanks,

– jv

8-bit PNGs.py (604 Bytes)

Jim Vickroy wrote:

The attachment is a simple script that creates a 2D array of unsigned, 8-bit integers and uses matplotlib to save it as a PNG file.

Unfortunately, the PNG file is much larger than expected -- apparently because it is True-Color; on my MS Windows machine, bit depth, for the file, is listed as 32 rather than the expected 8.

Can matplotlib be used to accomplish this? If so, could someone direct me to where this is discussed?

I don't think so directly. MPL uses a 32 bit image buffer internally, and that's what gets saved out in the PNG.

You can post-process the image with something like ImageMagick.

Another alternative is to use PIL -- you can grab the matplotlib buffer, make a PIL image out of it, and use PIL to convert to an 8-bit palleted image.

For that matter, you could probably bypass MPL, and use numpy to create the 8-bit image you want, and PIL to save it as a PNG.

-Chris

···

--
Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR&R (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception

Chris.Barker@...259...

Christopher Barker wrote:

Jim Vickroy wrote:

The attachment is a simple script that creates a 2D array of unsigned, 8-bit integers and uses matplotlib to save it as a PNG file.
Unfortunately, the PNG file is much larger than expected -- apparently because it is True-Color; on my MS Windows machine, bit depth, for the file, is listed as 32 rather than the expected 8.

Can matplotlib be used to accomplish this? If so, could someone direct me to where this is discussed?

I don't think so directly. MPL uses a 32 bit image buffer internally, and that's what gets saved out in the PNG.
You can post-process the image with something like ImageMagick.
Another alternative is to use PIL -- you can grab the matplotlib buffer, make a PIL image out of it, and use PIL to convert to an 8-bit palleted image.
For that matter, you could probably bypass MPL, and use numpy to create the 8-bit image you want, and PIL to save it as a PNG.
-Chris
Thanks much for the helpful information. I will revisit PIL; I tried matplotlib because of other requirements (colorbar, various figure annotations) which did not appear to be readily available in PIL. At this stage, it depends on how important the requirement is to reduce the size of the PNG images.

– jv

···

Christopher Barker wrote:

Jim Vickroy wrote:

The attachment is a simple script that creates a 2D array of unsigned,
8-bit integers and uses matplotlib to save it as a PNG file.

Unfortunately, the PNG file is much larger than expected -- apparently
because it is True-Color; on my MS Windows machine, bit depth, for the
file, is listed as 32 rather than the expected 8.

Can matplotlib be used to accomplish this? If so, could someone direct
me to where this is discussed?

I don't think so directly. MPL uses a 32 bit image buffer internally,
and that's what gets saved out in the PNG.

You can post-process the image with something like ImageMagick.

Another alternative is to use PIL -- you can grab the matplotlib buffer,
make a PIL image out of it, and use PIL to convert to an 8-bit palleted
image.

For that matter, you could probably bypass MPL, and use numpy to create
the 8-bit image you want, and PIL to save it as a PNG.

-Chris

Thanks much for the helpful information. I will revisit PIL; I tried matplotlib because of other requirements (colorbar, various figure annotations) which did not appear to be readily available in PIL. At this stage, it depends on how important the requirement is to reduce the size of the PNG images.

-- jv

No need to use anything other than matplotlib for generating the figure--Chris's main point is that mpl does not provide configuration options for saving png files, but you can take such a png file, complete with image, colorbar, annotations, whatever, and use pil or ImageMagick (and there are probably several additional alternatives) to convert to a more compact png format. I took a quick look at the documentation of pil and IM, but unfortunately did not see any nice example of this--it is not obvious to me how to generate the palette. I suspect it is not hard, but it might take a while to figure it out from the docs.

Programs like the following might do what you want:
http://www.libpng.org/pub/png/apps/pngquant.html
http://pngnq.sourceforge.net/

Eric

···

On 07/22/2010 03:40 PM, j vickroy wrote:

------------------------------------------------------------------------------
This SF.net email is sponsored by Sprint
What will you do first with EVO, the first 4G phone?
Visit sprint.com/first -- http://p.sf.net/sfu/sprint-com-first

_______________________________________________
Matplotlib-users mailing list
Matplotlib-users@lists.sourceforge.net
matplotlib-users List Signup and Options

You can post-process the image with something like ImageMagick.

Another alternative is to use PIL -- you can grab the matplotlib buffer,
make a PIL image out of it, and use PIL to convert to an 8-bit palleted
image.

For that matter, you could probably bypass MPL, and use numpy to create
the 8-bit image you want, and PIL to save it as a PNG.

-Chris

Thanks much for the helpful information. I will revisit PIL; I tried matplotlib because of other requirements (colorbar, various figure annotations) which did not appear to be readily available in PIL. At this stage, it depends on how important the requirement is to reduce the size of the PNG images.

-- jv

Try optipng:

http://optipng.sourceforge.net/

Here I am running it on a gray-scale image created by mpl; it was generated in such a way that there are only 100 distinct shades of gray.
You can see that it reduces the file size by quite a bit, converting it from RGBA to grayscale. This is lossless. For this to work, you have to make sure you have no more than 256 distinct colors--they don't have to be gray.

-rw-rw-r-- 1 efiring efiring 8458 2010-07-22 16:26 grayfig.png
efiring@...2091...:~$ optipng grayfig.png
OptiPNG 0.6.3: Advanced PNG optimizer.
Copyright (C) 2001-2009 Cosmin Truta.

** Processing: grayfig.png
800x600 pixels, 4x8 bits/pixel, RGB+alpha
Reducing image to 8 bits/pixel, grayscale
Input IDAT size = 8352 bytes
Input file size = 8458 bytes

Trying:
   zc = 9 zm = 8 zs = 0 f = 0 IDAT size = 3721
   zc = 9 zm = 8 zs = 0 f = 5 IDAT size = 3301
   zc = 9 zm = 8 zs = 1 f = 5 IDAT size = 3286

Selecting parameters:
   zc = 9 zm = 8 zs = 1 f = 5 IDAT size = 3286

Output IDAT size = 3286 bytes (5066 bytes decrease)
Output file size = 3377 bytes (5081 bytes = 60.07% decrease)

efiring@...2091...:~$ ll grayfig.png
-rw-rw-r-- 1 efiring efiring 3377 2010-07-22 16:26 grayfig.png

Eric

Eric Firing wrote:


You can post-process the image with something like ImageMagick.
Another alternative is to use PIL -- you can grab the matplotlib buffer,
make a PIL image out of it, and use PIL to convert to an 8-bit palleted
image.
For that matter, you could probably bypass MPL, and use numpy to create
the 8-bit image you want, and PIL to save it as a PNG.
-Chris
Thanks much for the helpful information. I will revisit PIL; I tried matplotlib because of other requirements (colorbar, various figure annotations) which did not appear to be readily available in PIL. At this stage, it depends on how important the requirement is to reduce the size of the PNG images.
-- jv



Try optipng:
Here I am running it on a gray-scale image created by mpl; it was generated in such a way that there are only 100 distinct shades of gray.
You can see that it reduces the file size by quite a bit, converting it from RGBA to grayscale. This is lossless. For this to work, you have to make sure you have no more than 256 distinct colors--they don't have to be gray.
-rw-rw-r-- 1 efiring efiring 8458 2010-07-22 16:26 grayfig.png
efiring@...2091...:~$ optipng grayfig.png
OptiPNG 0.6.3: Advanced PNG optimizer.
Copyright (C) 2001-2009 Cosmin Truta.
** Processing: grayfig.png
800x600 pixels, 4x8 bits/pixel, RGB+alpha
Reducing image to 8 bits/pixel, grayscale
Input IDAT size = 8352 bytes
Input file size = 8458 bytes
Trying:
zc = 9 zm = 8 zs = 0 f = 0 IDAT size = 3721
zc = 9 zm = 8 zs = 0 f = 5 IDAT size = 3301
zc = 9 zm = 8 zs = 1 f = 5 IDAT size = 3286
Selecting parameters:
zc = 9 zm = 8 zs = 1 f = 5 IDAT size = 3286
Output IDAT size = 3286 bytes (5066 bytes decrease)
Output file size = 3377 bytes (5081 bytes = 60.07% decrease)
efiring@...2091...:~$ ll grayfig.png
-rw-rw-r-- 1 efiring efiring 3377 2010-07-22 16:26 grayfig.png
Eric
------------------------------------------------------------------------------

Thanks much for this information and also for taking the additional
time to try the optipng tool. It is very helpful.

Since the above mentioned PNG generation is one step in a “near”
real-time products generation system, I was hoping to avoid the
addition of another component (i.e., PNG compression) in the stream,
but it appears unavoidable.

– jv

···

http://optipng.sourceforge.net/

j vickroy wrote:

Thanks much for this information and also for taking the additional time to try the optipng tool. It is very helpful.

Since the above mentioned PNG generation is one step in a "near" real-time products generation system, I was hoping to avoid the addition of another component (i.e., PNG compression) in the stream, but it appears unavoidable.

yes, but you can build it into your python script. I'm sorry I don't have time to write a sample for you, but:

You can get the RGBA buffer from MPL
You can convert that to a PIL RGBA image.
You can use PIL's "quantize" method to make a palletted image.
You can save that palleted image as a PNG.

I think that will all run pretty fast.

By the way, I'm pretty sure there are a few functions in MPL already that use PIL if it is installed -- so if you get this working, it may be worth adding to MPL -- or maybe not, it's pretty specialized.

-Chris

···

--
Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR&R (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception

Chris.Barker@...259...