Why?If you're having trouble piping image data frame-by-frame into FFMpeg (with the subprocess module), you may be interested in another way to convert python image data into a movie without having to store each individual frame as a file (whether it be .png, .jpg, .gif sequences).
However, this method is a little more complicated then attempting to get FFMpeg to work with python, so here's a little scenario to help with whether or not this tutorial is for you.
Let's say you're in a scenario, where you've encountered one of these errors:
"AttributeError: 'Popen' object has no attribute 'proc'"
"IOError: [Errno 22] Invalid argument"
"IOError: [Errno 32] Broken pipe"
Either resulting from this tutorial: Read and write video frames in Python using FFMPEG - __del__( self ) or from some code elsewhere, and you are willing to use an alternative to ffmpeg to convert your PIL images to a video format like in this case: python - Piped FFMPEG won't write frames correctly - Stack Overflow, then read on.
If you're not willing to switch from FFMpeg to another alternative then press backspace and keep on searching!
How?To do this, we're going to employ the assistance of OpenCV v2 and NumPy, which has been covered here: Python: Converting from PIL to OpenCV 2 Image Formats
Please note that the OpenCV version used is version 2, which uses
as the import statement, as opposed to something like
There may be an update to OpenCV that breaks the code like with the answer found in the following link. image - Python JPEG to movie - Stack Overflow.
But without further ado, let's jump right into it!
ImportsWe're going to be using PIL for loading and manipulating the images, NumPy for a PIL-to-OpenCV bridge, and OpenCV Version 2 for the actual image-to-movie process.
So our imports will look something like
from PIL import Image import numpy, cv2
ManipulationObviously, the purpose of using python to convert from PIL to a movie is to be able to manipulate the image frame-by-frame using the power of PIL.
So here, I'm going to demonstrate some basic image blending functionality, just to provide a basis for this tutorial.
Here, we have two images, demo3_1.jpg and demo3_2.jpg...
With PIL, you can do something like
# Imports can be found in the "Imports" section above # Load up the first and second demo images image1 = Image.open("demo3_1.jpg") image2 = Image.open("demo3_2.jpg") # Create a new image which is the half-way blend of image1 and image2 # The "0.5" parameter denotes the half-way point of the blend function. images1And2 = Image.blend(image1, image2, 0.5) # Save the resulting blend as a file images1And2.save("demo3_3.jpg")
In order to use PIL to blend two images together, in this case, the two images are blended at the halfway point, which means that half of each image is merged to become the resultant blended image.
Writing a video with OpenCVWith OpenCV, there's a "VideoWriter" method which you can access to create a movie with.
The method goes something like this:
Writing to the VideoWriter can be done with "video.write( numpy array as string )", and the VideoWriter can be "closed" by using "video.release()".
video = cv2.VideoWriter(filename, codec selection, frames per second, (width, height))
And that's all you need to know to convert from PIL to mp4 (or at least a movie, you need a certain codec for conversion to mp4).
All together nowWith all the elements from the sections above in mind, here's the code in action
Note that when you run the code above, you'll get a prompt for codec selection...
# Imports can be found in the "Imports" section above # Load up the first and second demo images, assumed is that image1 and image2 both share the same height and width image1 = Image.open("demo3_1.jpg") image2 = Image.open("demo3_2.jpg") # Grab the stats from image1 to use for the resultant video height, width, layers = numpy.array(image1).shape # Create the OpenCV VideoWriter video = cv2.VideoWriter("demo3_4.avi", # Filename -1, # Negative 1 denotes manual codec selection. You can make this automatic by defining the "fourcc codec" with "cv2.VideoWriter_fourcc" 10, # 10 frames per second is chosen as a demo, 30FPS and 60FPS is more typical for a YouTube video (width,height) # The width and height come from the stats of image1 ) # We'll have 30 frames be the animated transition from image1 to image2. At 10FPS, this is a whole 3 seconds for i in xrange(0,30): images1And2 = Image.blend(image1, image2, i/30.0) # Conversion from PIL to OpenCV from: http://blog.extramaster.net/2015/07/python-converting-from-pil-to-opencv-2.html video.write(cv2.cvtColor(numpy.array(images1And2), cv2.COLOR_RGB2BGR)) # And back from image2 to image1... for i in xrange(0,30): images2and1 = Image.blend(image2, image1, i/30.0) video.write(cv2.cvtColor(numpy.array(images2and1), cv2.COLOR_RGB2BGR)) # Release the video for it to be committed to a file video.release()
It is possible to find a codec for direct .mp4 conversions, however here, the default "Intel IYUV" codec was chosen and used.
From this stage as well, you can use FFMpeg (outside of Python) or your favourite video conversion program to convert from the codec that you selected to the format that you want, which can indeed include .mp4 files... ImageMagick was used to convert the output to the gif below:
And that's it!
Note that this post was made specifically for OpenCV v2, as documentation online were frustratingly for OpenCV v1, which has different methods and such.
As a disclaimer, things might change in a newer version of OpenCV, so this information is correct as of July 2015.
PIL to mp4 conversion
PIL to movie conversion
PIL/Python/OpenCV Video file from Images
PIL/Python/OpenCV JPEG to movie
Creating an OpenCV movie from PIL images
Converting an OpenCV movie into PIL Images