images2avi.py 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. # Copyright (C) 2012, Almar Klein
  2. # All rights reserved.
  3. #
  4. # This code is subject to the (new) BSD license:
  5. #
  6. # Redistribution and use in source and binary forms, with or without
  7. # modification, are permitted provided that the following conditions are met:
  8. # * Redistributions of source code must retain the above copyright
  9. # notice, this list of conditions and the following disclaimer.
  10. # * Redistributions in binary form must reproduce the above copyright
  11. # notice, this list of conditions and the following disclaimer in the
  12. # documentation and/or other materials provided with the distribution.
  13. # * Neither the name of the <organization> nor the
  14. # names of its contributors may be used to endorse or promote products
  15. # derived from this software without specific prior written permission.
  16. #
  17. # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  18. # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  19. # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  20. # ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
  21. # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  22. # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  23. # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  24. # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  25. # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  26. # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  27. #
  28. #
  29. # changes of this file GRASS (PNG instead of JPG) by Anna Petrasova 2013
  30. """ Module images2avi
  31. Uses ffmpeg to read and write AVI files. Requires PIL
  32. I found these sites useful:
  33. http://www.catswhocode.com/blog/19-ffmpeg-commands-for-all-needs
  34. http://linux.die.net/man/1/ffmpeg
  35. """
  36. import os
  37. import time
  38. import subprocess
  39. import shutil
  40. from grass.imaging import images2ims
  41. import grass.script as gscript
  42. def _cleanDir(tempDir):
  43. for i in range(3):
  44. try:
  45. shutil.rmtree(tempDir)
  46. except Exception:
  47. time.sleep(0.2) # Give OS time to free sources
  48. else:
  49. break
  50. else:
  51. print("Oops, could not fully clean up temporary files.")
  52. def writeAvi(
  53. filename,
  54. images,
  55. duration=0.1,
  56. encoding="mpeg4",
  57. inputOptions="",
  58. outputOptions="",
  59. bg_task=False,
  60. ):
  61. """Export movie to a AVI file, which is encoded with the given
  62. encoding. Hint for Windows users: the 'msmpeg4v2' codec is
  63. natively supported on Windows.
  64. Images should be a list consisting of PIL images or numpy arrays.
  65. The latter should be between 0 and 255 for integer types, and
  66. between 0 and 1 for float types.
  67. Requires the "ffmpeg" application:
  68. * Most linux users can install using their package manager
  69. * There is a windows installer on the visvis website
  70. :param str filename: output filename
  71. :param images:
  72. :param float duration:
  73. :param str encoding: the encoding type
  74. :param inputOptions:
  75. :param outputOptions:
  76. :param bool bg_task: if thread background task, not raise but
  77. return error message
  78. :return str: error message
  79. """
  80. # Get fps
  81. try:
  82. fps = float(1.0 / duration)
  83. except Exception:
  84. raise ValueError(_("Invalid duration parameter for writeAvi."))
  85. # Determine temp dir and create images
  86. tempDir = os.path.join(os.path.expanduser("~"), ".tempIms")
  87. images2ims.writeIms(os.path.join(tempDir, "im*.png"), images)
  88. # Determine formatter
  89. N = len(images)
  90. formatter = "%04d"
  91. if N < 10:
  92. formatter = "%d"
  93. elif N < 100:
  94. formatter = "%02d"
  95. elif N < 1000:
  96. formatter = "%03d"
  97. # Compile command to create avi
  98. command = "ffmpeg -r %i %s " % (int(fps), inputOptions)
  99. command += "-i im%s.png " % (formatter,)
  100. command += "-g 1 -vcodec %s %s " % (encoding, outputOptions)
  101. command += "output.avi"
  102. # Run ffmpeg
  103. S = subprocess.Popen(
  104. command, shell=True, cwd=tempDir, stdout=subprocess.PIPE, stderr=subprocess.PIPE
  105. )
  106. # Show what ffmpeg has to say
  107. outPut = S.stdout.read()
  108. if S.wait():
  109. # Clean up
  110. _cleanDir(tempDir)
  111. if bg_task:
  112. return (
  113. gscript.decode(outPut)
  114. + "\n"
  115. + gscript.decode(S.stderr.read())
  116. + "\n"
  117. + _("Could not write avi.")
  118. )
  119. else:
  120. # An error occurred, show
  121. print(gscript.decode(outPut))
  122. print(gscript.decode(S.stderr.read()))
  123. raise RuntimeError(_("Could not write avi."))
  124. else:
  125. try:
  126. # Copy avi
  127. shutil.copy(os.path.join(tempDir, "output.avi"), filename)
  128. except Exception as err:
  129. # Clean up
  130. _cleanDir(tempDir)
  131. if bg_task:
  132. return str(err)
  133. else:
  134. raise
  135. # Clean up
  136. _cleanDir(tempDir)
  137. def readAvi(filename, asNumpy=True):
  138. """Read images from an AVI (or MPG) movie.
  139. Requires the "ffmpeg" application:
  140. * Most linux users can install using their package manager
  141. * There is a windows installer on the visvis website
  142. :param str filename: name of input movie file
  143. :param bool asNumpy:
  144. """
  145. # Check whether it exists
  146. if not os.path.isfile(filename):
  147. raise IOError("File not found: " + str(filename))
  148. # Determine temp dir, make sure it exists
  149. tempDir = os.path.join(os.path.expanduser("~"), ".tempIms")
  150. if not os.path.isdir(tempDir):
  151. os.makedirs(tempDir)
  152. # Copy movie there
  153. shutil.copy(filename, os.path.join(tempDir, "input.avi"))
  154. # Run ffmpeg
  155. command = "ffmpeg -i input.avi im%d.jpg"
  156. S = subprocess.Popen(
  157. command, shell=True, cwd=tempDir, stdout=subprocess.PIPE, stderr=subprocess.PIPE
  158. )
  159. # Show what mencodec has to say
  160. outPut = S.stdout.read()
  161. if S.wait():
  162. # An error occurred, show
  163. print(outPut)
  164. print(S.stderr.read())
  165. # Clean up
  166. _cleanDir(tempDir)
  167. raise RuntimeError("Could not read avi.")
  168. else:
  169. # Read images
  170. images = images2ims.readIms(os.path.join(tempDir, "im*.jpg"), asNumpy)
  171. # Clean up
  172. _cleanDir(tempDir)
  173. # Done
  174. return images