RBC Aggregation Analysis
High-performance 3D analysis of red blood cell aggregation from confocal microscopy. Written in Rust.
Pipeline
┌────────────┐ ┌────────────┐ ┌────────────┐ ┌────────────┐
│ TIFF │ │ ML │ │ OBJ │ │ SPATIAL │
│ Stack │────▶│ Segment │────▶│ Meshes │────▶│ Analysis │
│ │ │ (ilastik) │ │ │ │ │
└────────────┘ └────────────┘ └────────────┘ └────────────┘
│ │ │
▼ ▼ ▼
┌────────────┐ ┌────────────┐ ┌────────────┐
│ Intensity │ │ Inertia │ │ g(r) │
│ Profile │ │ Tensor │ │ Function │
└────────────┘ └────────────┘ └────────────┘
Shape Classification via Inertia Tensor
RBC morphology is encoded in the eigenvalues (λ₁ ≥ λ₂ ≥ λ₃) of the gyration tensor:
┌────────────────────────────────────────┐
│ SHAPE SPACE │
│ │
λ₁/λ₂ │ Elliptocyte · │
▲ │ · · Stomatocyte │
│ │ · · · │
│ │ Discocyte │
│ │ · (healthy) · │
│ │ · │
│ │ Spherocyte │
│ │ · │
└────┼─────────────────────────────────────▶ │
│ λ₂/λ₃ │
└────────────────────────────────────────┘
Asphericity = λ₁ - ½(λ₂ + λ₃) → deviation from sphere
Acylindricity = λ₂ - λ₃ → deviation from cylinder
Pair Correlation Function
Quantifies aggregation by measuring spatial distribution:
g(r)
▲
│ ╭─╮
│ ╱ ╲ Aggregation peak
│ ╱ ╲ (cells cluster at this distance)
1 │──╱───────╲──────────────────
│ ╱ ╲
│╱ ╲______________
│
└────────────────────────────▶ r
│
└── Contact distance (~8μm for RBCs)
For random distribution, g(r) = 1. Peaks indicate preferred separation distances.
Why Rust?
| Concern | Solution |
|---|---|
| Large meshes (100K+ vertices) | Zero-copy parsing, stack allocation |
| Batch processing (1000s of cells) | Rayon parallel iterators |
| Numerical stability | nalgebra with proper epsilon handling |
| Memory safety | Borrow checker prevents data races |
Core Algorithm
// Pair correlation with interior particle handling
fn compute_g_r(&self, positions: &[[f64; 3]]) -> Vec<f64> {
let interior = positions.par_iter()
.filter(|p| self.is_interior(p))
.collect::<Vec<_>>();
interior.par_iter()
.map(|ref_pos| self.histogram_distances(ref_pos, positions))
.reduce(|| vec![0.0; n_bins], |a, b| add_vecs(a, b))
.normalize_by_shell_volume()
}