Getting Started
Installation
using Pkg
Pkg.add("GaussMLE")GaussMLE re-exports ROIBatch, IdealCamera, SCMOSCamera, and @filter from SMLMData.jl.
PSF parameters and output positions are in microns. The camera's pixel_size handles all internal conversions.
Basic Workflow
Step 1: Define Camera and PSF
using GaussMLE
# Camera model (defines pixel size for unit conversion)
camera = IdealCamera(0:1023, 0:1023, 0.1) # 100nm pixels
# PSF model (sigma in microns, from your PSF calibration)
psf = GaussianXYNB(0.13f0) # 130nm PSF widthStep 2: Create or Load ROIBatch
In a real workflow, ROIBatch comes from SMLMBoxer.jl:
Raw Movie → SMLMBoxer.jl → ROIBatch → GaussMLE.fit() → BasicSMLDFor testing, use generate_roi_batch():
batch = generate_roi_batch(camera, psf, n_rois=100, roi_size=11)Step 3: Fit and Access Results
fitter = GaussMLEConfig(psf_model = psf)
smld, info = fit(batch, fitter)
# Results are in microns (camera coordinates)
for e in smld.emitters[1:3]
println("Position: ($(e.x), $(e.y)) μm")
println("Precision: $(e.σ_x * 1000) nm")
endComplete Example
using GaussMLE
using Statistics
# 1. Camera defines pixel size
camera = IdealCamera(0:1023, 0:1023, 0.1) # 100nm pixels
# 2. PSF from calibration (in microns)
psf = GaussianXYNB(0.13f0) # 130nm
# 3. Generate test data (or load from SMLMBoxer)
batch = generate_roi_batch(camera, psf, n_rois=100, roi_size=11)
# 4. Fit
fitter = GaussMLEConfig(psf_model = psf)
smld, info = fit(batch, fitter)
# 5. Results in microns
println("Fitted: $(length(smld.emitters)) localizations")
x_positions = [e.x for e in smld.emitters]
y_positions = [e.y for e in smld.emitters]
photons = [e.photons for e in smld.emitters]
precisions_x = [e.σ_x for e in smld.emitters]
println("Mean position: ($(round(mean(x_positions), digits=2)), $(round(mean(y_positions), digits=2))) microns")
println("Mean photons: $(round(mean(photons), digits=1))")
println("Mean precision: $(round(mean(precisions_x)*1000, digits=1)) nm")Understanding the Output
BasicSMLD Structure
The fit() function returns a tuple (smld, info) where smld is a SMLMData.BasicSMLD containing:
emitters: Vector of emitter objects with fitted parameterscamera: Camera model used for fittingmetadata: Additional information
Emitter Types
Different PSF models return different emitter types, all subtypes of SMLMData.AbstractEmitter:
| PSF Model | Emitter Type | Additional Fields |
|---|---|---|
GaussianXYNB | Emitter2DFitGaussMLE | (base type) |
GaussianXYNBS | Emitter2DFitSigma | σ, σ_σ (fitted PSF width) |
GaussianXYNBSXSY | Emitter2DFitSigmaXY | σx, σy (fitted PSF widths) |
AstigmaticXYZNB | Emitter3DFitGaussMLE | z, σ_z (z-position) |
Emitter2DFitGaussMLE Fields
All 2D emitter types include these base fields:
| Field | Description | Units |
|---|---|---|
x, y | Fitted position | microns |
photons | Total photon count | photons |
bg | Background level | photons/pixel |
σ_x, σ_y | Position uncertainty (CRLB) | microns |
σ_xy | Position covariance (off-diagonal of Fisher matrix inverse) | microns² |
σ_photons, σ_bg | Photometry uncertainties | photons |
pvalue | Goodness-of-fit p-value (χ² test) | 0-1 |
frame | Frame number | integer |
dataset, track_id, id | Metadata fields | integer |
Filtering Results
Use SMLMData's @filter macro for quality control:
using GaussMLE
smld, info = fit(data, fitter)
# Filter by precision and photon count
good = @filter(smld, σ_x < 0.020 && photons > 500)
# Filter by multiple criteria
precise = @filter(smld, σ_x < 0.015 && σ_y < 0.015 && bg < 50)
println("Kept $(length(good.emitters)) / $(length(smld.emitters)) localizations")Working with ROIBatch
In a typical SMLM pipeline, ROIBatch comes from SMLMBoxer.jl which detects candidates and extracts ROIs from raw movie frames:
Raw Movie → SMLMBoxer.jl → ROIBatch → GaussMLE.fit() → BasicSMLD → AnalysisWrapping Raw Data in ROIBatch
If you have raw 3D array data and want proper unit conversion, wrap it in ROIBatch with a camera model. This is the recommended approach even for simple cases:
using GaussMLE
# Your raw data: (roi_size, roi_size, n_rois) Float32 array
data = rand(Float32, 11, 11, 100) # 100 ROIs of 11×11 pixels
n_rois = size(data, 3)
# Camera provides pixel_size for unit conversion
camera = IdealCamera(0:1023, 0:1023, 0.1) # 100nm pixels
# Create ROIBatch - all ROIs at camera position (1,1) if corners don't matter
batch = ROIBatch(
data,
ones(Int32, n_rois), # x_corners: all at column 1
ones(Int32, n_rois), # y_corners: all at row 1
collect(Int32, 1:n_rois), # frame_indices: 1, 2, 3, ...
camera
)
# Fit with proper unit handling
fitter = GaussMLEConfig(psf_model = GaussianXYNB(0.13f0))
smld, info = fit(batch, fitter)
# Results in microns (relative to ROI corner)
println("Position: ($(smld.emitters[1].x), $(smld.emitters[1].y)) μm")For sCMOS cameras, the corners must be the actual camera positions because the fitter indexes into the pixel-specific variance map. For IdealCamera with uniform noise, corners can all be (1,1) since no variance map lookup is needed.
Creating ROIBatch from Known Positions
You can also create ROIBatch manually with specific corner positions:
using GaussMLE
# Create camera model (65nm pixels)
camera = IdealCamera(0:2047, 0:2047, 0.065)
# Create ROIBatch with camera and corner positions
batch = ROIBatch(
data, # (roi_size, roi_size, n_rois) Float32 array
x_corners, # Vector{Int32} - x position of each ROI on sensor
y_corners, # Vector{Int32} - y position of each ROI on sensor
frame_indices, # Vector{Int32} - frame number for each ROI
camera # Camera model
)
# Fit with proper coordinate conversion
fitter = GaussMLEConfig(psf_model = GaussianXYNB(0.13f0))
smld, info = fit(batch, fitter)Generating Test Data
For testing and development, use generate_roi_batch():
using GaussMLE
# Create camera
camera = IdealCamera(0:1023, 0:1023, 0.1) # 100nm pixels
# Generate synthetic data with Poisson noise
batch = generate_roi_batch(
camera,
GaussianXYNB(0.13f0), # PSF model (sigma in microns)
n_rois = 100,
roi_size = 11
)
# Fit the generated data
fitter = GaussMLEConfig(psf_model = GaussianXYNB(0.13f0))
smld, info = fit(batch, fitter)Performance Tips
- Use
Float32data for best performance (native GPU type) - For large datasets, GPU acceleration provides significant speedups
- Choose the simplest PSF model that adequately describes your data
- Pre-allocate arrays when processing multiple datasets
Next Steps
- Learn about different models and when to use them
- Explore GPU acceleration for large datasets
- Check out the examples for more detailed use cases