z-stackr

Focus stacking · Rust · desktop, command line and browser

Sharp from front to back.

z-stackr takes a series of macro or micro photographs focused at different depths, aligns them and fuses the sharp parts of each into one picture.

Build and run it Tour the desktop app Try it in the browser

A lens focused close up has a very thin plane of focus. Photograph the subject again and again while the focus moves through it, and every frame holds a different slice in focus. z-stackr registers the frames onto one another, decides pixel by pixel which frame is sharpest, and blends the result without seams.

It does this in linear light, with three fusion methods to choose from, an aligner that corrects the change in magnification as the focus moves, and an optional GPU path. The same pipeline runs in a desktop app, in a command-line tool that stacks images larger than memory, and from Python.

Licence: MIT or Apache-2.0, at your option.

One frame of the stack: only the front crystals are sharp The stacked result: every crystal is sharp ONE FRAME STACKED · APEX
Fig. 1Rough crystals on a white card, 28 frames at 3840×2160, stacked at half size with registration alignment; auto-cull kept 13 frames. Left of the line: the first frame. Right: the stack fused with Apex. Drag across the picture to compare.

01What it does

02From a series to one picture

The stages of a stack: decode to linear light, align to the first frame, auto-cull, fuse with Apex, Relief or Strata, encode to sRGB. 1 · DECODE JPEG, PNG, TIFF 8 or 16 bit, RAW to linear light, three f32 planes 2 · ALIGN to the first frame shift, scale, rotation; match brightness; crop 3 · AUTO-CULL optional drop frames that win almost no sharp detail 4 · FUSE Apex · Relief · Strata the sharpest frame per pixel, blended without seams 5 · ENCODE to sRGB TIFF, PNG 16 bit, or JPEG 8 bit GPU OPTIONAL GPU OPTIONAL (APEX, RELIEF, STRATA)
Fig. 2The five stages. The desktop app and the command-line tool call the same functions for each one, so the same frames and settings give the same pixels in both.

The frames are read in natural file-name order (frame_2 before frame_10), and the first one is the reference the others are aligned to. Everything after decoding runs on linear-light planes, so a blend of two frames is a blend of light, not of gamma-encoded numbers, and linear white comes out as exactly 255 or 65 535.

Four frames of the input series, each sharp at a different depth
Fig. 3Frames 1, 10, 19 and 28 of the series in Fig. 1. The plane of focus moves from the front of the crystals to the back.

How the alignment and the three fusion methods work

03The desktop app

z-stackr-gui keeps the whole stack in memory and shows what it does: each frame appears as it is aligned, a chip in the status strip shows every running job with an estimate of the time left, and the result lands in a list next to your source files. Projects remember the files, the settings and every retouch stroke; the manual is built in (F1).

The z-stackr desktop app: source files and results on the left, the stacked image on the canvas
Fig. 4The main window with a stacked result on the canvas.

The same window also runs in the browser, at live.z-stackr.suitable-na.me: nothing is installed and the images never leave the tab. It aligns on the GPU through WebGPU and stacks in the page's memory, so very large series are stacked at a reduced size there (what differs).

A tour of the desktop app

04The command line

z-stackr stacks a folder of frames into one file. It writes each aligned frame to a scratch folder as padded tiles and fuses tile by tile, so its memory does not grow with the image size. It reads the same settings file the desktop app writes.

terminal
z-stackr --input-dir ./frames --output-file ./stacked.tif --mode apex --tile-size 512

Every argument, the settings file and the disk budget

05Getting started

z-stackr is built from source with Rust. It needs the nightly compiler (it uses portable SIMD); the repository pins the exact version, and rustup installs it on the first build. There are no ready-built programs yet.

terminal — in the source folder
# the desktop app
cargo build --release -p z-stackr-gui

# the command-line tool
cargo build --release -p z-stackr-cli

# either one with the GPU path, or with camera RAW input
cargo build --release -p z-stackr-gui --features gpu
cargo build --release -p z-stackr-cli --features raw

The programs are written to target/release/. Start z-stackr-gui, drop a folder of frames on the window, choose an algorithm and press Start Stacking.

A plain build targets every 64-bit x86 processor and uses 4-lane vectors. For a faster build on a processor with AVX2 (Intel Haswell, AMD Zen and newer), set RUSTFLAGS="-C target-cpu=x86-64-v3"; see building for all the options.

06Status

The full list of limits