SMLMData.jl
Data types and utilities for Single Molecule Localization Microscopy (SMLM) in Julia.
Overview
SMLMData.jl provides core data structures and operations for working with Single Molecule Localization Microscopy data. The package follows a type-based design that makes it easy to represent, manipulate, and analyze localization data.
Ecosystem Role
SMLMData is the core types package for the JuliaSMLM ecosystem. It defines the foundational types (emitters, cameras, SMLD containers) that all other packages share.
You rarely need to import SMLMData directly. Packages like GaussMLE, SMLMBoxer, and SMLMAnalysis depend on SMLMData and re-export the types you need:
using GaussMLE # Re-exports ROIBatch, camera types, etc.
using SMLMAnalysis # Re-exports all SMLMData types for analysis workflowsDirect using SMLMData is primarily for package developers, standalone data manipulation, or learning the type system.
Emitters
Emitters represent individual fluorophore localizations in single molecule localization microscopy. SMLMData provides several emitter types to accommodate different analysis needs.
Emitter Type Hierarchy
All emitter types derive from the abstract AbstractEmitter base type:
AbstractEmitter
├─ Emitter2D{T} - Basic 2D emitter with position and photons
├─ Emitter3D{T} - Basic 3D emitter with position and photons
├─ Emitter2DFit{T} - 2D emitter with fit results and uncertainties
└─ Emitter3DFit{T} - 3D emitter with fit results and uncertaintiesBasic Emitter Types
The most basic emitter types store only position and photon count:
struct Emitter2D{T} <: AbstractEmitter
x::T # x-coordinate in microns
y::T # y-coordinate in microns
photons::T # number of photons emitted
end
struct Emitter3D{T} <: AbstractEmitter
x::T # x-coordinate in microns
y::T # y-coordinate in microns
z::T # z-coordinate in microns
photons::T # number of photons emitted
endThese types are useful for:
- Simulating fluorophore emissions
- Representing ground truth data
- Simple visualization scenarios
Fit Result Emitter Types
For real data analysis, SMLMData provides extended emitter types that include fit results with uncertainties and tracking information:
mutable struct Emitter2DFit{T} <: AbstractEmitter
x::T # fitted x-coordinate in microns
y::T # fitted y-coordinate in microns
photons::T # fitted number of photons
bg::T # fitted background in photons/pixel
σ_x::T # uncertainty in x position in microns
σ_y::T # uncertainty in y position in microns
σ_photons::T # uncertainty in photon count
σ_bg::T # uncertainty in background level
frame::Int # frame number in acquisition sequence
dataset::Int # identifier for specific acquisition/dataset
track_id::Int # identifier for linking localizations across frames
id::Int # unique identifier within dataset
end
mutable struct Emitter3DFit{T} <: AbstractEmitter
x::T # fitted x-coordinate in microns
y::T # fitted y-coordinate in microns
z::T # fitted z-coordinate in microns
photons::T # fitted number of photons
bg::T # fitted background in photons/pixel
σ_x::T # uncertainty in x position in microns
σ_y::T # uncertainty in y position in microns
σ_z::T # uncertainty in z position in microns
σ_photons::T # uncertainty in photon count
σ_bg::T # uncertainty in background level
frame::Int # frame number in acquisition sequence
dataset::Int # identifier for specific acquisition/dataset
track_id::Int # identifier for linking localizations across frames
id::Int # unique identifier within dataset
endThese types are suitable for:
- Storing localization analysis results
- Quality control and filtering
- Tracking and trajectory analysis
- Multi-dataset analysis
Creating Emitters
# Basic 2D emitter
emitter_2d = Emitter2D{Float64}(1.5, 2.3, 1000.0) # x, y, photons
# Basic 3D emitter
emitter_3d = Emitter3D{Float64}(1.5, 2.3, -0.5, 1000.0) # x, y, z, photons
# 2D emitter with fit results using convenience constructor
emitter_2d_fit = Emitter2DFit{Float64}(
1.5, 2.3, # x, y coordinates (μm)
1000.0, 10.0, # photons, background
0.01, 0.01, # σ_x, σ_y (uncertainties in μm)
50.0, 2.0; # σ_photons, σ_bg (uncertainties)
frame=5, # frame number
dataset=1, # dataset identifier
track_id=2, # tracking identifier (0 = unlinked)
id=42 # unique identifier
)
# 3D emitter with fit results
emitter_3d_fit = Emitter3DFit{Float64}(
1.5, 2.3, -0.5, # x, y, z coordinates (μm)
1000.0, 10.0, # photons, background
0.01, 0.01, 0.02, # σ_x, σ_y, σ_z (uncertainties in μm)
50.0, 2.0; # σ_photons, σ_bg (uncertainties)
frame=5, # frame number
dataset=1, # dataset identifier
track_id=2, # tracking identifier (0 = unlinked)
id=42 # unique identifier
)Type Parameter
All emitter types use a type parameter T to specify the numeric precision:
# Float64 precision (default)
emitter_f64 = Emitter2D{Float64}(1.0, 2.0, 1000.0)
# Float32 precision for reduced memory usage
emitter_f32 = Emitter2D{Float32}(1.0f0, 2.0f0, 1000.0f0)Cameras
Cameras define the imaging system's geometry and handling of pixel coordinates.
Camera Types
SMLMData provides two camera types:
- IdealCamera: For detectors with Poisson noise only (e.g., EMCCD in photon-counting mode)
- SCMOSCamera: For sCMOS detectors with pixel-dependent calibration parameters
IdealCamera
# Create a camera with 512x512 pixels, each 100nm (0.1μm) in size
camera = IdealCamera(512, 512, 0.1)
# For non-square pixels, specify different x and y sizes
camera_rect = IdealCamera(512, 512, (0.1, 0.12))SCMOSCamera
# Minimal: uniform readnoise (assumes offset=0, gain=1, qe=1)
cam_scmos = SCMOSCamera(512, 512, 0.1, 1.6) # 1.6 e⁻ rms readnoise
# From camera spec sheet (e.g., ORCA-Flash4.0 V3)
cam_flash = SCMOSCamera(
2048, 2048, 0.065, # 2048×2048 pixels, 65nm pixel size
1.6, # 1.6 e⁻ rms readnoise from spec
offset = 100.0, # typical dark level (ADU)
gain = 0.46, # 0.46 e⁻/ADU from spec
qe = 0.72 # 72% QE at 550nm
)
# With per-pixel calibration maps (precision SMLM)
readnoise_map = load("camera_noise.mat") # 512×512 measured values
gain_map = load("camera_gain.mat")
qe_map = load("camera_qe.mat")
cam_calibrated = SCMOSCamera(512, 512, 0.1, readnoise_map,
gain=gain_map, qe=qe_map)
# Mixed scalar and matrix parameters
cam_mixed = SCMOSCamera(
512, 512, 0.1, readnoise_map, # Per-pixel noise
offset = 100.0, # Uniform offset
gain = 0.5 # Uniform gain
)SCMOSCamera Parameters:
offset: Dark level in ADU (analog-to-digital units)gain: Conversion gain in e⁻/ADU (electrons per ADU)readnoise: Read noise in e⁻ rms (root-mean-square, matches spec sheets)qe: Quantum efficiency (dimensionless, 0-1)
Each parameter can be:
- Scalar: Uniform value across the sensor
- Matrix: Per-pixel calibration map (size must match pixel grid)
Coordinate Conventions
- All spatial coordinates are in microns
- Physical space: (0,0) at top-left corner of camera
- Pixel space: (1,1) at center of top-left pixel
# Convert between coordinate systems
x_physical, y_physical = pixel_to_physical(10.5, 15.5, 0.1)
px, py = physical_to_pixel(1.05, 1.55, 0.1)ROI Batch Types
ROI (Region of Interest) batch types provide efficient storage and processing of image regions extracted from SMLM data. These types enable batched processing workflows across the JuliaSMLM ecosystem.
SingleROI
A single region of interest with its location context:
struct SingleROI{T}
data::Matrix{T} # ROI image data (roi_size × roi_size)
corner::SVector{2,Int32} # (x, y) = (col, row) corner position
frame_idx::Int32 # Frame number (1-indexed)
end
# Example
roi_data = rand(Float32, 11, 11)
roi = SingleROI(roi_data, SVector{2,Int32}(100, 200), Int32(5))ROIBatch
A batch of ROIs for efficient parallel processing:
struct ROIBatch{T,N,A<:AbstractArray{T,N},C<:AbstractCamera}
data::A # ROI stack (roi_size × roi_size × n_rois)
x_corners::Vector{Int32} # X (column) coordinates of ROI corners
y_corners::Vector{Int32} # Y (row) coordinates of ROI corners
frame_indices::Vector{Int32} # Frame number for each ROI
camera::C # Camera object
roi_size::Int # Size of each ROI (square)
endCreating ROI Batches
# From arrays
camera = IdealCamera(512, 512, 0.1)
data = rand(Float32, 11, 11, 100) # 100 ROIs of 11×11 pixels
corners = rand(Int32(1):Int32(500), 2, 100)
frames = rand(Int32(1):Int32(50), 100)
batch = ROIBatch(data, corners, frames, camera)
# From separate x/y corner vectors
x_corners = rand(Int32(1):Int32(500), 100)
y_corners = rand(Int32(1):Int32(500), 100)
batch = ROIBatch(data, x_corners, y_corners, frames, camera)
# From vector of SingleROI
using StaticArrays
rois = [SingleROI(rand(Float32, 11, 11), SVector{2,Int32}(i*10, i*10), Int32(i))
for i in 1:100]
batch = ROIBatch(rois, camera)Working with ROI Batches
# Indexing
roi = batch[5] # Returns SingleROI
# Iteration
for roi in batch
# Process each ROI
process(roi.data, roi.corner, roi.frame_idx)
end
# Length
n_rois = length(batch)
# GPU adaptation
using CUDA
batch_gpu = adapt(CuArray, batch) # Transfer to GPUCoordinate System
- Camera coordinates: 1-indexed, (1,1) = top-left of full image
- ROI corners: (x, y) = (col, row) position in camera coordinates
- ROI data: Local coordinates, (1,1) = top-left within ROI
- Frame indices: 1-indexed
Typical Workflow
- Extract ROIs: Use SMLMBoxer.jl to detect and extract ROIs from image stack
- Fit ROIs: Use GaussMLE.jl to fit Gaussian PSFs to each ROI
- Convert to SMLD: Convert fit results to
BasicSMLDfor further analysis
SMLD
SMLD (Single Molecule Localization Data) is the container type that holds emitters and camera information.
Creating an SMLD
# Create a vector of emitters
emitters = [
Emitter2D{Float64}(1.0, 2.0, 1000.0),
Emitter2D{Float64}(3.0, 4.0, 1200.0)
]
# Create a BasicSMLD
smld = BasicSMLD(emitters, camera, 1, 1, Dict{String,Any}())
# Add metadata
smld_with_metadata = BasicSMLD(
emitters,
camera,
10, # number of frames
1, # number of datasets
Dict{String,Any}(
"exposure_time" => 0.1,
"sample" => "Test Sample"
)
)Filtering Operations
# Filter by emitter properties
bright_emitters = @filter(smld, photons > 1000)
precise_fits = @filter(smld, σ_x < 0.02 && σ_y < 0.02)
# Select region of interest
region = filter_roi(smld, 0.0:2.0, 1.0:3.0)
# Select frames
frame_5 = filter_frames(smld, 5)
early_frames = filter_frames(smld, 1:10)Combining SMLDs
# Concatenate two SMLD objects
combined = cat_smld(smld1, smld2)
# Merge with sequential frame numbering
merged = merge_smld([smld1, smld2], adjust_frames=true)File I/O
SMLMData currently supports the SMITE format, with more formats planned for future releases.
# Import from SMITE format (MATLAB)
smd = SmiteSMD("path/to/data", "localizations.mat")
smld_2d = load_smite_2d(smd)
smld_3d = load_smite_3d(smd)
# Export to SMITE format
save_smite(smld, "output/directory", "results.mat")Installation
using Pkg
Pkg.add("SMLMData")For complete API documentation, see the API Reference.