123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129 |
- #!/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/module-itertools.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 file-like 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#first-steps-towards-programming
- 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 two-dimensional NumPy array by stacking a
- sequence of 1-dimensional 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 three-dimensional 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 three-dimensional, as it is above, the best thing
- to do is reshape it into a two-dimensional array with a shape of
- ``(row_count, column_count*plane_count)``. Because a
- two-dimensional 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 16-bit 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 2009-04-13 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()
|