exnumpy.py 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. #!/usr/bin/env python
  2. # $URL: http://pypng.googlecode.com/svn/trunk/code/exnumpy.py $
  3. # $Rev: 126 $
  4. # Numpy example.
  5. # Original code created by Mel Raab, modified by David Jones.
  6. '''
  7. Example code integrating RGB PNG files, PyPNG and NumPy
  8. (abstracted from Mel Raab's functioning code)
  9. '''
  10. # http://www.python.org/doc/2.4.4/lib/module-itertools.html
  11. import itertools
  12. import numpy
  13. import png
  14. ''' If you have a PNG file for an RGB image,
  15. and want to create a numpy array of data from it.
  16. '''
  17. # Read the file "picture.png" from the current directory. The `Reader`
  18. # class can take a filename, a file-like object, or the byte data
  19. # directly; this suggests alternatives such as using urllib to read
  20. # an image from the internet:
  21. # png.Reader(file=urllib.urlopen('http://www.libpng.org/pub/png/PngSuite/basn2c16.png'))
  22. pngReader=png.Reader(filename='picture.png')
  23. # Tuple unpacking, using multiple assignment, is very useful for the
  24. # result of asDirect (and other methods).
  25. # See
  26. # http://docs.python.org/tutorial/introduction.html#first-steps-towards-programming
  27. row_count, column_count, pngdata, meta = pngReader.asDirect()
  28. bitdepth=meta['bitdepth']
  29. plane_count=meta['planes']
  30. # Make sure we're dealing with RGB files
  31. assert plane_count == 3
  32. ''' Boxed row flat pixel:
  33. list([R,G,B, R,G,B, R,G,B],
  34. [R,G,B, R,G,B, R,G,B])
  35. Array dimensions for this example: (2,9)
  36. Create `image_2d` as a two-dimensional NumPy array by stacking a
  37. sequence of 1-dimensional arrays (rows).
  38. The NumPy array mimics PyPNG's (boxed row flat pixel) representation;
  39. it will have dimensions ``(row_count,column_count*plane_count)``.
  40. '''
  41. # The use of ``numpy.uint16``, below, is to convert each row to a NumPy
  42. # array with data type ``numpy.uint16``. This is a feature of NumPy,
  43. # discussed further in
  44. # http://docs.scipy.org/doc/numpy/user/basics.types.html .
  45. # You can use avoid the explicit conversion with
  46. # ``numpy.vstack(pngdata)``, but then NumPy will pick the array's data
  47. # type; in practice it seems to pick ``numpy.int32``, which is large enough
  48. # to hold any pixel value for any PNG image but uses 4 bytes per value when
  49. # 1 or 2 would be enough.
  50. # --- extract 001 start
  51. image_2d = numpy.vstack(itertools.imap(numpy.uint16, pngdata))
  52. # --- extract 001 end
  53. # Do not be tempted to use ``numpy.asarray``; when passed an iterator
  54. # (`pngdata` is often an iterator) it will attempt to create a size 1
  55. # array with the iterator as its only element.
  56. # An alternative to the above is to create the target array of the right
  57. # shape, then populate it row by row:
  58. if 0:
  59. image_2d = numpy.zeros((row_count,plane_count*column_count),
  60. dtype=numpy.uint16)
  61. for row_index, one_boxed_row_flat_pixels in enumerate(pngdata):
  62. image_2d[row_index,:]=one_boxed_row_flat_pixels
  63. del pngReader
  64. del pngdata
  65. ''' Reconfigure for easier referencing, similar to
  66. Boxed row boxed pixel:
  67. list([ (R,G,B), (R,G,B), (R,G,B) ],
  68. [ (R,G,B), (R,G,B), (R,G,B) ])
  69. Array dimensions for this example: (2,3,3)
  70. ``image_3d`` will contain the image as a three-dimensional numpy
  71. array, having dimensions ``(row_count,column_count,plane_count)``.
  72. '''
  73. # --- extract 002 start
  74. image_3d = numpy.reshape(image_2d,
  75. (row_count,column_count,plane_count))
  76. # --- extract 002 end
  77. ''' ============= '''
  78. ''' Convert NumPy image_3d array to PNG image file.
  79. If the data is three-dimensional, as it is above, the best thing
  80. to do is reshape it into a two-dimensional array with a shape of
  81. ``(row_count, column_count*plane_count)``. Because a
  82. two-dimensional numpy array is an iterator, it can be passed
  83. directly to the ``png.Writer.write`` method.
  84. '''
  85. row_count, column_count, plane_count = image_3d.shape
  86. assert plane_count==3
  87. pngfile = open('picture_out.png', 'wb')
  88. try:
  89. # This example assumes that you have 16-bit pixel values in the data
  90. # array (that's what the ``bitdepth=16`` argument is for).
  91. # If you don't, then the resulting PNG file will likely be
  92. # very dark. Hey, it's only an example.
  93. pngWriter = png.Writer(column_count, row_count,
  94. greyscale=False,
  95. alpha=False,
  96. bitdepth=16)
  97. # As of 2009-04-13 passing a numpy array that has an element type
  98. # that is a numpy integer type (for example, the `image_3d` array has an
  99. # element type of ``numpy.uint16``) generates a deprecation warning.
  100. # This is probably a bug in numpy; it may go away in the future.
  101. # The code still works despite the warning.
  102. # See http://code.google.com/p/pypng/issues/detail?id=44
  103. # --- extract 003 start
  104. pngWriter.write(pngfile,
  105. numpy.reshape(image_3d, (-1, column_count*plane_count)))
  106. # --- extract 003 end
  107. finally:
  108. pngfile.close()