Configuration

The primary interface follows the JuliaSMLM tuple pattern:

(smld_corrected, info) = driftcorrect(smld, config)

where config is a DriftConfig and info is a DriftInfo.

Input: DriftConfig

SMLMDriftCorrection.DriftConfigType
DriftConfig <: AbstractSMLMConfig

Configuration for drift correction, holding all algorithm parameters. Constructed with keyword arguments; all fields have sensible defaults.

Fields

FieldDefaultDescription
quality:singlepassQuality tier: :fft, :singlepass, or :iterative
degree2Legendre polynomial degree for intra-dataset drift
dataset_mode:registeredMulti-dataset handling: :registered or :continuous
chunk_frames0Split datasets into chunks of N frames (0 = no chunking)
n_chunks0Alternative: number of chunks per dataset (0 = use chunk_frames)
maxn200Maximum neighbors for entropy calculation
max_iterations10Maximum iterations for :iterative mode
convergence_tol0.001Convergence tolerance in μm for :iterative mode
warm_startnothingPrevious info.model for warm starting optimization
verbose0Verbosity level: 0=quiet, 1=info, 2=debug
auto_roifalseUse dense ROI subset for faster estimation
σ_loc0.010Typical localization precision (μm) for ROI sizing
σ_target0.001Target drift precision (μm) for ROI sizing
roi_safety_factor4.0Safety multiplier for required localizations

Example

julia> config = DriftConfig(quality=:iterative, degree=3);

julia> config.quality
:iterative

julia> config.degree
3

julia> config.convergence_tol
0.001
source

Quality Tiers

The quality parameter selects the algorithm complexity:

  • :fft – Fast cross-correlation of histogram images. No intra-dataset correction. Best for quick previews or very large datasets.
  • :singlepass (default) – One pass of entropy-based intra-dataset correction followed by inter-dataset alignment. Good balance of speed and accuracy.
  • :iterative – Iterates intra and inter correction until convergence. Most accurate; resolves the coupling between intra and inter drift estimates.

Dataset Modes

The dataset_mode parameter controls how multiple datasets are related:

  • :registered (default) – Datasets are independent acquisitions of the same field of view (e.g., SeqSRM). Inter-dataset alignment finds the best constant shift for each dataset against the others.
  • :continuous – One long acquisition split into multiple files or chunks. Polynomials are warm-started from the previous chunk's endpoint, and inter-shifts are regularized to maintain continuity.

Chunking (Continuous Mode)

For long continuous acquisitions, a single polynomial may not capture complex drift. Use chunk_frames or n_chunks to split each dataset into temporal segments, each modeled independently:

# Split into ~4000-frame chunks
config = DriftConfig(dataset_mode=:continuous, chunk_frames=4000)

# Or specify number of chunks
config = DriftConfig(dataset_mode=:continuous, n_chunks=3)

Each chunk gets its own polynomial. Warm-starting from the previous chunk's endpoint ensures smooth transitions.

Auto-ROI

When auto_roi=true, the algorithm selects a dense rectangular subregion of the field of view for drift estimation, then applies the fitted model to all localizations. This can significantly speed up processing for large datasets while trading some accuracy (~1.4 nm vs ~0.5 nm RMSD in testing).

The ROI size is determined by σ_loc, σ_target, and roi_safety_factor:

config = DriftConfig(auto_roi=true, σ_loc=0.010, σ_target=0.001)

The estimated ROI indices are stored in info.roi_indices.

Warm Starting

Pass a previously fitted model to initialize optimization:

# From a previous correction
(smld1, info1) = driftcorrect(smld1, DriftConfig(degree=2))

# Use as starting point for new data
config2 = DriftConfig(warm_start=info1.model)
(smld2, info2) = driftcorrect(smld2, config2)

Output: DriftInfo

SMLMDriftCorrection.DriftInfoType
DriftInfo <: AbstractSMLMInfo

Metadata from drift correction, returned as second element of tuple. Supports warm start via info.model.

Fields

  • model::LegendrePolynomial: Fitted drift model (intra + inter)
  • elapsed_s::Float64: Wall time in seconds
  • backend::Symbol: Computation backend (:cpu)
  • iterations::Int: Number of iterations completed (0 for :fft, 1 for :singlepass, N for :iterative)
  • converged::Bool: Whether convergence criterion was met (always true for :fft/:singlepass)
  • entropy::Float64: Final entropy value after correction
  • history::Vector{Float64}: Entropy per iteration (empty for :fft)
  • roi_indices::Union{Nothing, Vector{Int}}: Indices used for ROI subsampling (nothing if not used)

Usage

(smld_corrected, info) = driftcorrect(smld)
info.converged    # check convergence
info.entropy      # final value
info.elapsed_s    # timing
plot(info.history)  # diagnostics
info.roi_indices  # ROI used for estimation (nothing if auto_roi=false)

# Warm start from previous result
(smld2, info2) = driftcorrect(smld2; warm_start=info.model)
source

Accessing Results

(smld_corrected, info) = driftcorrect(smld, DriftConfig())

# Diagnostics
info.converged     # true if convergence criterion met
info.entropy       # final entropy value
info.elapsed_s     # wall time in seconds
info.iterations    # iterations completed (0 for :fft, 1 for :singlepass)
info.history       # entropy per iteration (for plotting convergence)
info.roi_indices   # indices used for ROI subset (nothing if auto_roi=false)

Drift Trajectory

Extract the fitted drift model for plotting:

traj = drift_trajectory(info.model)
# traj.frames, traj.x, traj.y (and traj.z for 3D)

# For continuous mode, chain datasets end-to-end
traj = drift_trajectory(info.model; cumulative=true)

Continuation

Pass DriftInfo directly to continue iterating from a previous result:

(smld1, info1) = driftcorrect(smld, DriftConfig(quality=:singlepass))

# Continue with more iterations
(smld2, info2) = driftcorrect(smld, info1; max_iterations=5)