Skip to content

ENH: Add NV-Segment-CTMR segmentation backend - #104

Merged
aylward merged 2 commits into
Project-MONAI:mainfrom
aylward:NVSegment
Aug 2, 2026
Merged

ENH: Add NV-Segment-CTMR segmentation backend#104
aylward merged 2 commits into
Project-MONAI:mainfrom
aylward:NVSegment

Conversation

@aylward

@aylward aylward commented Aug 2, 2026

Copy link
Copy Markdown
Collaborator

Add SegmentNVSegmentCTMRI, a VISTA3D-derived segmenter wrapping NVIDIA's NV-Segment-CTMR model (345 classes across CT_BODY, MRI_BODY, MRI_BRAIN). Weights are pulled from HuggingFace on first use; the OneWay Non-Commercial license is logged at WARNING on first call.

  • SegmentAnatomyBase gains labelmap_dtype (default np.uint8) and _finalize_other_group(id_range) so backends whose class indices exceed 255 can emit uint16 labelmaps. NV-Segment-CTMR uses the model's published indices verbatim (up to 345), so it sets np.uint16.
  • Register the backend in physiotwin4d.init, the CLI factory ("NVSegmentCTMR"), and a session-scoped conftest fixture.
  • USDAnatomyTools: add render params for the new brain_parcellation group -- shared grey-matter and CSF dicts plus overrides for white matter, WMH, ventricles, pallidum, brain stem, and cerebellar cortex. Several keys exist only to outrank shorter substring matches (e.g. "lateral_ventricle" vs the heart's "ventricle_left").
  • Docs: API page for the new segmenter, plus architecture/FAQ/workflow updates.
  • Experiments: add Lung-GatedCT_To_USD_NV variant of the DIRLAB pipeline (4DCT registration, model building, painting).
  • Tutorials: add tutorial_04_lung_create_statistical_model.

Breaking API changes:

  • ContourTools.save_combined_surface(surfaces, output_dir, prefix) -> save_combined_surfaces(surfaces, output_filename).
  • WorkflowCreateStatisticalModel.run_workflow() -> process(), matching the other workflows. Default pca_number_of_components 15 -> 7.
  • WorkflowConvertImageToVTK.ANATOMY_GROUPS -> anatomy_groups (instance attribute, not a constant).
  • ContourTools.extract_contours() exposes smoothing_iterations and smoothing_scale, and no longer applies a hard-coded Taubin pass afterward.
  • Module-level _extract_surface() folded into ContourTools.extract_surface().

Summary by CodeRabbit

  • New Features

    • Added CT and MRI segmentation using NVIDIA’s NV-Segment-CTMR model, supporting 345 anatomy classes and high-resolution label maps.
    • Added workflows and tutorials for registering, modeling, and exporting segmented lung anatomy to USD.
    • Improved brain anatomy rendering presets.
  • Enhancements

    • Added configurable contour smoothing and direct combined-surface file export.
    • Expanded support for anatomy labels beyond 255.
  • Documentation

    • Added API guidance, examples, architecture details, FAQs, licensing information, and usage requirements.
  • Bug Fixes

    • Updated tutorials and workflows to use the current processing and surface-export interfaces.

Add SegmentNVSegmentCTMRI, a VISTA3D-derived segmenter wrapping NVIDIA's
NV-Segment-CTMR model (345 classes across CT_BODY, MRI_BODY, MRI_BRAIN).
Weights are pulled from HuggingFace on first use; the OneWay Non-Commercial
license is logged at WARNING on first call.

- SegmentAnatomyBase gains labelmap_dtype (default np.uint8) and
  _finalize_other_group(id_range) so backends whose class indices exceed 255
  can emit uint16 labelmaps. NV-Segment-CTMR uses the model's published
  indices verbatim (up to 345), so it sets np.uint16.
- Register the backend in physiotwin4d.__init__, the CLI factory
  ("NVSegmentCTMR"), and a session-scoped conftest fixture.
- USDAnatomyTools: add render params for the new brain_parcellation group --
  shared grey-matter and CSF dicts plus overrides for white matter, WMH,
  ventricles, pallidum, brain stem, and cerebellar cortex. Several keys exist
  only to outrank shorter substring matches (e.g. "lateral_ventricle" vs the
  heart's "ventricle_left").
- Docs: API page for the new segmenter, plus architecture/FAQ/workflow updates.
- Experiments: add Lung-GatedCT_To_USD_NV variant of the DIRLAB pipeline
  (4DCT registration, model building, painting).
- Tutorials: add tutorial_04_lung_create_statistical_model.

Breaking API changes:
- ContourTools.save_combined_surface(surfaces, output_dir, prefix) ->
  save_combined_surfaces(surfaces, output_filename).
- WorkflowCreateStatisticalModel.run_workflow() -> process(), matching the
  other workflows. Default pca_number_of_components 15 -> 7.
- WorkflowConvertImageToVTK.ANATOMY_GROUPS -> anatomy_groups (instance
  attribute, not a constant).
- ContourTools.extract_contours() exposes smoothing_iterations and
  smoothing_scale, and no longer applies a hard-coded Taubin pass afterward.
- Module-level _extract_surface() folded into ContourTools.extract_surface().
Copilot AI review requested due to automatic review settings August 2, 2026 19:08
@coderabbitai

coderabbitai Bot commented Aug 2, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@aylward, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 22 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 97615b08-39fb-4651-83d7-fc0ddb763620

📥 Commits

Reviewing files that changed from the base of the PR and between 9483fc6 and 2373877.

📒 Files selected for processing (9)
  • docs/api/segmentation/nv_segment_ct_mri.rst
  • docs/cli_scripts/create_statistical_model.rst
  • experiments/Lung-GatedCT_To_USD_NV/0-register_dirlab_4dct.py
  • pyproject.toml
  • src/physiotwin4d/cli/create_statistical_model.py
  • src/physiotwin4d/segment_nv_segment_ct_mri.py
  • src/physiotwin4d/workflow_convert_image_to_vtk.py
  • src/physiotwin4d/workflow_create_statistical_model.py
  • tutorials/tutorial_04_lung_create_statistical_model.py

Walkthrough

Added the NV-Segment-CTMR backend for CT and MRI segmentation, including taxonomy and rendering support. Updated contour and workflow APIs, added DirLab processing scripts, aligned tutorials and documentation, and added backend tests.

Changes

NV-Segment-CTMR integration

Layer / File(s) Summary
Segmentation backend and public integration
src/physiotwin4d/segment_anatomy_base.py, src/physiotwin4d/segment_nv_segment_ct_mri.py, src/physiotwin4d/cli/*, src/physiotwin4d/__init__.py, tests/*, pyproject.toml
Added CT/MRI segmentation with NVIDIA model download, modality validation, taxonomy labels 1–345, CUDA inference, and uint16 labelmaps.
Brain taxonomy rendering
src/physiotwin4d/usd_anatomy_tools.py
Added brain parcellation rendering parameters and brain-tissue material overrides.
DirLab NV processing pipeline
experiments/Lung-GatedCT_To_USD_NV/*, experiments/Lung-GatedCT_To_USD/*
Added guarded DirLab registration, transformed contour generation, USD model creation, and painted USD export.
Surface and statistical-model API updates
src/physiotwin4d/contour_tools.py, src/physiotwin4d/workflow_convert_image_to_vtk.py, src/physiotwin4d/workflow_create_statistical_model.py, src/physiotwin4d/cli/*, tutorials/tutorial_02_*, tutorials/tutorial_04_*, docs/api/workflows.rst
Added surface extraction and explicit combined-surface output paths. Renamed workflow entry points and anatomy-group attributes.
Documentation and tutorial alignment
docs/api/segmentation/*, docs/architecture.rst, docs/faq.rst, docs/tutorials.rst, tutorials/tutorial_01_lung_gated_ct_to_usd.py
Documented NV-Segment-CTMR and updated examples, paths, and tutorial execution settings.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

Suggested reviewers: copilot

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant SegmentNVSegmentCTMRI
  participant HuggingFace
  participant VISTA3D
  Caller->>SegmentNVSegmentCTMRI: select modality and request segmentation
  SegmentNVSegmentCTMRI->>HuggingFace: download or reuse model bundle
  SegmentNVSegmentCTMRI->>VISTA3D: run CUDA inference
  VISTA3D-->>SegmentNVSegmentCTMRI: return labelmap
  SegmentNVSegmentCTMRI-->>Caller: return uint16 labelmap
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely identifies the primary change: adding the NV-Segment-CTMR segmentation backend.
Docstring Coverage ✅ Passed Docstring coverage is 93.75% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new NVIDIA NV-Segment-CTMR segmentation backend (SegmentNVSegmentCTMRI) to PhysioTwin4D, including taxonomy/group registration, CLI wiring, rendering defaults for a new brain_parcellation group, updated workflow/tutorial call sites for breaking API renames, and tests/docs/experiments to support the new backend.

Changes:

  • Introduces SegmentNVSegmentCTMRI (HuggingFace snapshot download + VISTA3D pipeline) and registers it across __init__, CLI factories, and test fixtures.
  • Extends segmentation + surface tooling APIs to support larger label index spaces (labelmap_dtype, wider “other” sweep) and renames save_combined_surfacesave_combined_surfaces.
  • Adds brain-parcellation USD render defaults and updates docs/tutorials/experiments accordingly.

Reviewed changes

Copilot reviewed 29 out of 29 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
tutorials/tutorial_04_lung_create_statistical_model.py New lung PCA statistical model tutorial (DirLab-based).
tutorials/tutorial_04_heart_create_statistical_model.py Updates workflow call to process().
tutorials/tutorial_02_lung_ct_to_vtk.py Updates combined-surface save API usage.
tutorials/tutorial_02_heart_ct_to_vtk.py Updates combined-surface save API usage.
tutorials/tutorial_01_lung_gated_ct_to_usd.py Adjusts DirLab path selection and playback FPS.
tests/test_segment_nv_segment_ct_mri.py Adds configuration + GPU/slow end-to-end tests for NV-Segment-CTMR.
tests/conftest.py Registers a session-scoped SegmentNVSegmentCTMRI fixture.
src/physiotwin4d/workflow_create_statistical_model.py Renames entrypoint to process(), adjusts defaults, uses ContourTools.extract_surface.
src/physiotwin4d/workflow_convert_image_to_vtk.py Replaces ANATOMY_GROUPS constant with instance anatomy_groups and updates validation/docs.
src/physiotwin4d/usd_anatomy_tools.py Adds brain_parcellation defaults + tissue overrides for USD materials.
src/physiotwin4d/segment_nv_segment_ct_mri.py New NV-Segment-CTMR backend implementation.
src/physiotwin4d/segment_anatomy_base.py Adds labelmap_dtype and widens _finalize_other_group() sweep; casts labelmap to configured dtype.
src/physiotwin4d/contour_tools.py Exposes contour smoothing params, adds extract_surface, renames combined-surface saver.
src/physiotwin4d/cli/create_statistical_model.py Updates workflow call to process().
src/physiotwin4d/cli/convert_image_to_vtk.py Updates anatomy-group choices var and combined-surface save path behavior.
src/physiotwin4d/cli/_method_factories.py Registers NVSegmentCTMR backend name and factory mapping.
src/physiotwin4d/init.py Exports SegmentNVSegmentCTMRI.
pyproject.toml Updates mypy module ignore list for NV bundle modules.
experiments/Lung-GatedCT_To_USD/1-make_dirlab_models.py Uses Path for results directory.
experiments/Lung-GatedCT_To_USD/2-paint_dirlab_models.py Uses Path for results directory.
experiments/Lung-GatedCT_To_USD_NV/0-register_dirlab_4dct.py New NV-backed DIRLAB registration experiment script.
experiments/Lung-GatedCT_To_USD_NV/1-make_dirlab_models.py New NV-backed DIRLAB model-building experiment script.
experiments/Lung-GatedCT_To_USD_NV/2-paint_dirlab_models.py New NV-backed USD painting experiment script.
docs/tutorials.rst Updates run_workflow()process() usage.
docs/faq.rst Adds NV-Segment-CTMR option + license caveat.
docs/architecture.rst Adds the new segmenter to architecture flow/docs.
docs/api/workflows.rst Updates combined-surface save API usage in docs.
docs/api/segmentation/nv_segment_ct_mri.rst New API documentation page for NV-Segment-CTMR.
docs/api/segmentation/index.rst Adds NV-Segment-CTMR to segmentation overview.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread tutorials/tutorial_04_lung_create_statistical_model.py Outdated
Comment thread tutorials/tutorial_04_lung_create_statistical_model.py
Comment thread tutorials/tutorial_04_lung_create_statistical_model.py Outdated
Comment thread tutorials/tutorial_01_lung_gated_ct_to_usd.py
Comment thread docs/api/segmentation/nv_segment_ct_mri.rst Outdated
Comment thread src/physiotwin4d/segment_nv_segment_ct_mri.py Outdated
Comment thread src/physiotwin4d/segment_nv_segment_ct_mri.py
Comment thread src/physiotwin4d/segment_nv_segment_ct_mri.py Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 9

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/physiotwin4d/contour_tools.py (1)

35-58: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Document the new smoothing parameters.

Lines 37-38 add public parameters, but the docstring does not describe them. Add smoothing_iterations and smoothing_scale to Args, including their effect and valid values.

As per coding guidelines, "**/*.{py,md,rst}: Update docstrings for every changed public method."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/physiotwin4d/contour_tools.py` around lines 35 - 58, Update the
extract_contours docstring’s Args section to document smoothing_iterations and
smoothing_scale, including how each controls contour smoothing and their valid
values. Keep the existing parameter descriptions unchanged.

Source: Coding guidelines

src/physiotwin4d/workflow_create_statistical_model.py (1)

48-57: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Add the constructor return annotation.

WorkflowCreateStatisticalModel.__init__ needs -> None for strict mypy-compatible type hints.

As per coding guidelines, "**/*.py: Use ... full type hints compatible with strict mypy."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/physiotwin4d/workflow_create_statistical_model.py` around lines 48 - 57,
Add a -> None return annotation to the WorkflowCreateStatisticalModel.__init__
method signature, preserving all existing parameters and defaults.

Source: Coding guidelines

🧹 Nitpick comments (6)
src/physiotwin4d/segment_nv_segment_ct_mri.py (1)

629-633: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Check CUDA availability before you build the pipeline.

The device is hard-coded to cuda:0. On a CPU-only host torch raises a low-level assertion that does not name the cause. Raise an explicit error instead.

Proposed change
+            if not torch.cuda.is_available():
+                raise RuntimeError(
+                    "NV-Segment-CTMR requires a CUDA device; none is available."
+                )
             pipeline = VISTA3DPipeline(model, device=torch.device("cuda:0"))
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/physiotwin4d/segment_nv_segment_ct_mri.py` around lines 629 - 633, In the
pipeline setup around VISTA3DPipeline, check torch.cuda availability before
constructing the pipeline with cuda:0; if CUDA is unavailable, raise a clear
explicit error, and preserve the existing GPU pipeline invocation when it is
available.
tests/test_segment_nv_segment_ct_mri.py (2)

184-189: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy lift

Compare the produced labelmap against a baseline.

The test writes the labelmap but never validates it against a stored reference. Use TestTools from src/physiotwin4d/test_tools.py with a baseline under tests/baselines/.

As per path instructions: "When a test produces an image or surface, compare it against a baseline using utilities such as TestTools from src/physiotwin4d/test_tools.py."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_segment_nv_segment_ct_mri.py` around lines 184 - 189, Update the
labelmap test around the output write in the segmentation flow to compare the
produced image against a stored baseline under tests/baselines/. Use the
existing TestTools utilities from src/physiotwin4d/test_tools.py, preserving the
current output generation while asserting the written labelmap matches its
corresponding baseline.

Source: Path instructions


143-164: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

State the image shape and axis order in the docstring.

The docstring does not describe the input volume. Add the shape and axis order, for example shape (X, Y, Z, T) = (..., ..., ..., 1), LPS world frame.

As per path instructions: "State image shape and axis order in every test docstring, such as shape (X, Y, Z, T) = (64, 64, 32, 1), LPS world frame."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_segment_nv_segment_ct_mri.py` around lines 143 - 164, Update the
docstring of test_segment_single_image to state the input image shape and axis
order, using the required “shape (X, Y, Z, T) = (..., ..., ..., 1), LPS world
frame” format and the test’s actual dimensions.

Source: Path instructions

src/physiotwin4d/segment_anatomy_base.py (1)

47-50: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider a narrower type for labelmap_dtype.

type accepts any class, so strict mypy cannot reject self.labelmap_dtype = str. type[np.integer] documents and enforces the intended contract.

Proposed change
-        self.labelmap_dtype: type = np.uint8
+        self.labelmap_dtype: type[np.integer] = np.uint8

Also applies to: 75-75

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/physiotwin4d/segment_anatomy_base.py` around lines 47 - 50, Update the
labelmap_dtype annotation in the segment anatomy base class documentation and
corresponding declaration to use type[np.integer] instead of unrestricted type.
Preserve the existing np.uint8 default and subclass overrides such as
SegmentNVSegmentCTMRI.
experiments/Lung-GatedCT_To_USD_NV/0-register_dirlab_4dct.py (1)

58-62: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Keep the f-string lines at or below 88 characters.

Lines 60, 258, 264, 270, and 276 exceed the limit. Build the file name in a local variable before the call.

As per coding guidelines: "keep lines at or below 88 characters".

Also applies to: 256-260

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@experiments/Lung-GatedCT_To_USD_NV/0-register_dirlab_4dct.py` around lines 58
- 62, In the relevant itk.imwrite calls in the registration script, including
the blocks around the mask and image outputs, assign each long f-string path to
a local filename variable first, then pass that variable to itk.imwrite. Keep
every resulting source line at or below 88 characters and preserve the existing
filenames and output behavior.

Source: Coding guidelines

experiments/Lung-GatedCT_To_USD_NV/1-make_dirlab_models.py (1)

26-28: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add type hints to both helper functions.

make_dirlab_models has no annotations. transform_contours_list has no return annotation, and its output_dir is annotated str while line 81 passes the Path created at line 23.

Proposed change
     def transform_contours_list(
-        contours: pv.PolyData, case_name: str, mask_name: str, output_dir: str
-    ):
+        contours: pv.PolyData, case_name: str, mask_name: str, output_dir: Path
+    ) -> list[pv.PolyData]:
     def make_dirlab_models(
-        output_dir,
-        label,
-        case_name,
-        base_timepoint,
-        all_labelmap_arr,
-        all_mask_ids,
-        con_tools,
-        seg,
-    ):
+        output_dir: Path,
+        label: str,
+        case_name: str,
+        base_timepoint: int,
+        all_labelmap_arr: np.ndarray,
+        all_mask_ids: dict[int, str],
+        con_tools: ContourTools,
+        seg: SegmentNVSegmentCTMRI,
+    ) -> None:

As per coding guidelines: "use full type hints compatible with strict mypy".

Also applies to: 47-56

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@experiments/Lung-GatedCT_To_USD_NV/1-make_dirlab_models.py` around lines 26 -
28, Update both helper functions, make_dirlab_models and
transform_contours_list, with complete strict-mypy-compatible annotations:
annotate make_dirlab_models’ parameters and return type, add
transform_contours_list’s return type, and change output_dir to match the
pathlib.Path value passed by the caller. Ensure all inferred input and output
types are explicitly represented without altering behavior.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@experiments/Lung-GatedCT_To_USD_NV/0-register_dirlab_4dct.py`:
- Around line 126-144: Update the fixed-image mask construction around
fixed_image_dynamic_anatomy_mask and fixed_image_static_anatomy_mask so every
registration mask is binary: threshold each source label array to
foreground/background before creating the ITK image, and combine static-anatomy
components as a binary union rather than adding label IDs. Apply the same
binarization and union logic to the corresponding moving-image mask block.
- Around line 39-48: Update the register_image function’s fixed_mask and
moving_mask annotations to Optional[itk.image], matching the existing None call
sites and moving_mask null check while following the project’s strict-mypy
typing convention.

In `@src/physiotwin4d/cli/create_statistical_model.py`:
- Line 155: Set the CLI parser’s pca_components default and help text to 7 so
the value passed by the create statistical model workflow remains consistent;
update the constructor documentation in
src/physiotwin4d/workflow_create_statistical_model.py lines 52-63 to document
the default as 7 while keeping its constructor default unchanged.

In `@src/physiotwin4d/segment_nv_segment_ct_mri.py`:
- Around line 556-566: Update the snapshot_download calls in the model
snapshot-loading flow, including the path around the _snapshot_dir assignment,
to pass an explicit pinned Hugging Face revision (commit SHA or audited tag) via
the supported revision parameter. Use the same pin for both affected call sites
and preserve the existing repository, cache, and allow_patterns behavior.
- Around line 604-621: Cache the loaded VISTA3DModel instance on the
segmentation class alongside _snapshot_dir, and update segmentation_method to
reuse that cached model instead of constructing VISTA3DModel and calling
torch.load on every invocation. Initialize or populate the cache once, then
preserve the existing inference behavior for subsequent segment calls.

In `@src/physiotwin4d/workflow_convert_image_to_vtk.py`:
- Line 23: Update the ContourTools.save_combined_surfaces call to access the
surfaces key with double quotes, changing result['surfaces'] to
result["surfaces"] while preserving the existing behavior.

In `@tutorials/tutorial_04_lung_create_statistical_model.py`:
- Around line 9-12: Update the module documentation’s “Data Required” section to
name the DirLab-4DCT dataset used by the tutorial’s data-loading code, and
replace the incorrect KCL-Heart-Model paths with the supported test-data
location if applicable. Keep the documentation aligned with the dataset path
referenced by the tutorial.
- Around line 83-87: Update the itk.imwrite call for sample_labelmap in the
labelmap generation flow to enable compressed persistence by passing
compression=True, while preserving the existing image and output path arguments.
- Around line 71-90: Update the fresh-output branch in the loop over
sample_image_files to assign sample_surface after saving the generated surfaces,
before sample_surfaces.append(sample_surface). Keep the existing pv.read path
for already-created surface files and ensure both branches initialize
sample_surface.

---

Outside diff comments:
In `@src/physiotwin4d/contour_tools.py`:
- Around line 35-58: Update the extract_contours docstring’s Args section to
document smoothing_iterations and smoothing_scale, including how each controls
contour smoothing and their valid values. Keep the existing parameter
descriptions unchanged.

In `@src/physiotwin4d/workflow_create_statistical_model.py`:
- Around line 48-57: Add a -> None return annotation to the
WorkflowCreateStatisticalModel.__init__ method signature, preserving all
existing parameters and defaults.

---

Nitpick comments:
In `@experiments/Lung-GatedCT_To_USD_NV/0-register_dirlab_4dct.py`:
- Around line 58-62: In the relevant itk.imwrite calls in the registration
script, including the blocks around the mask and image outputs, assign each long
f-string path to a local filename variable first, then pass that variable to
itk.imwrite. Keep every resulting source line at or below 88 characters and
preserve the existing filenames and output behavior.

In `@experiments/Lung-GatedCT_To_USD_NV/1-make_dirlab_models.py`:
- Around line 26-28: Update both helper functions, make_dirlab_models and
transform_contours_list, with complete strict-mypy-compatible annotations:
annotate make_dirlab_models’ parameters and return type, add
transform_contours_list’s return type, and change output_dir to match the
pathlib.Path value passed by the caller. Ensure all inferred input and output
types are explicitly represented without altering behavior.

In `@src/physiotwin4d/segment_anatomy_base.py`:
- Around line 47-50: Update the labelmap_dtype annotation in the segment anatomy
base class documentation and corresponding declaration to use type[np.integer]
instead of unrestricted type. Preserve the existing np.uint8 default and
subclass overrides such as SegmentNVSegmentCTMRI.

In `@src/physiotwin4d/segment_nv_segment_ct_mri.py`:
- Around line 629-633: In the pipeline setup around VISTA3DPipeline, check
torch.cuda availability before constructing the pipeline with cuda:0; if CUDA is
unavailable, raise a clear explicit error, and preserve the existing GPU
pipeline invocation when it is available.

In `@tests/test_segment_nv_segment_ct_mri.py`:
- Around line 184-189: Update the labelmap test around the output write in the
segmentation flow to compare the produced image against a stored baseline under
tests/baselines/. Use the existing TestTools utilities from
src/physiotwin4d/test_tools.py, preserving the current output generation while
asserting the written labelmap matches its corresponding baseline.
- Around line 143-164: Update the docstring of test_segment_single_image to
state the input image shape and axis order, using the required “shape (X, Y, Z,
T) = (..., ..., ..., 1), LPS world frame” format and the test’s actual
dimensions.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 26e974fa-8d61-4b75-a62a-e4d1b82dae01

📥 Commits

Reviewing files that changed from the base of the PR and between 66cd788 and 9483fc6.

📒 Files selected for processing (29)
  • docs/api/segmentation/index.rst
  • docs/api/segmentation/nv_segment_ct_mri.rst
  • docs/api/workflows.rst
  • docs/architecture.rst
  • docs/faq.rst
  • docs/tutorials.rst
  • experiments/Lung-GatedCT_To_USD/1-make_dirlab_models.py
  • experiments/Lung-GatedCT_To_USD/2-paint_dirlab_models.py
  • experiments/Lung-GatedCT_To_USD_NV/0-register_dirlab_4dct.py
  • experiments/Lung-GatedCT_To_USD_NV/1-make_dirlab_models.py
  • experiments/Lung-GatedCT_To_USD_NV/2-paint_dirlab_models.py
  • pyproject.toml
  • src/physiotwin4d/__init__.py
  • src/physiotwin4d/cli/_method_factories.py
  • src/physiotwin4d/cli/convert_image_to_vtk.py
  • src/physiotwin4d/cli/create_statistical_model.py
  • src/physiotwin4d/contour_tools.py
  • src/physiotwin4d/segment_anatomy_base.py
  • src/physiotwin4d/segment_nv_segment_ct_mri.py
  • src/physiotwin4d/usd_anatomy_tools.py
  • src/physiotwin4d/workflow_convert_image_to_vtk.py
  • src/physiotwin4d/workflow_create_statistical_model.py
  • tests/conftest.py
  • tests/test_segment_nv_segment_ct_mri.py
  • tutorials/tutorial_01_lung_gated_ct_to_usd.py
  • tutorials/tutorial_02_heart_ct_to_vtk.py
  • tutorials/tutorial_02_lung_ct_to_vtk.py
  • tutorials/tutorial_04_heart_create_statistical_model.py
  • tutorials/tutorial_04_lung_create_statistical_model.py

Comment thread experiments/Lung-GatedCT_To_USD_NV/0-register_dirlab_4dct.py
Comment thread experiments/Lung-GatedCT_To_USD_NV/0-register_dirlab_4dct.py Outdated
Comment thread src/physiotwin4d/cli/create_statistical_model.py
Comment thread src/physiotwin4d/segment_nv_segment_ct_mri.py
Comment thread src/physiotwin4d/segment_nv_segment_ct_mri.py Outdated
Comment thread src/physiotwin4d/workflow_convert_image_to_vtk.py Outdated
Comment thread tutorials/tutorial_04_lung_create_statistical_model.py Outdated
Comment thread tutorials/tutorial_04_lung_create_statistical_model.py Outdated
Comment thread tutorials/tutorial_04_lung_create_statistical_model.py Outdated
@codecov

codecov Bot commented Aug 2, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 52.00000% with 48 lines in your changes missing coverage. Please review.
✅ Project coverage is 35.61%. Comparing base (66cd788) to head (2373877).

Files with missing lines Patch % Lines
src/physiotwin4d/segment_nv_segment_ct_mri.py 57.97% 29 Missing ⚠️
src/physiotwin4d/contour_tools.py 27.27% 8 Missing ⚠️
.../physiotwin4d/workflow_create_statistical_model.py 20.00% 4 Missing ⚠️
src/physiotwin4d/cli/_method_factories.py 0.00% 2 Missing ⚠️
src/physiotwin4d/cli/convert_image_to_vtk.py 33.33% 2 Missing ⚠️
src/physiotwin4d/workflow_convert_image_to_vtk.py 33.33% 2 Missing ⚠️
src/physiotwin4d/cli/create_statistical_model.py 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #104      +/-   ##
==========================================
+ Coverage   35.40%   35.61%   +0.21%     
==========================================
  Files          63       64       +1     
  Lines        8203     8277      +74     
==========================================
+ Hits         2904     2948      +44     
- Misses       5299     5329      +30     
Flag Coverage Δ
integration-tests 35.42% <52.00%> (?)
unittests 35.61% <52.00%> (+0.21%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copilot AI review requested due to automatic review settings August 2, 2026 19:45

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 30 out of 30 changed files in this pull request and generated no new comments.

Suppressed comments (7)

src/physiotwin4d/segment_nv_segment_ct_mri.py:601

  • _ensure_pipeline mutates global sys.path by inserting the downloaded Hugging Face snapshot directory, but it never removes it. This can cause surprising import shadowing later in the process (especially since the snapshot contains top-level module names). Prefer adding the path only for the duration of the local imports, then removing it.
            # The bundle ships hugging_face_pipeline / vista3d_pipeline as
            # top-level modules inside the snapshot rather than as an installed
            # package, so the snapshot directory has to be importable.
            if snapshot_dir not in sys.path:
                sys.path.insert(0, snapshot_dir)

tutorials/tutorial_04_lung_create_statistical_model.py:13

  • The tutorial header claims a "Test data" path under data/test/DirLab-4DCT, but the repository does not ship a DirLab-4DCT test subset (only data/test/README.md and .gitignore). This is likely to confuse readers; suggest removing the test-data line or clarifying that there is no bundled test subset.
Full data: ``data/DirLab-4DCT/Case*T70.mha``
Test data: ``data/test/DirLab-4DCT/Case*T70.mha``
DirLab-4DCT is not auto-downloaded — see ``data/DirLab-4DCT/README.md``.

experiments/Lung-GatedCT_To_USD/1-make_dirlab_models.py:23

  • output_dir was changed to a Path, but the rest of this script builds paths via f"{output_dir}/...". On Windows this can produce mixed separators like "C:\...\results/Case...". Either keep output_dir as a str here, or switch the downstream path building to Path operations.
    output_dir = Path(__file__).parent / "results"

experiments/Lung-GatedCT_To_USD/2-paint_dirlab_models.py:20

  • output_dir was changed to a Path, but this script still uses f"{output_dir}/..." to build filenames. On Windows this can produce mixed separators (backslashes plus "/"), which can break downstream tools. Either keep output_dir as a str or convert the f-strings to Path joins.
    output_dir = Path(__file__).parent / "results"

experiments/Lung-GatedCT_To_USD_NV/1-make_dirlab_models.py:23

  • output_dir is a Path, but downstream filenames are constructed via f"{output_dir}/...". On Windows this can produce mixed separators like "C:\...\results/Case...". Either keep output_dir as a str or use Path / joins throughout.
    output_dir = Path(__file__).parent / "results"

experiments/Lung-GatedCT_To_USD_NV/2-paint_dirlab_models.py:20

  • output_dir is a Path, but the script constructs USD paths via f"{output_dir}/...". On Windows this can yield mixed separators (backslashes plus "/"), which can break consumers. Prefer Path joining (output_dir / filename) or keep output_dir as a str.
    output_dir = Path(__file__).parent / "results"

src/physiotwin4d/contour_tools.py:39

  • extract_contours() now exposes smoothing_iterations and smoothing_scale, but the docstring still documents only labelmap_image. Please document the new parameters so callers know what they control and their defaults.
    def extract_contours(
        labelmap_image: itk.image,
        smoothing_iterations: int = 10,
        smoothing_scale: float = 1.0,
    ) -> pv.PolyData:

@aylward
aylward merged commit 79bf471 into Project-MONAI:main Aug 2, 2026
12 checks passed
@aylward
aylward deleted the NVSegment branch August 2, 2026 22:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants