Image Sequences to Video¶
The lab keeps three small scripts for turning a folder of PNG frames into an MP4 video and a GIF. They wrap FFmpeg commands that are easy to get wrong by hand: frame ordering, quality settings, and GIF color palettes.
| Script | What it does |
|---|---|
generate_video_ffmpeg.py |
PNG frames to an H.264 MP4 |
mp4_to_gif_converter.py |
MP4 to an optimized GIF |
animate.sh |
Runs both in a row with default settings |
Requirements: Python 3 and an ffmpeg on your PATH that was built with libx264. On Vega, see Building FFmpeg on Vega.
Quick start¶
Download all three scripts into the same folder, make the shell script executable, and run it on your frames:
This writes an MP4 and a GIF into ./output. For control over frame rate, quality, size or trimming, run the two Python scripts directly as described below.
1. generate_video_ffmpeg.py¶
Converts a folder of PNG frames into an MP4 using the H.264 (x264) encoder.
| Option | Default | Description |
|---|---|---|
--fps INT |
20 | Frames per second. |
--duration FLOAT |
not set | Target video length in seconds. The frame rate is set to number of frames ÷ duration, capped at 240. Ignored if you also pass --fps. |
--quality INT |
50 | Quality from 1 (worst) to 100 (lossless). |
How it works:
- Frame naming. Frames must be named <prefix><number>.png, for example frame_0001.png, frame_0002.png. Every frame must share the same prefix, and the prefix can't contain digits. Frames are sorted by their number, so frame_2.png comes before frame_10.png even without zero padding.
- Quality. --quality is converted to x264's CRF setting (51 − quality × 0.51), so 50 becomes CRF 26 and 100 becomes CRF 0. Around 50 gives the best balance of quality and file size. 100 is lossless and produces very large files.
- Output name. The output file is named after the frame prefix plus the settings used. For example, frames named frame_0001.png with --duration 8.5 --quality 80 produce frame__dur8p5_q80.mp4. The double underscore comes from the prefix ending in _. fps appears in the name only if you set --fps yourself.
- Errors. If FFmpeg fails, the script prints an error and exits with a non-zero status, so a job script or animate.sh can detect the failure.
Example:
2. mp4_to_gif_converter.py¶
Converts an MP4 into an animated GIF. It uses FFmpeg's two-pass palette method, which gives much better colors than a direct conversion.
If you leave out output.gif, the GIF is written next to the input with the same name.
| Option | Default | Description |
|---|---|---|
--fps INT |
10 | GIF frame rate. |
--width INT |
480 | Output width in pixels; height follows the aspect ratio. Use 0 to keep the original size. |
--dither {none,basic,best} |
best |
How colors are blended (see below). |
--quality {fast,default,best} |
best |
How the color palette is chosen (see below). |
--start TIME |
not set | Start time, in seconds or HH:MM:SS. |
--end TIME |
not set | End time. |
--duration TIME |
not set | Length in seconds from the start. |
--transparency |
off | Keep the alpha channel from the input. |
--loop {yes,no} |
yes |
yes loops forever. no plays once. |
You can combine at most two of --start, --end and --duration.
Choosing dither and quality¶
A GIF can only hold 256 colors. --quality controls which 256 colors are chosen, and --dither controls how they are mixed to fake the colors in between.
--quality |
FFmpeg setting | Effect |
|---|---|---|
fast |
palettegen=stats_mode=diff |
Builds the palette mostly from the parts of the frame that change. Faster, and can miss subtle colors in static areas. |
default |
palettegen |
FFmpeg's general-purpose balance. |
best |
palettegen=stats_mode=full |
Analyzes every pixel of every frame. Slowest, richest colors. |
--dither |
FFmpeg setting | Effect |
|---|---|---|
none |
paletteuse=dither=none |
No blending. Smallest and fastest, but gradients show visible bands. |
basic |
paletteuse=dither=bayer:bayer_scale=5 |
Ordered pattern dithering. A middle ground. |
best |
paletteuse=dither=floyd_steinberg |
Error-diffusion dithering. Smoothest gradients, larger files. |
For the best-looking result use --quality best --dither best, which is the default. For speed and small files use --quality fast --dither none. GIFs are large by nature; if size matters, run the result through gifsicle afterwards.
Example:
3. animate.sh¶
Runs the full pipeline with default settings: PNG frames to MP4, then that MP4 to a GIF.
- Creates the output folder if it doesn't exist.
- Runs
generate_video_ffmpeg.pyon the input folder. If this fails, the script stops. - Picks the newest
.mp4in the output folder. - Runs
mp4_to_gif_converter.pyon it, writing the GIF next to the MP4.
The two Python scripts must be in the same folder as animate.sh. To change settings, such as quality or GIF width, edit the two python3 lines in the script to pass extra options.
Tip
To make videos automatically when a simulation finishes, call animate.sh from the post-processing section of your job script. The STAR-CCM+ job scripts have a marked place for this.