Filtrations
Introduction
A filtration is a nested sequence of topological spaces built from data. For images, filtrations are constructed by thresholding intensity values, creating a series of binary images at different levels.
Filtrations are the foundation of persistent homology, allowing us to track how topological features evolve across scales.
What is a Filtration?
Formal Definition (Simplified)
A filtration is a sequence of topological spaces:
where each \(X_i\) is contained in the next.
For Images:
Each \(X_i\) corresponds to regions where intensity is below (or above) a threshold \(\tau_i\).
Intuitive Understanding
Think of a filtration as a movie showing structure appearing/disappearing:
Start with nothing (empty set)
Gradually add pixels/voxels based on intensity
End with the complete image
Analogy: Watching a photograph develop in a darkroom - structure emerges gradually.
Building Filtrations from Images
Sublevel Filtration
Definition: Include pixels with intensity \(\leq\) threshold.
Process:
Start with lowest intensity value
Gradually increase threshold
Add pixels as threshold increases
End with all pixels
Use Cases:
Dark features on bright background
Vessels in angiography (low intensity)
Air in CT scans (dark regions)
In MedTDA:
from medtda import BarcodeExtractor
extractor = BarcodeExtractor(filtration_type='sublevel')
barcodes = extractor.execute(image)
Superlevel Filtration
Definition: Include pixels with intensity \(\geq\) threshold.
Process:
Start with highest intensity value
Gradually decrease threshold
Add pixels as threshold decreases
End with all pixels
Use Cases:
Bright features on dark background
Contrast-enhanced regions (high intensity)
Bright lesions in MRI
Enhanced tumors in CT
In MedTDA:
extractor = BarcodeExtractor(filtration_type='superlevel')
barcodes = extractor.execute(image)
Choosing Filtration Direction
Feature Type |
Filtration |
Example |
|---|---|---|
Dark on bright background |
Sublevel |
Blood vessels |
Bright on dark background |
Superlevel |
Contrast-enhanced lesions |
Both types present |
Try both |
Mixed tissue types |
Tip: Visualize your image - which features stand out?
Cubical Complexes
What are Cubical Complexes?
Cubical complexes are topological structures built from cubes (pixels in 2D, voxels in 3D).
Why Cubical?
Images are naturally defined on grids
Direct construction from pixels/voxels
No need for triangulation
Computationally efficient
Alternative: Simplicial complexes (triangulations) - more common in point cloud TDA but less natural for images.
Construction Methods
MedTDA supports two cubical complex construction methods:
T-Construction (Top-Cell)
Each pixel/voxel becomes a top-dimensional cell - a 2-cube (square) in 2D images or a 3-cube (cube) in 3D images. The filtration value equals the pixel/voxel intensity.
Properties:
More features detected
Finer topological detail
Default and recommended method
In MedTDA:
extractor = BarcodeExtractor(construction='T')
V-Construction (Vertex-Based)
Each pixel/voxel becomes a vertex (0-cube). Higher-dimensional cells are built from the vertex grid, inheriting intensities from the vertices.
Properties:
Fewer features detected
Coarser topological detail
Slightly faster - use when speed is critical
In MedTDA:
extractor = BarcodeExtractor(construction='V')
Comparison
Property |
T-Construction |
V-Construction |
|---|---|---|
Cells per pixel/voxel |
One top-cell |
One vertex |
Feature count |
More features |
Fewer features |
Detail level |
Finer |
Coarser |
Computation speed |
Slightly slower |
Slightly faster |
Recommendation |
Default choice |
Speed-critical applications |
Practical Difference:
# T-construction: More detailed
extractor_t = BarcodeExtractor(construction='T')
barcodes_t = extractor_t.execute(image)
print(f"H1 features: {len(barcodes_t['H1'])}") # e.g., 47 features
# V-construction: Faster, less detail
extractor_v = BarcodeExtractor(construction='V')
barcodes_v = extractor_v.execute(image)
print(f"H1 features: {len(barcodes_v['H1'])}") # e.g., 32 features
Filtration Process
As we sweep through thresholds during a sublevel filtration:
H0 (Connected Components):
Birth: New component appears
Death: Two components merge
One component persists forever (infinite persistence)
H1 (Loops):
Birth: Cycle forms
Death: Cycle gets filled
All H1 features eventually die
H2 (Voids - 3D only):
Birth: Enclosed void forms
Death: Void gets filled
All H2 features eventually die
Multi-Dimensional Images
2D Images (H0, H1): H0 captures separate regions/blobs; H1 captures loops and enclosed areas.
extractor = BarcodeExtractor(max_dimension=1)
barcodes = extractor.execute(image_2d)
h0 = barcodes['H0'] # Connected components
h1 = barcodes['H1'] # Loops
3D Images (H0, H1, H2): H0 captures separate regions; H1 captures tunnels/loops; H2 captures enclosed voids and cavities.
extractor = BarcodeExtractor(max_dimension=2)
barcodes = extractor.execute(image_3d)
h0 = barcodes['H0'] # Connected components
h1 = barcodes['H1'] # Loops/tunnels
h2 = barcodes['H2'] # Voids/cavities
Practical Considerations
Image Preprocessing
Filtrations work best on preprocessed images:
Normalization: Consistent intensity ranges
from medtda import Preprocessor
preprocessor = Preprocessor(
normalize=True,
normalize_method='robust'
)
processed = preprocessor.preprocess(image)
Resampling: Isotropic voxels
preprocessor = Preprocessor(spacing=(1.0, 1.0, 1.0))
Masking: Focus on region of interest
preprocessor = Preprocessor(crop_to_roi=True)
Computational Complexity
Time complexity: Roughly O(n³) for n³ voxels
Memory: Stores cubical complex
Tips for large images:
Downsample if possible
Crop to ROI first
Use V-construction for speed
Process 2D slices instead of full 3D
Mathematical Foundations
Cubical Complexes
A cubical complex is a collection of elementary cubes (vertices, edges, squares, cubes, etc.) in Euclidean space. Medical images naturally form cubical complexes where pixels/voxels are the top-dimensional cubes.
Elementary Cubes: In dimension n, an elementary k-cube is a product:
where exactly k intervals have \(a_i < b_i\) (non-degenerate) and the rest have \(a_i = b_i\) (degenerate).
Examples:
0-cube (vertex): all intervals degenerate, a single point
1-cube (edge): one non-degenerate interval
2-cube (square): two non-degenerate intervals
3-cube (cube): three non-degenerate intervals
Boundary Operator: The boundary of a cube consists of all faces (cubes of one dimension lower) on its surface. For a 2D pixel at (i, j):
Filtered Complexes
A filtration is an increasing sequence of complexes where each complex is a subcomplex of the next:
From Images: Given a grayscale image I with intensity function f(x), filtrations are built by thresholding:
Sublevel sets: \(X_t = \{x : f(x) \leq t\}\)
Superlevel sets: \(X_t = \{x : f(x) \geq t\}\)
Lower-star filtration: For cubical complexes, each lower-dimensional cube (edge, vertex) enters the filtration at the minimum intensity of its cofaces (adjacent pixels):
This ensures the filtration respects the cubical complex structure.
Cubical Homology
Chain Groups: The k-th chain group \(C_k\) consists of formal sums of k-dimensional cubes with coefficients in a field (typically \(\mathbb{Z}/2\mathbb{Z}\)).
Boundary Map: The boundary operator \(\partial_k : C_k \to C_{k-1}\) maps each k-cube to its boundary (collection of (k-1)-faces).
Homology Groups: The k-th homology group is:
This quotient captures:
Cycles: k-dimensional structures with no boundary (\(\partial_k = 0\))
Boundaries: k-dimensional structures that are boundaries of (k+1)-structures
Homology classes: Equivalence classes of cycles that differ by boundaries
Interpretation:
H_0: Connected components (0-cycles not bounding anything)
H_1: Loops (1-cycles that don’t bound 2-dimensional regions)
H_2: Voids (2-cycles that don’t bound 3-dimensional volumes)
See Also
Persistent Homology - Computing homology on filtrations
Barcodes and Diagrams - Visualizing filtration results
Persistent Homology - Practical PH guide
PH Computer - PH computation API