lapstack

Fusion

Fusion is the step that turns N aligned frames into one image. lapstack decomposes each frame into a Laplacian pyramid — a stack of band-pass images, coarse to fine, plus a small residual — decides frame by frame which coefficient to keep at every position in every band, and reconstructs the picture from the winners.

Because the reassembly is a reconstruction rather than a paste, the blending between frames happens inside the transform itself. There is no seam to feather and no mask to tune. How lapstack works explains the machinery; this page is about the controls.

Tip

The short version: leave everything at its default except halo control, which is the one you may want to turn on. A parameter sweep on a real stack found the energy window is the only other knob that changes the result measurably.

Levels

levels in the panel, --levels N on the command line.

The number of band-pass levels in the pyramid. The default is automatic: as many as keep the residual's short side at 32 pixels or more — seven levels on an 8280×5520 frame, whose residual is then 65×44.

Changing this alters less than one percent of the image on a deep stack. As Burt and Adelson observed, the low-pass content is largely shared between frames, so the coarsest levels rarely disagree.

The energy window

energy radius in the panel, --energy-radius R on the command line, default 1 (a 3×3 window).

This is the knob that matters. At each band-pass level lapstack computes a region energy for every coefficient — the sum of squared coefficients over a binomial-weighted window — and the frame with the largest region energy wins that coefficient. Ties go to the earlier frame.

RadiusWindowCharacter
0Single coefficientThe 1984 per-node maximum. Grainier — the decision has no context at all
13×3Default. The right balance for nearly every stack
25×5Slightly smoother

The energy is computed on the luminance coefficient (Y = 0.299R + 0.587G + 0.114B of the RGB coefficients — the pyramid is linear, so that is exactly the luma pyramid), and the selection is then applied to all three channels, so color never splits at a selection edge.

--use-chroma computes energy from R, G and B separately instead. It changes under one percent of the image and is there for completeness.

The residual rule

residual rule in the panel, --top RULE on the command line, default de.

The residual is the coarsest, low-pass image left at the bottom of the pyramid — the overall tone and color of the picture. A winner-take-all rule is wrong there, because every frame has essentially the same low-pass content and picking one would be arbitrary.

RuleWhat it does
deDefault. Local deviation and local entropy, the paper's rule
devDeviation only
avgPlain mean of all frames

The paper's rule, written for two frames, takes A when A wins on both measures, B when B wins on both, and averages otherwise. Generalized to N frames, lapstack treats it as a Pareto rule: a frame is dominated if another frame is at least as good on both measures and strictly better on one, and the fused value is the mean of the frames that are not dominated.

Two further controls shape the measures: --top-radius R (the window for deviation and entropy, default 2 = 5×5) and --entropy-bins N (gray levels for the entropy histogram, default 256).

On a deep stack the choice of rule changes under one percent of the image.

Halo control

halo control in the panel, --halo-control P on the command line, default 0 (off).

The problem

A Laplacian pyramid's characteristic artifact is a soft rim around bright (or dark) objects, and it comes from each level picking its own winner independently.

Consider a bright object against a background. The frames focused behind the object carry the object's defocused copy, spread out over the background — strong coarse energy exactly where the frame that has the object sharp has none. So the coarse levels collect that glow, frame after frame, while the fine levels correctly take the sharp background. The result is a soft halo around the object.

The fix

With halo control on, the levels coarser than the guide level do not select at all. Each of them — the residual included — becomes the mean of the frames, weighted by

((region energy at the guide level + ε) / ρ) ^ P

that is, the guide level's region energy raised to a hardness P and REDUCEd down to each coarser level's size. This is the Gaussian pyramid of a weight mask, exactly as a multiresolution spline blends with one.

The coarse structure then follows whichever frames the guide found sharp, and where nothing is sharp — a flat area — the frames simply average.

SettingEffect
0Off. Every level picks its own winner
1Weight by the energy itself — the gentlest correction
2–4A practical range
8The cap; approaches a hard pick

The guide level is depth level in the panel, --depth-level on the command line, and defaults to 2 (quarter resolution).

How much it does

Tested on the halo in isolation — a sharp fine texture against the same texture blurred away with a wide soft bump added, which is coarse structure only, exactly as a defocused copy of a bright object is — letting every level pick its own winner admits the bump at an RMS error above 0.05 of full scale. With the guide finding the sharp frame everywhere, the error falls by more than 85 % at every hardness from 1 to 8.

On a real stack the change is smaller and localized. On a stack of dark grapes on a bright table, halo control changes about 1 % of full scale along the silhouettes and is invisible elsewhere: the halo is a coarse-level effect, and a deep stack of small focus steps leaves little of it to remove in the first place.

Note

Turn halo control on when you can see a rim, and leave it off when you cannot. It is not free — the coarse levels stop being a hard pick, which is occasionally what you wanted.

What the fusion holds in memory

The accumulator folds frames in one at a time. What it keeps is the running fused pyramid, one best-energy plane per level (plus a weight sum at the levels halo control guides), and the tiny residuals. Nothing grows with the number of frames, which is why stack length costs time but not memory.

Source: sites/lapstack/content/docs/app/fusion.md