.. _api_ph_computer: =========== PH Computer =========== .. currentmodule:: medtda.ph_computer The ``ph_computer`` module provides functions for computing persistent homology from images using cubical complexes. .. contents:: Contents :local: :depth: 2 Overview ======== This module contains the core functions for computing persistent homology (PH) from image data. It uses the GUDHI library's cubical complex implementation. **Key Features:** * Sublevel and superlevel filtrations * T-construction and V-construction cubical complexes * Multi-dimensional homology (H0, H1, H2, ...) * Automatic dimension detection * Infinite persistence handling Basic Usage =========== Quick Start ----------- :: from medtda.ph_computer import compute_ph import numpy as np # Create a simple 2D image image = np.random.rand(50, 50) # Compute persistence barcodes barcodes = compute_ph(image, filtration_type='sublevel') # barcodes is a dict: {'H0': H0 pairs, 'H1': H1 pairs, ...} print(f"H0 features: {len(barcodes['H0'])}") print(f"H1 features: {len(barcodes['H1'])}") With Custom Parameters ---------------------- :: barcodes = compute_ph( image, filtration_type='superlevel', construction='V', max_dimension=2 ) Functions ========= compute_ph ---------- .. autofunction:: medtda.ph_computer.compute_ph Compute persistent homology from an image. **Signature:** .. code-block:: python def compute_ph( image: np.ndarray, filtration_type: str = 'sublevel', construction: str = 'T', max_dimension: int = -1 ) -> Dict[int, np.ndarray] **Parameters:** * **image** (*np.ndarray*) - Input image (2D or 3D) * **filtration_type** (*str*) - ``'sublevel'`` or ``'superlevel'`` (default: ``'sublevel'``) * **construction** (*str*) - ``'T'`` or ``'V'`` for cubical complex construction (default: ``'T'``) * **max_dimension** (*int*) - Maximum homology dimension to compute, ``-1`` for auto (default: ``-1``) **Returns:** * **barcodes** (*dict*) - Dictionary mapping dimension to barcode array * Keys: homology dimensions (0, 1, 2, ...) * Values: NumPy arrays of shape ``(n_features, 2)`` with ``[birth, death]`` columns **Example:** :: import numpy as np from medtda.ph_computer import compute_ph # 3D medical image image = np.random.rand(64, 64, 64) # Compute H0, H1, H2 barcodes = compute_ph( image, filtration_type='sublevel', max_dimension=2 ) # Access barcodes by dimension h0_barcode = barcodes['H0'] # Connected components h1_barcode = barcodes['H1'] # Loops/tunnels h2_barcode = barcodes['H2'] # Voids/cavities # Each barcode is an array of [birth, death] pairs for birth, death in h1_barcode: persistence = death - birth print(f"H1 feature: birth={birth:.3f}, death={death:.3f}, persistence={persistence:.3f}") clean_and_cap_ph ---------------- .. autofunction:: medtda.ph_computer.clean_and_cap_ph Clean and cap persistence values to handle infinite persistence. **Signature:** .. code-block:: python def clean_and_cap_ph( ph_array: np.ndarray, cap_value: float ) -> np.ndarray **Parameters:** * **ph_array** (*np.ndarray*) - Raw persistence barcode array * **cap_value** (*float*) - Value to cap infinite persistence **Returns:** * **cleaned_barcode** (*np.ndarray*) - Cleaned barcode with finite values **Example:** :: from medtda.ph_computer import compute_ph, clean_and_cap_ph barcodes = compute_ph(image) # H0 often has infinite persistence features h0_raw = barcodes['H0'] h0_clean = clean_and_cap_ph(h0_raw, cap_value=1.0) Parameters ========== Filtration Type --------------- **sublevel** Build filtration from low to high intensity values. * Features appear at low intensities (birth) * Features disappear at high intensities (death) * Use for: bright features on dark background **superlevel** Build filtration from high to low intensity values. * Features appear at high intensities * Features disappear at low intensities * Use for: dark features on bright background Example:: # Dark lesions on bright CT scan barcodes_sublevel = compute_ph(image, filtration_type='sublevel') # Bright lesions on dark background barcodes_superlevel = compute_ph(image, filtration_type='superlevel') Construction Method ------------------- **T-construction (default)** * Each voxel becomes a top-dimensional cell * More features, finer detail * Slightly slower computation **V-construction** * Each voxel becomes a vertex * Fewer features, coarser detail * Slightly faster computation Example:: # T-construction: finer detail barcodes_t = compute_ph(image, construction='T') # V-construction: faster computation barcodes_v = compute_ph(image, construction='V') Max Dimension ------------- **-1 (auto)** Automatically determines max dimension from image: * 2D images → max_dimension = 1 (H0, H1) * 3D images → max_dimension = 2 (H0, H1, H2) **0** Compute only H0 (connected components):: barcodes = compute_ph(image, max_dimension=0) # Returns {0: h0_barcode} **1** Compute H0 and H1:: barcodes = compute_ph(image, max_dimension=1) # Returns {0: h0_barcode, 1: h1_barcode} **2** Compute H0, H1, and H2:: barcodes = compute_ph(image, max_dimension=2) # Returns {0: h0_barcode, 1: h1_barcode, 2: h2_barcode} Homology Dimensions =================== H0: Connected Components ------------------------- Represents connected regions in the image:: h0_barcode = barcodes['H0'] # Number of significant connected components # (persistence > threshold) threshold = 0.1 significant_components = np.sum( (h0_barcode[:, 1] - h0_barcode[:, 0]) > threshold ) H1: Loops and Tunnels ---------------------- Represents 1-dimensional holes:: h1_barcode = barcodes['H1'] # Features with high persistence indicate prominent loops persistent_loops = h1_barcode[ (h1_barcode[:, 1] - h1_barcode[:, 0]) > 0.2 ] H2: Voids and Cavities ----------------------- Represents 2-dimensional voids (3D images only):: h2_barcode = barcodes['H2'] # Count significant cavities significant_voids = np.sum( (h2_barcode[:, 1] - h2_barcode[:, 0]) > 0.15 ) Complete Examples ================= Example 1: 2D Image Analysis ----------------------------- :: import numpy as np from medtda.ph_computer import compute_ph from medtda.loaders import load_image # Load 2D image image, metadata = load_image('xray.png') # Compute persistence barcodes = compute_ph( image, filtration_type='sublevel', construction='T', max_dimension=1 # H0 and H1 only for 2D ) # Analyze connected components h0 = barcodes['H0'] persistence_h0 = h0[:, 1] - h0[:, 0] print(f"Connected components: {len(h0)}") print(f"Mean persistence: {persistence_h0.mean():.3f}") print(f"Max persistence: {persistence_h0.max():.3f}") # Analyze loops h1 = barcodes['H1'] persistence_h1 = h1[:, 1] - h1[:, 0] print(f"Loops detected: {len(h1)}") print(f"Significant loops (p>0.1): {np.sum(persistence_h1 > 0.1)}") Example 2: 3D Medical Image ---------------------------- :: import numpy as np from medtda.ph_computer import compute_ph from medtda import Preprocessor from medtda.loaders import load_image, load_mask # Load and preprocess image, _ = load_image('ct_scan.nii.gz') mask, _ = load_mask('organ_mask.nii.gz') preprocessor = Preprocessor( normalize=True, crop_to_roi=True ) processed = preprocessor.preprocess(image, mask) # Compute all homology dimensions barcodes = compute_ph( processed, filtration_type='sublevel', construction='T', max_dimension=2 ) # Analyze 3D topology for dim, barcode in barcodes.items(): persistence = barcode[:, 1] - barcode[:, 0] dim_names = {0: 'Connected Components', 1: 'Tunnels', 2: 'Voids'} print(f"\n{dim_names[dim]} (H{dim}):") print(f" Total features: {len(barcode)}") print(f" Mean persistence: {persistence.mean():.4f}") print(f" Std persistence: {persistence.std():.4f}") print(f" Max persistence: {persistence.max():.4f}") Example 3: Comparing Filtrations --------------------------------- :: from medtda.ph_computer import compute_ph # Dark features (e.g., vessels on bright background) barcodes_sub = compute_ph(ct_image, filtration_type='sublevel') # Bright features (e.g., contrast-enhanced regions) barcodes_sup = compute_ph(ct_image, filtration_type='superlevel') # Compare print("Sublevel filtration:") print(f" H1 features: {len(barcodes_sub[1])}") print("Superlevel filtration:") print(f" H1 features: {len(barcodes_sup[1])}") Performance Tips ================ 1. **Choose appropriate max_dimension:** * For 2D images, max_dimension=1 is usually sufficient * Computing H2 on 3D images can be slow for large volumes 2. **Construction method:** * Use T-construction for detailed analysis * Use V-construction for faster computation on large images 3. **Image size:** * Downsampling or cropping to ROI can significantly speed up computation * Consider preprocessing with ``crop_to_roi=True`` 4. **Infinite persistence:** * H0 always has one infinite persistence feature * Use ``clean_and_cap_ph()`` if needed for downstream analysis See Also ======== * :doc:`barcodeextractor` - Higher-level barcode extraction class * :doc:`featureextractor` - Complete feature extraction pipeline * :doc:`../user_guide/persistent_homology` - PH concepts and usage guide * :doc:`../theory/persistent_homology` - Mathematical background