|
|
@@ -1,216 +0,0 @@
|
|
|
-# spatial_suv_charact
|
|
|
-
|
|
|
-Utilities for PET SUV NIfTI analysis, with emphasis on spatial properties of high-SUV tail regions.
|
|
|
-
|
|
|
-The code is organized into focused modules instead of one long `utils.py` file. This keeps the data-management, image-processing, feature-extraction and plotting tasks separate and easier to test.
|
|
|
-
|
|
|
-## File organization
|
|
|
-
|
|
|
-```text
|
|
|
-utils.py -> remove or keep only temporary imports
|
|
|
-metadata.py -> dataframe / patient metadata utilities
|
|
|
-image_io.py -> NIfTI loading and segmentation application
|
|
|
-suv_stats.py -> simple SUV distribution features
|
|
|
-spatial_features.py -> tail features and helper functions
|
|
|
-plotting.py -> Plotly visualization
|
|
|
-```
|
|
|
-
|
|
|
-In this version, `utils.py` is kept as a thin compatibility layer that re-exports the functions from the focused modules. New code should import directly from the specific module.
|
|
|
-
|
|
|
-## Recommended imports
|
|
|
-
|
|
|
-```python
|
|
|
-from spatial_suv_charact.metadata import (
|
|
|
- get_meta_data,
|
|
|
- flag_corrupted_files,
|
|
|
- flag_AE_patients,
|
|
|
- get_AE_statistics,
|
|
|
-)
|
|
|
-from spatial_suv_charact.image_io import get_processed_image
|
|
|
-from spatial_suv_charact.suv_stats import get_suv_percentiles
|
|
|
-from spatial_suv_charact.spatial_features import compute_tail_spatial_features
|
|
|
-from spatial_suv_charact.plotting import plot_suv_pdf_plotly, plot_hot_voxels_plotly
|
|
|
-```
|
|
|
-
|
|
|
-Older notebooks can still use:
|
|
|
-
|
|
|
-```python
|
|
|
-from spatial_suv_charact.utils import compute_tail_spatial_features
|
|
|
-```
|
|
|
-
|
|
|
-but this should be treated as temporary.
|
|
|
-
|
|
|
-## Typical workflow
|
|
|
-
|
|
|
-```python
|
|
|
-from spatial_suv_charact.metadata import get_meta_data, flag_corrupted_files, flag_AE_patients
|
|
|
-from spatial_suv_charact.image_io import get_processed_image
|
|
|
-from spatial_suv_charact.suv_stats import get_suv_percentiles
|
|
|
-from spatial_suv_charact.spatial_features import compute_tail_spatial_features
|
|
|
-from spatial_suv_charact.plotting import plot_suv_pdf_plotly
|
|
|
-
|
|
|
-# 1. Build metadata table.
|
|
|
-df_meta = get_meta_data("/path/to/raw/data")
|
|
|
-df_meta = flag_corrupted_files(df_meta)
|
|
|
-df_meta = flag_AE_patients(df_meta)
|
|
|
-
|
|
|
-# 2. Load PET image and apply segmentation mask.
|
|
|
-row, image = get_processed_image(
|
|
|
- df_meta,
|
|
|
- patient_id="NIX-LJU-D2002-IRAE-A001",
|
|
|
- organ="Lung",
|
|
|
- visit=0,
|
|
|
-)
|
|
|
-
|
|
|
-# 3. Compute simple SUV percentiles.
|
|
|
-percentile_df = get_suv_percentiles(
|
|
|
- image,
|
|
|
- percentiles=(50, 75, 90, 95, 99),
|
|
|
-)
|
|
|
-
|
|
|
-# 4. Compute spatial high-tail features.
|
|
|
-features = compute_tail_spatial_features(
|
|
|
- image,
|
|
|
- percentiles=(90, 95, 97.5, 99),
|
|
|
- connectivity=26,
|
|
|
- min_component_voxels=3,
|
|
|
- image_id="NIX-LJU-D2002-IRAE-A001_Lung_VISIT_0",
|
|
|
-)
|
|
|
-
|
|
|
-# 5. Plot SUV distribution.
|
|
|
-fig, percentile_df = plot_suv_pdf_plotly(
|
|
|
- image,
|
|
|
- percentiles=(50, 75, 90, 95, 99),
|
|
|
- log_x=False,
|
|
|
-)
|
|
|
-fig.show()
|
|
|
-```
|
|
|
-
|
|
|
-## Main feature-extraction function
|
|
|
-
|
|
|
-The central function is:
|
|
|
-
|
|
|
-```python
|
|
|
-compute_tail_spatial_features(
|
|
|
- image,
|
|
|
- voxel_spacing=None,
|
|
|
- percentiles=(90, 95, 97.5, 99),
|
|
|
- connectivity=26,
|
|
|
- min_component_voxels=1,
|
|
|
- image_id=None,
|
|
|
-)
|
|
|
-```
|
|
|
-
|
|
|
-The input `image` is assumed to be a processed PET SUV NIfTI image. Finite positive voxels are treated as the region of interest. This works naturally if the image was produced by multiplying PET SUV by an organ segmentation mask.
|
|
|
-
|
|
|
-For each percentile `q`, the high-SUV tail is defined as:
|
|
|
-
|
|
|
-```text
|
|
|
-R_q = {voxel : SUV(voxel) >= percentile_q(SUV inside ROI)}
|
|
|
-```
|
|
|
-
|
|
|
-The function returns one dataframe row per percentile.
|
|
|
-
|
|
|
-## Tail features currently computed
|
|
|
-
|
|
|
-### Basic tail intensity
|
|
|
-
|
|
|
-- `threshold`
|
|
|
-- `tail_mean`
|
|
|
-- `tail_median`
|
|
|
-- `tail_max`
|
|
|
-- `tail_std`
|
|
|
-- `tail_cv`
|
|
|
-- `tail_sum`
|
|
|
-- `tail_excess_mean`
|
|
|
-- `tail_excess_sum`
|
|
|
-
|
|
|
-### Volume / voxel counts
|
|
|
-
|
|
|
-- `n_roi_voxels`
|
|
|
-- `roi_volume_mm3`
|
|
|
-- `n_tail_voxels`
|
|
|
-- `tail_volume_mm3`
|
|
|
-- `tail_fraction`
|
|
|
-
|
|
|
-Note: if the threshold is defined as a within-ROI percentile, `tail_fraction` is mostly determined by the chosen percentile. It is included mainly for checking and completeness.
|
|
|
-
|
|
|
-### Spatial spread
|
|
|
-
|
|
|
-- `tail_spread_mm2`
|
|
|
-- `tail_weighted_spread_mm2`
|
|
|
-
|
|
|
-These measure how spatially dispersed high-SUV voxels are.
|
|
|
-
|
|
|
-### Local contrast
|
|
|
-
|
|
|
-- `tail_local_contrast`
|
|
|
-- `tail_local_contrast_norm`
|
|
|
-
|
|
|
-`tail_local_contrast` is a continuous, non-discretized contrast-like measure:
|
|
|
-
|
|
|
-```text
|
|
|
-mean over neighboring voxel pairs inside R_q of (SUV_i - SUV_j)^2
|
|
|
-```
|
|
|
-
|
|
|
-`tail_local_contrast_norm` divides this value by `tail_mean ** 2`, giving a dimensionless version that is easier to compare across patients.
|
|
|
-
|
|
|
-### Connected-component features
|
|
|
-
|
|
|
-- `n_components`
|
|
|
-- `largest_component_voxels`
|
|
|
-- `largest_component_volume_mm3`
|
|
|
-- `largest_component_fraction`
|
|
|
-- `component_entropy`
|
|
|
-
|
|
|
-These describe whether high-SUV voxels form one dominant region or many disconnected foci.
|
|
|
-
|
|
|
-### Shape feature
|
|
|
-
|
|
|
-- `largest_component_sphericity`
|
|
|
-
|
|
|
-This is an approximate marching-cubes-based sphericity of the largest connected component.
|
|
|
-
|
|
|
-## Connectivity
|
|
|
-
|
|
|
-The `connectivity` argument controls both connected components and local contrast neighborhoods:
|
|
|
-
|
|
|
-```text
|
|
|
-6 -> face neighbors
|
|
|
-18 -> face + edge neighbors
|
|
|
-26 -> face + edge + corner neighbors
|
|
|
-```
|
|
|
-
|
|
|
-For small or noisy PET regions, `connectivity=26` and `min_component_voxels=3` is a reasonable starting point.
|
|
|
-
|
|
|
-## Dependencies
|
|
|
-
|
|
|
-Required Python packages:
|
|
|
-
|
|
|
-```text
|
|
|
-numpy
|
|
|
-pandas
|
|
|
-nibabel
|
|
|
-scipy
|
|
|
-scikit-image
|
|
|
-plotly
|
|
|
-```
|
|
|
-
|
|
|
-Install with:
|
|
|
-
|
|
|
-```bash
|
|
|
-pip install numpy pandas nibabel scipy scikit-image plotly
|
|
|
-```
|
|
|
-
|
|
|
-## Notes from code cleanup
|
|
|
-
|
|
|
-The original single file contained several useful functions but had started to mix several responsibilities:
|
|
|
-
|
|
|
-- metadata parsing,
|
|
|
-- patient/AE flags,
|
|
|
-- image loading and segmentation,
|
|
|
-- SUV summaries,
|
|
|
-- Plotly visualization,
|
|
|
-- spatial tail-feature extraction.
|
|
|
-
|
|
|
-It also contained duplicate imports and repeated sections. The new structure keeps functions simple and explicit. I would postpone introducing a class until the workflow stabilizes further. A class can be added later as a thin convenience wrapper, but the current function-based design is easier to test and use in notebooks.
|