Saving GIF and MP4 Movies#
Use quantem.widget.movie when you already have one or more image stacks and
want a GIF or MP4 without opening a widget first. This is useful for denoising
comparisons, time-series previews, reconstruction iterations, and report-ready
movies.
from quantem.widget import movie
movie.save_mp4(stack, "movie.mp4", fps=12)
movie.save_gif(stack, "movie.gif", fps=12)
The input stack shape is (frame, row, col). Several stacks can be saved into
one comparison movie by passing a list. All stacks must have the same frame
count and spatial shape.
movie.save_mp4(
[raw, denoised],
"raw_vs_denoised.mp4",
labels=["Raw", "Denoised"],
fps=12,
cols=2,
)
Choose a Backend#
MP4 export accepts three backend names:
Backend |
Use it when |
|---|---|
|
You want the fastest available path. This is the default. |
|
You are on an NVIDIA workstation and want CUDA/NVENC MP4 compression. |
|
You need the portable writer, or you are not in the CUDA environment. |
backend="auto" selects the CUDA MP4 path only when CuPy, PyNvVideoCodec, and
an NVIDIA CUDA device are available in the current Python process. Otherwise it
uses the portable CPU writer.
movie.save_mp4(
[raw, denoised],
"raw_vs_denoised_cuda.mp4",
labels=["Raw", "Denoised"],
fps=12,
cols=2,
backend="cuda",
)
GIF export is CPU-only:
movie.save_gif(
[raw, denoised],
"raw_vs_denoised.gif",
labels=["Raw", "Denoised"],
fps=8,
cols=2,
)
Keep Contrast Comparable#
By default, all panels share one percentile window, so raw and processed views are visually comparable.
movie.save_mp4(
[raw, denoised],
"comparison.mp4",
labels=["Raw", "Denoised"],
percentile=(1, 99),
shared_contrast=True,
)
If raw frames contain edge artifacts or unusually bright acquisition glitches, compute the shared contrast from the processed stack while still showing both panels:
movie.save_mp4(
[raw, denoised],
"comparison.mp4",
labels=["Raw", "Denoised"],
ref_stacks=[denoised],
)
Save From a Widget#
Show3D.save_mp4(...) and Show3D.save_gif(...) route through the same package
movie writer after rendering the current widget view.
from quantem.widget import Show3D
w = Show3D(stack, fps=12)
w.save_gif("show3d-slides.gif", quality="medium", fps=8, slides_preset=True)
w.save_mp4("show3d-view.mp4", quality="high", fps=12, max_frames=40)
Use the package-level movie.save_mp4(...) API when you want array-first
control over panels, labels, and backend selection. Use the widget methods when
you want the saved movie to match the current widget-rendered view. For a slide
GIF, start with slides_preset=True or use the widget Export menu’s GIF
panel; it caps the export to a slide-friendly frame count and panel size without
changing the source stack.
Performance Reference#
On an NVIDIA RTX PRO 6000 Blackwell workstation, a two-panel MP4 export from an in situ DriftCorrected time series measured:
Path |
Backend |
MP4 export time |
Output size |
Speedup |
|---|---|---|---|---|
Portable writer |
|
33.131 s |
11.3 MB |
1.0x |
CUDA MP4 writer |
|
1.834 s |
9.7 MB |
18.1x |
The benchmark used 58 frames from the 800C_1.3Mx_1 time series, exported as a
two-panel raw/denoised comparison from a center 512 x 512 crop at 12 fps. Use
this table as a hardware-specific reference point, not a universal guarantee:
load time, denoising time, frame shape, codec settings, and storage all affect
end-to-end runtime.