Skip to content

Commit dc784af

Browse files
Hendrik-codeclaude
andcommitted
Phase 3: add per-folder README.md API reference files
Add a README.md to each sub-package documenting its purpose, key classes/functions with one-line descriptions, and minimal usage examples. Folders covered: core, core/poi_fun, logger, mesh3D, registration, segmentation, spine, spine/snapshot2D, spine/spinestats, stitching. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent c7faff8 commit dc784af

10 files changed

Lines changed: 411 additions & 3 deletions

File tree

TPTBox/core/README.md

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
# TPTBox Core
2+
3+
The `core` subpackage is the foundation of TPTBox. It provides the three primary abstractions —
4+
`NII`, `POI`, and `BIDS_FILE` — along with helper utilities for array operations and anatomical constants.
5+
6+
## Key Classes and Functions
7+
8+
### `nii_wrapper.py` — NIfTI image wrapper
9+
10+
| Symbol | Description |
11+
|---|---|
12+
| `NII` | Wraps `nibabel.Nifti1Image`; the central image type throughout TPTBox |
13+
| `NII.load(path, seg)` | Load a NIfTI file from disk (classmethod) |
14+
| `NII.from_numpy(arr, affine, seg)` | Construct from a numpy array and affine matrix |
15+
| `NII.reorient(axcodes_to)` | Reorient to a canonical axis code (e.g. `("R","A","S")`) |
16+
| `NII.rescale(voxel_spacing)` | Resample to new voxel spacing in mm |
17+
| `NII.resample_from_to(other)` | Resample to match the grid of another `NII` |
18+
| `NII.apply_mask(mask)` | Zero-out voxels outside a binary/label mask |
19+
| `NII.map_labels(label_map)` | Remap integer labels |
20+
| `NII.save(path)` | Save to disk as `.nii` or `.nii.gz` |
21+
| `NII.get_array()` | Return a copy of the underlying numpy array |
22+
| `NII.get_seg_array()` | Same as `get_array()` but asserts `seg=True` |
23+
| `Image_Reference` | Type alias: `BIDS_FILE | Nifti1Image | Path | str | NII` |
24+
25+
### `bids_files.py` — BIDS dataset navigation
26+
27+
| Symbol | Description |
28+
|---|---|
29+
| `BIDS_Global_info` | Scans a dataset root and indexes all BIDS files |
30+
| `BIDS_Global_info.enumerate_subjects()` | Iterate over subjects as `(subject_id, Subject_Container)` |
31+
| `Subject_Container` | Per-subject file index; entry point for queries |
32+
| `Subject_Container.new_query()` | Returns a `Searchquery` for this subject |
33+
| `BIDS_FILE` | One file parsed into BIDS entities (sub, ses, format, …) |
34+
| `BIDS_FILE.open_nii()` | Load this file's NIfTI |
35+
| `BIDS_FILE.get_changed_path(...)` | Derive a new path with changed BIDS entities |
36+
| `Searchquery` | Fluent query builder: `.filter()`, `.loop_dict()`, `.first()` |
37+
| `BIDS_Family` | `dict[str, list[BIDS_FILE]]` grouping files by format |
38+
39+
### `poi.py` — Points of Interest
40+
41+
| Symbol | Description |
42+
|---|---|
43+
| `POI` | Maps `(vertebra_id, subregion_id) → (x, y, z)` |
44+
| `calc_centroids(seg_nii)` | Compute centroids for every label in a segmentation |
45+
| `calc_poi_from_subreg_vert(vert, subreg)` | Compute POIs from paired vertebra + subregion segmentations |
46+
| `POI.save(path)` | Serialise to JSON |
47+
| `POI.load(path)` | Deserialise from JSON |
48+
| `POI.to_global(ref)` | Convert from voxel to world (mm) coordinates |
49+
| `POI.to_local(ref)` | Convert from world to voxel coordinates |
50+
51+
### `np_utils.py` — NumPy utilities
52+
53+
| Symbol | Description |
54+
|---|---|
55+
| `np_extract_label(arr, label)` | Extract a single label as a binary mask |
56+
| `np_center_of_mass(arr)` | Per-label centre-of-mass |
57+
| `np_volume(arr)` | Per-label voxel count |
58+
| `np_bbox_binary(mask)` | Bounding-box slice tuple for a binary array |
59+
| `np_dilate_msk(arr, mm, zoom)` | Morphological dilation by `mm` millimetres |
60+
| `np_erode_msk(arr, mm, zoom)` | Morphological erosion |
61+
| `np_fill_holes(arr)` | Fill holes per label |
62+
| `np_connected_components(arr)` | Label connected components |
63+
| `np_map_labels(arr, label_map)` | Remap label integers via a dict |
64+
| `np_unique(arr)` | Unique values (faster than `np.unique` for uint arrays) |
65+
66+
### `vert_constants.py` — Anatomical constants
67+
68+
| Symbol | Description |
69+
|---|---|
70+
| `Location` | `IntEnum` of anatomical subregion IDs (used as POI keys) |
71+
| `Vertebra_Instance` | Maps integer IDs → anatomical names (C1–S1) |
72+
| `v_name2idx` | Dict: `"L1" → 20`, etc. |
73+
| `v_idx2name` | Dict: `20 → "L1"`, etc. |
74+
| `v_idx_order` | Canonical sort order for vertebra IDs |
75+
| `ZOOMS` | Type alias: `tuple[float, float, float]` |
76+
| `AX_CODES` | Type alias: `tuple[str, str, str]` |
77+
| `AFFINE` | Type alias: `np.ndarray` (4×4) |
78+
79+
## Quick Example
80+
81+
```python
82+
from TPTBox import NII, BIDS_Global_info, calc_centroids
83+
84+
# Load and resample a CT
85+
ct = NII.load("sub-001_ct.nii.gz", seg=False)
86+
ct_ras = ct.reorient(("R", "A", "S")).rescale((1.0, 1.0, 1.0))
87+
88+
# Compute centroids from a segmentation
89+
seg = NII.load("sub-001_seg.nii.gz", seg=True)
90+
poi = calc_centroids(seg)
91+
print(poi)
92+
93+
# Scan a BIDS dataset
94+
bids = BIDS_Global_info(["dataset/"], parents=["rawdata"])
95+
for subj, container in bids.enumerate_subjects():
96+
t2 = container.new_query().filter("format", "T2w").first()
97+
```

TPTBox/core/poi_fun/README.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# POI Strategies (`core/poi_fun`)
2+
3+
Internal subpackage implementing the different strategies for computing Points of Interest (POIs)
4+
from NIfTI segmentation volumes. End users typically call the high-level helpers in `poi.py` and
5+
`vert_constants.py`; the modules here provide the underlying algorithms.
6+
7+
## Modules
8+
9+
| Module | Description |
10+
|---|---|
11+
| `ray_casting.py` | Casts rays through a volume to find surface-intersection points |
12+
| `vertebra_direction.py` | Derives superior/inferior/anterior/posterior unit vectors per vertebra |
13+
| `vertebra_pois_non_centroids.py` | Computes non-centroid anatomical landmarks (process tips, endplates) |
14+
| `pixel_based_point_finder.py` | Locates extreme/boundary pixels within a label for POI placement |
15+
| `strategies.py` | Pluggable strategy objects for POI computation |
16+
| `save_load.py` | JSON serialisation/deserialisation for `POI` objects |
17+
| `save_mkr.py` | Export POIs as 3D Slicer markup files (`.fcsv`, `.mrk.json`) |
18+
| `poi_abstract.py` | Abstract base classes shared across POI modules |
19+
| `poi_global.py` | `POI_Global` — POI container in world-coordinate (mm) space |
20+
| `_help.py` | Internal helpers (not part of the public API) |
21+
22+
## Key symbols
23+
24+
| Symbol | Module | Description |
25+
|---|---|---|
26+
| `POI_Global` | `poi_global.py` | World-space POI container; used after `POI.to_global()` |
27+
| `save_poi` | `save_load.py` | Serialise a `POI` to a JSON file |
28+
| `load_poi` | `save_load.py` | Deserialise a `POI` from a JSON file |
29+
| `save_poi_as_slicer_markup` | `save_mkr.py` | Write POIs as a 3D Slicer `.mrk.json` markup file |
30+
31+
## Coordinate system
32+
33+
POIs inside this package use the same convention as `poi.py`:
34+
- **Local** (`is_global() == False`): voxel indices `(i, j, k)` into the reference NIfTI
35+
- **Global** (`is_global() == True`): world coordinates in mm, consistent with the NIfTI affine

TPTBox/logger/README.md

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# Logger (`TPTBox.logger`)
2+
3+
Structured, consistent logging for long-running medical image processing pipelines.
4+
Provides a simple interface with configurable verbosity, message categories, and output targets.
5+
6+
## Public API
7+
8+
```python
9+
from TPTBox import Logger, Print_Logger, No_Logger, String_Logger, Log_Type
10+
```
11+
12+
## Key classes
13+
14+
| Class | Description |
15+
|---|---|
16+
| `Logger` | Base logger; prints to stdout with optional file output and timestamps |
17+
| `Print_Logger` | Always-verbose logger — prints every message regardless of `verbose` flag |
18+
| `No_Logger` | Silent logger — discards all messages; useful in batch/library code |
19+
| `String_Logger` | Accumulates messages into an in-memory string; useful for testing |
20+
| `Reflection_Logger` | Wraps another logger and mirrors its messages to a second logger |
21+
| `Logger_Interface` | Abstract base class for custom logger implementations |
22+
23+
## Log_Type enum
24+
25+
| Member | Meaning |
26+
|---|---|
27+
| `Log_Type.BOLD` | Highlighted/important message |
28+
| `Log_Type.OK` | Success confirmation |
29+
| `Log_Type.WARNING` | Non-fatal warning |
30+
| `Log_Type.FAIL` | Error or failure |
31+
| `Log_Type.TEXT` | Plain informational text |
32+
33+
## Example
34+
35+
```python
36+
from TPTBox import Logger, Log_Type
37+
38+
log = Logger(path="run.log", log_filename="pipeline", default_verbose=True)
39+
40+
log.print("Starting segmentation", Log_Type.BOLD)
41+
log.print("Loaded 42 subjects", Log_Type.OK)
42+
log.print("Missing T2w for sub-007", Log_Type.WARNING)
43+
44+
# Suppress all output (e.g. in a library function)
45+
from TPTBox import No_Logger
46+
log = No_Logger()
47+
log.print("This is silently discarded")
48+
```

TPTBox/mesh3D/README.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# Mesh 3D (`TPTBox.mesh3D`)
2+
3+
3D surface mesh generation from segmentation NIfTI volumes and rendering of 3D snapshots.
4+
Requires `pyvista` and `vtk` (included in the `dev` extras).
5+
6+
## Key symbols
7+
8+
| Symbol | Module | Description |
9+
|---|---|---|
10+
| `Mesh` | `mesh.py` | Generates a surface mesh from a segmentation label using marching cubes |
11+
| `create_snapshot3D` | `snapshot3D.py` | Renders a 3D snapshot from a list of meshes to a PNG file |
12+
| `LABEL_COLORS` | `mesh_colors.py` | Default colour mapping for anatomical label IDs |
13+
| `label_to_color(label_id)` | `mesh_colors.py` | Look up the RGB colour for a given label |
14+
| `create_html_preview(meshes)` | `html_preview.py` | Generate an interactive HTML file with an embedded 3D viewer |
15+
16+
## Example
17+
18+
```python
19+
from TPTBox import NII
20+
from TPTBox.mesh3D.mesh import Mesh
21+
from TPTBox.mesh3D.snapshot3D import create_snapshot3D
22+
23+
seg = NII.load("seg.nii.gz", seg=True)
24+
25+
# Build meshes for all labels and render
26+
meshes = [Mesh(seg, label=lbl) for lbl in seg.unique_labels()]
27+
create_snapshot3D(meshes, to="snapshot3D.png")
28+
```
29+
30+
## Installation
31+
32+
```bash
33+
pip install pyvista vtk
34+
# or via the dev extras:
35+
poetry install --with dev
36+
```

TPTBox/registration/README.md

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# Registration (`TPTBox.registration`)
2+
3+
Image registration utilities supporting rigid (point- and intensity-based) and deformable
4+
registration. Wraps ANTs (via SimpleITK) and the optional DeepALI deep learning backend.
5+
6+
## Public API
7+
8+
```python
9+
from TPTBox.registration import (
10+
Point_Registration,
11+
ridged_points_from_poi,
12+
ridged_points_from_subreg_vert,
13+
Deformable_Registration,
14+
Template_Registration,
15+
General_Registration, # requires hf-deepali
16+
Rigid_Elements_Registration, # requires hf-deepali
17+
)
18+
```
19+
20+
## Key symbols
21+
22+
| Symbol | Module | Description |
23+
|---|---|---|
24+
| `Point_Registration` | `_ridged_points/point_registration.py` | Rigid registration from paired 3D landmark sets |
25+
| `ridged_points_from_poi(fixed, moving, poi_fixed, poi_moving)` | same | Convenience wrapper: align two NIIs using POI correspondences |
26+
| `ridged_points_from_subreg_vert(...)` | same | Same but derives POIs from vertebra+subregion segmentations automatically |
27+
| `Deformable_Registration` | `_deformable/deformable_reg.py` | ANTs-based deformable (SyN) registration |
28+
| `Template_Registration` | `_deformable/deformable_reg.py` | Deformable registration to an atlas/template |
29+
| `General_Registration` | `_deepali/` | DeepALI deep-learning registration (requires `hf-deepali`) |
30+
| `Rigid_Elements_Registration` | `_deepali/` | Per-element rigid registration via DeepALI |
31+
32+
## Installation of optional dependency
33+
34+
```bash
35+
pip install hf-deepali # only needed for General_Registration / Rigid_Elements_Registration
36+
```
37+
38+
## Example
39+
40+
```python
41+
from TPTBox.registration import ridged_points_from_poi
42+
43+
fixed_nii = NII.load("fixed.nii.gz", seg=False)
44+
moving_nii = NII.load("moving.nii.gz", seg=False)
45+
46+
registered, transform = ridged_points_from_poi(
47+
fixed_nii, moving_nii,
48+
poi_fixed=poi_fixed,
49+
poi_moving=poi_moving,
50+
)
51+
registered.save("registered.nii.gz")
52+
```

TPTBox/segmentation/README.md

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# Segmentation (`TPTBox.segmentation`)
2+
3+
Integration with external segmentation pipelines. Provides a consistent `NII`-based interface
4+
over SPINEPS, VibeSeg/TotalVibeSeg, and nnU-Net.
5+
6+
## Public API
7+
8+
```python
9+
from TPTBox.segmentation import (
10+
run_spineps,
11+
run_vibeseg,
12+
run_totalvibeseg,
13+
run_nnunet,
14+
run_inference_on_file,
15+
extract_vertebra_bodies_from_VibeSeg,
16+
)
17+
```
18+
19+
## Key functions
20+
21+
| Function | Module | Description |
22+
|---|---|---|
23+
| `run_spineps(img_nii, model, ...)` | `spineps.py` | Run SPINEPS spine segmentation on a NIfTI; returns vertebra + subregion masks |
24+
| `run_vibeseg(img_nii, ...)` | `VibeSeg/vibeseg.py` | Run VibeSeg body composition segmentation |
25+
| `run_totalvibeseg(img_nii, ...)` | `VibeSeg/vibeseg.py` | Run TotalVibeSeg — extended label set |
26+
| `run_nnunet(img_nii, model_dir, ...)` | `VibeSeg/vibeseg.py` | Generic nnU-Net inference on a single NIfTI |
27+
| `run_inference_on_file(path, ...)` | `nnUnet_utils/inference_api.py` | Low-level nnU-Net inference on a file path |
28+
| `extract_vertebra_bodies_from_VibeSeg(seg)` | `VibeSeg/vibeseg.py` | Post-process VibeSeg output to isolate vertebra bodies |
29+
30+
## Dependencies
31+
32+
| Pipeline | Requirement |
33+
|---|---|
34+
| SPINEPS | `pip install spineps` + model weights |
35+
| VibeSeg / TotalVibeSeg | `pip install nnunetv2` + model weights (auto-downloaded on first run) |
36+
| Generic nnU-Net | `pip install nnunetv2` + custom model directory |
37+
38+
All external tools are imported lazily — the core TPTBox package installs and imports cleanly
39+
without them.
40+
41+
## Example
42+
43+
```python
44+
from TPTBox import NII
45+
from TPTBox.segmentation import run_spineps
46+
47+
ct = NII.load("ct.nii.gz", seg=False)
48+
vert_seg, subreg_seg = run_spineps(ct, model="small")
49+
vert_seg.save("vertebrae.nii.gz")
50+
```

TPTBox/spine/README.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Spine (`TPTBox.spine`)
2+
3+
Spine-specific utilities built on top of the core `NII` and `POI` abstractions.
4+
Contains two sub-modules: 2D snapshot generation and statistical spine measurements.
5+
6+
## Sub-modules
7+
8+
| Sub-module | Description |
9+
|---|---|
10+
| [`snapshot2D/`](snapshot2D/README.md) | Modular 2D image snapshot generation (slices, MIPs, overlays) |
11+
| [`spinestats/`](spinestats/README.md) | Clinical measurements: distances, Cobb angles, IVD POIs, endplates |
12+
13+
## Quick Example
14+
15+
```python
16+
from TPTBox import NII, calc_centroids
17+
from TPTBox.spine.snapshot2D.snapshot_modular import Snapshot_Frame, create_snapshot
18+
19+
ct = NII.load("ct.nii.gz", seg=False)
20+
seg = NII.load("seg.nii.gz", seg=True)
21+
22+
# Generate a 2D sagittal snapshot with a segmentation overlay
23+
create_snapshot(
24+
[Snapshot_Frame(image=ct, segmentation=seg, mode="CT")],
25+
to="snapshot.png",
26+
)
27+
```

TPTBox/spine/snapshot2D/README.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# 2D Snapshots (`spine/snapshot2D`)
2+
3+
Modular 2D image generation for NIfTI data. Supports axial/sagittal/coronal slices,
4+
maximum intensity projections (MIPs), and segmentation overlays.
5+
6+
## Key symbols
7+
8+
| Symbol | Module | Description |
9+
|---|---|---|
10+
| `create_snapshot` | `snapshot_modular.py` | Main entry point — renders a list of `Snapshot_Frame` objects to a PNG |
11+
| `Snapshot_Frame` | `snapshot_modular.py` | Configuration for one image panel (image, overlay, view direction, …) |
12+
| `Plane` | `snapshot_modular.py` | Enum: `Plane.axial`, `Plane.sagittal`, `Plane.coronal` |
13+
| `to_image_nii` | `snapshot_modular.py` | Convert a NIfTI slice to a matplotlib-ready RGB array |
14+
| Pre-built templates | `snapshot_templates.py` | Ready-to-use snapshot configurations for common spine workflows |
15+
16+
## Example
17+
18+
```python
19+
from TPTBox.spine.snapshot2D.snapshot_modular import Snapshot_Frame, create_snapshot, Plane
20+
21+
frames = [
22+
Snapshot_Frame(image=ct, segmentation=seg, mode="CT", plane=Plane.sagittal),
23+
Snapshot_Frame(image=ct, mode="CT", plane=Plane.axial),
24+
]
25+
create_snapshot(frames, to="output.png")
26+
```

0 commit comments

Comments
 (0)