Convert images into a movie with mencoder

Here’s how to create a movie out of a collection of images, along with a more detailed example on creating multiple images with nested folders of images.

The basic idea

You’ll need the command line utility mencoder (which comes with mplayer) for this.

The command to create a movie out of a list of files is this (note this command should all be on one line, but it needs to be wrapped to be displayed here):


mencoder "mf://@temp.txt" -mf fps=25 -o output.avi -ovc lavc
 -lavcopts vcodec=mpeg4

temp.txt is a file containing a list of image files, and the new movie will be called output.avi.

A specific example

This a Python script for my future reference, but perhaps someone will find it useful.
The problem was this:

  • I had many subfolders with up to 20,000 jpeg images per folder. Each image was named after the experiment and had a number at the end specifying the frame number.
  • Some of those subfolders had up to three different experiments in them. Each experiment needed its own movie.
  • It was OK to have multiple movies for a single experiment.

Directory structure was something like this;


workingDir
    -- day1
            -- a_001.jpg
            -- a_002.jpg
            ...
            -- a_21999.jpg
            -- b_001.jpg
            -- b_002.jpg
            ...
            -- b_487.jpg
    --  day2
            -- c_001.jpg
            -- c_002.jpg
            ...
            -- c_1478.jpg
    -- day3
            ...
    ...
    -- day20

I decided to use Python to parse an input file containing a list of the directories (created using ls workingDir > folders-to-run.txt). If I wanted to have a movie created from the contents of a folder, I marked that folder by putting a “*” as the first character on the line.

I parsed the contents of each marked directory, separated out files that had different base names, then sorted by the frame number. I decided on a movie length of 2000 frames to keep file sizes manageable. For each batch of 2000 images from an experiment, I wrote the filenames to temp.txt and fed that to mencoder.

folders-to-run.txt looked like this:

day1
*day2
*day3
...
day20

(Since only day2 and day3 had a *, they would be the only ones run)

In the end, I’ll end up with movies called:


a_0-2000.avi
a_2000-4000.avi
a_4000-6000.avi
...
a_20000-22000.avi
b_0-2000.avi
c_0-2000.avi
...

Those last two will be smaller than each of the “a” movies, since they have less frames, but that’s OK for my purposes.

Here’s the working Python script.


"""A Python script for creating movies out of directories of jpegs.
Requires mencoder to be installed."""

import os
import re

directory = 'images/workingDir''

# Parse the list of folders to run from the input file.
folderlist = open('folders-to-run.txt')
folders = [line.rstrip() for line in folderlist if line.startswith('*')]
folders = [i.replace('*','') for i in folders]

# Set up regular expressions for later
RE = re.compile('.*-(\d*)\.jpg')
fbRE = re.compile('(.*)-.*\.jpg')

# How many frames to use per movie
framestep = 2000

for folder in folders:

    print '\n\n\tlisting contents of %s . . .'%folder
    files = os.listdir(os.path.join(directory,folder))
    print '%s files found.\n\n' % len(files)

    # If a file is called "asdf-003.jpg", the basename will be 'asdf'.
    basenames = [fbRE.match(i).groups()[0] for i in files if fbRE.match(i)]

    # Get the set of unique basenames.  In the
    basenames = list(set(basenames))

    print '\t***There are %s different runs here.***' % len(basenames)

    # This loop will only execute once if there was only a single experiment
    # in the folder.
    for j,bn in enumerate(basenames):
        these_files = [i for i in files if bn in i]

        # Sort using the "decorate-sort-undecorate" approach
        these_sorted_files = [(int(RE.match(i).groups()[0]),i) for i in these_files if RE.match(i)]
        these_sorted_files.sort()
        these_sorted_files = [i[1] for i in these_sorted_files]

        # these_sorted_files is now a list of the filenames a_001.jpg, a_002.jpg, etc.
        for k in range(0, len(these_sorted_files), framestep):

            frame1 = k
            frame2 = k+framestep

            # Name the output file based on the folder, basename, a number
            # to indicate if it was a second basename in the folder, and the
            # frame range.  Then replace any spaces with "_" so as not
            # to confuse the mencoder command
            this_output_name = '%s_%s_%s_%s-%s.avi' % (folder,bn,j,frame1,frame2
            this_output_name = this_output_name.replace(' ','-')
            print '\n\n\toutput will be %s.' % this_output_name

            #Create a temporary text file that will contain pathnames.  This
            # will be passed to mencoder.
            f = open('temp.txt','w')
            filenames = [os.path.join(directory,folder,i)+'\n' \
                                for i in these_sorted_files[frame1:frame2]]
            f.writelines(filenames)
            f.close()

            # Finally!  Now execute the command to create the video.
            cmd = 'mencoder "mf://@temp.txt" -mf fps=25 -o %s -ovc lavc\
            -lavcopts vcodec=mpeg4' % this_output_name

            os.system(cmd)
            print '\n\nDONE with %s' % this_output_name
print 'Done with all marked folders.'

Tags: , , , , , , ,

Leave a Reply