You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('') and can be up to 35 characters long.
128 lines
4.8 KiB
128 lines
4.8 KiB
#!/usr/bin/env python 

# $URL: http://pypng.googlecode.com/svn/trunk/code/exnumpy.py $ 

# $Rev: 126 $ 



# Numpy example. 

# Original code created by Mel Raab, modified by David Jones. 



''' 

Example code integrating RGB PNG files, PyPNG and NumPy 

(abstracted from Mel Raab's functioning code) 

''' 



# http://www.python.org/doc/2.4.4/lib/moduleitertools.html 

import itertools 



import numpy 

import png 





''' If you have a PNG file for an RGB image, 

and want to create a numpy array of data from it. 

''' 

# Read the file "picture.png" from the current directory. The `Reader` 

# class can take a filename, a filelike object, or the byte data 

# directly; this suggests alternatives such as using urllib to read 

# an image from the internet: 

# png.Reader(file=urllib.urlopen('http://www.libpng.org/pub/png/PngSuite/basn2c16.png')) 

pngReader=png.Reader(filename='picture.png') 

# Tuple unpacking, using multiple assignment, is very useful for the 

# result of asDirect (and other methods). 

# See 

# http://docs.python.org/tutorial/introduction.html#firststepstowardsprogramming 

row_count, column_count, pngdata, meta = pngReader.asDirect() 

bitdepth=meta['bitdepth'] 

plane_count=meta['planes'] 



# Make sure we're dealing with RGB files 

assert plane_count == 3 



''' Boxed row flat pixel: 

list([R,G,B, R,G,B, R,G,B], 

[R,G,B, R,G,B, R,G,B]) 

Array dimensions for this example: (2,9) 



Create `image_2d` as a twodimensional NumPy array by stacking a 

sequence of 1dimensional arrays (rows). 

The NumPy array mimics PyPNG's (boxed row flat pixel) representation; 

it will have dimensions ``(row_count,column_count*plane_count)``. 

''' 

# The use of ``numpy.uint16``, below, is to convert each row to a NumPy 

# array with data type ``numpy.uint16``. This is a feature of NumPy, 

# discussed further in 

# http://docs.scipy.org/doc/numpy/user/basics.types.html . 

# You can use avoid the explicit conversion with 

# ``numpy.vstack(pngdata)``, but then NumPy will pick the array's data 

# type; in practice it seems to pick ``numpy.int32``, which is large enough 

# to hold any pixel value for any PNG image but uses 4 bytes per value when 

# 1 or 2 would be enough. 

#  extract 001 start 

image_2d = numpy.vstack(itertools.imap(numpy.uint16, pngdata)) 

#  extract 001 end 

# Do not be tempted to use ``numpy.asarray``; when passed an iterator 

# (`pngdata` is often an iterator) it will attempt to create a size 1 

# array with the iterator as its only element. 

# An alternative to the above is to create the target array of the right 

# shape, then populate it row by row: 

if 0: 

image_2d = numpy.zeros((row_count,plane_count*column_count), 

dtype=numpy.uint16) 

for row_index, one_boxed_row_flat_pixels in enumerate(pngdata): 

image_2d[row_index,:]=one_boxed_row_flat_pixels 



del pngReader 

del pngdata 





''' Reconfigure for easier referencing, similar to 

Boxed row boxed pixel: 

list([ (R,G,B), (R,G,B), (R,G,B) ], 

[ (R,G,B), (R,G,B), (R,G,B) ]) 

Array dimensions for this example: (2,3,3) 



``image_3d`` will contain the image as a threedimensional numpy 

array, having dimensions ``(row_count,column_count,plane_count)``. 

''' 

#  extract 002 start 

image_3d = numpy.reshape(image_2d, 

(row_count,column_count,plane_count)) 

#  extract 002 end 





''' ============= ''' 



''' Convert NumPy image_3d array to PNG image file. 



If the data is threedimensional, as it is above, the best thing 

to do is reshape it into a twodimensional array with a shape of 

``(row_count, column_count*plane_count)``. Because a 

twodimensional numpy array is an iterator, it can be passed 

directly to the ``png.Writer.write`` method. 

''' 



row_count, column_count, plane_count = image_3d.shape 

assert plane_count==3 



pngfile = open('picture_out.png', 'wb') 

try: 

# This example assumes that you have 16bit pixel values in the data 

# array (that's what the ``bitdepth=16`` argument is for). 

# If you don't, then the resulting PNG file will likely be 

# very dark. Hey, it's only an example. 

pngWriter = png.Writer(column_count, row_count, 

greyscale=False, 

alpha=False, 

bitdepth=16) 

# As of 20090413 passing a numpy array that has an element type 

# that is a numpy integer type (for example, the `image_3d` array has an 

# element type of ``numpy.uint16``) generates a deprecation warning. 

# This is probably a bug in numpy; it may go away in the future. 

# The code still works despite the warning. 

# See http://code.google.com/p/pypng/issues/detail?id=44 

#  extract 003 start 

pngWriter.write(pngfile, 

numpy.reshape(image_3d, (1, column_count*plane_count))) 

#  extract 003 end 

finally: 

pngfile.close() 



