Skip to content

ENH: Remove unreliable netgen meshing; fix py launcher and CT auto-convert#86

Merged
aylward merged 3 commits into
Project-MONAI:mainfrom
aylward:tutorial02
Jul 13, 2026
Merged

ENH: Remove unreliable netgen meshing; fix py launcher and CT auto-convert#86
aylward merged 3 commits into
Project-MONAI:mainfrom
aylward:tutorial02

Conversation

@aylward

@aylward aylward commented Jul 13, 2026

Copy link
Copy Markdown
Collaborator

Remove netgen-based tetrahedral volume meshing from the image-to-VTK workflow. netgen crashed on degenerate triangles produced by PyVista's clean() defaults, and — once that was fixed — proved to hang indefinitely on self-intersecting/non-manifold surfaces from real segmented anatomy (e.g. lung airways) rather than failing fast like well-formed surfaces do. Extensive testing showed no practical preprocessing (image padding, fill_holes, morphological closing) reliably prevents this, and fill_holes() itself carries a documented segfault risk. Rather than paper over an unreliable feature, drop it: ContourTools.extract_mesh/save_meshes/save_combined_mesh are gone, WorkflowConvertImageToVTK.process() no longer takes mesh_target_reduction and its result dict drops the 'meshes' key (breaking API change), the CLI drops --mesh-target-reduction and VTU output, and netgen-mesher is removed from pyproject.toml. Docs and tests updated accordingly.

Fix the Windows py launcher resolving the wrong Python interpreter: a #!/usr/bin/env python shebang as line 1 makes py.exe search PATH for a bare python instead of using the active venv, breaking physiotwin4d imports. The shebang was leftover jupytext boilerplate with no functional purpose (not executable-bit set, bypassed by installed console-script entry points and by pytest's sys.executable-based invocation). Removed from all 64 affected files repo-wide.

DataDownloadTools.DownloadSlicerHeartCTData now also splits the downloaded Slicer-Heart-CT 4D sequence into per-frame slice_???.mha volumes via ConvertImage4DTo3D, skipping the split once those files exist. Callers (tests, experiments, tutorials) no longer need a separate conversion step.

Summary by CodeRabbit

  • New Features
    • Slicer-Heart-CT downloads automatically split 4D data into per-phase 3D volumes (slice_*.mha), and repeated runs reuse existing outputs and skip completed splitting.
    • Image-to-VTK conversion is now surface-only, with combined output and optional per-label surface extraction.
  • Documentation
    • Updated tutorials, CLI help, and documentation to reflect surface-only VTK outputs and the revised conversion configuration/results.
  • Chores
    • Removed an unused meshing dependency and aligned related packaging/docs.
  • Tests
    • Updated and extended coverage to validate surface outputs and label-surface isolation behavior.

…nvert

Remove netgen-based tetrahedral volume meshing from the image-to-VTK
workflow. netgen crashed on degenerate triangles produced by PyVista's
clean() defaults, and — once that was fixed — proved to hang
indefinitely on self-intersecting/non-manifold surfaces from real
segmented anatomy (e.g. lung airways) rather than failing fast like
well-formed surfaces do. Extensive testing showed no practical
preprocessing (image padding, fill_holes, morphological closing)
reliably prevents this, and fill_holes() itself carries a documented
segfault risk. Rather than paper over an unreliable feature, drop it:
ContourTools.extract_mesh/save_meshes/save_combined_mesh are gone,
WorkflowConvertImageToVTK.process() no longer takes
mesh_target_reduction and its result dict drops the 'meshes' key
(breaking API change), the CLI drops --mesh-target-reduction and VTU
output, and netgen-mesher is removed from pyproject.toml. Docs and
tests updated accordingly.

Fix the Windows `py` launcher resolving the wrong Python interpreter:
a `#!/usr/bin/env python` shebang as line 1 makes py.exe search PATH
for a bare `python` instead of using the active venv, breaking
`physiotwin4d` imports. The shebang was leftover jupytext boilerplate
with no functional purpose (not executable-bit set, bypassed by
installed console-script entry points and by pytest's
sys.executable-based invocation). Removed from all 64 affected files
repo-wide.

DataDownloadTools.DownloadSlicerHeartCTData now also splits the
downloaded Slicer-Heart-CT 4D sequence into per-frame slice_???.mha
volumes via ConvertImage4DTo3D, skipping the split once those files
exist. Callers (tests, experiments, tutorials) no longer need a
separate conversion step.
Copilot AI review requested due to automatic review settings July 13, 2026 00:27
@coderabbitai

coderabbitai Bot commented Jul 13, 2026

Copy link
Copy Markdown

Walkthrough

The PR removes volumetric mesh generation and Netgen metadata, centralizes 4D dataset splitting, updates tutorials and documentation for surface-only outputs, changes statistical-model input discovery, and removes Python shebangs across scripts and tests.

Changes

Surface conversion and data pipeline

Layer / File(s) Summary
Surface-only VTK conversion
src/physiotwin4d/{contour_tools.py,workflow_convert_image_to_vtk.py}, src/physiotwin4d/cli/convert_image_to_vtk.py, tutorials/tutorial_02_ct_to_vtk.py, tests/*
Removes mesh extraction, VTU outputs, and mesh reduction arguments; adds combined, group, and label VTP surface handling.
Centralized 4D dataset splitting
src/physiotwin4d/data_download_tools.py, experiments/*/0-download_and_convert_4d_to_3d.py, tests/conftest.py, data/Slicer-Heart-CT/README.md, docs/cli_scripts/download_data.rst
The download helper creates missing slice_???.mha files, and callers no longer perform separate conversion steps.
Downstream model and tutorial inputs
src/physiotwin4d/workflow_fit_statistical_model_to_patient.py, tutorials/tutorial_03_create_statistical_model.py, tests/*
Patient-model conversion uses surfaces, while statistical-model setup discovers VTK reference and sample meshes without a sample limit.
Dependency and documentation alignment
README.md, pyproject.toml, statistics.md, docs/*
Removes Netgen dependency metadata and updates workflow, CLI, tutorial, dataset, and license descriptions.
Python shebang removal
.github/scripts/*, src/*, experiments/*, tests/*, utils/*, data/*
Removes leading Python interpreter directives without changing the remaining reported logic.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant CLI as convert_image_to_vtk
  participant Workflow as WorkflowConvertImageToVTK
  participant ContourTools
  CLI->>Workflow: process image with output mode
  Workflow->>ContourTools: extract anatomy and label surfaces
  ContourTools-->>CLI: save VTP surfaces
Loading
sequenceDiagram
  participant Downloader as DownloadSlicerHeartCTData
  participant Converter as ConvertImage4DTo3D
  participant Dataset as Slicer-Heart-CT
  Downloader->>Dataset: download or reuse .seq.nrrd
  Downloader->>Converter: split missing frames
  Converter-->>Dataset: write slice_???.mha files
Loading

Possibly related PRs

Suggested reviewers: copilot

🚥 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 captures the three main changes: removing netgen meshing, fixing Windows py launcher issues by dropping shebangs, and auto-converting CT data.
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

This PR removes the netgen-based tetrahedral volume meshing path from the image-to-VTK workflow/CLI (favoring surface-only outputs), eliminates #!/usr/bin/env python shebangs that interfere with Windows py.exe venv resolution, and updates Slicer-Heart-CT downloading to automatically split the 4D sequence into per-phase slice_???.mha volumes (with corresponding updates to tests/docs/tutorials).

Changes:

  • Removed netgen tetrahedral meshing APIs (ContourTools.extract_mesh/save_meshes/save_combined_mesh) and dropped mesh-related workflow/CLI parameters and outputs.
  • Removed #!/usr/bin/env python shebangs repo-wide to prevent the Windows launcher from selecting the wrong interpreter.
  • Updated DataDownloadTools.DownloadSlicerHeartCTData to split .seq.nrrd into slice_???.mha frames automatically and updated callers/docs accordingly.

Reviewed changes

Copilot reviewed 80 out of 80 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
utils/setup_feature_worktree.py Removed shebang to avoid Windows py.exe interpreter mis-resolution.
utils/generate_api_map.py Removed shebang to avoid Windows py.exe interpreter mis-resolution.
utils/ai_agent_github_reviews.py Removed shebang to avoid Windows py.exe interpreter mis-resolution.
tutorials/tutorial_03_create_statistical_model.py Updated KCL-Heart-Model inputs to .vtk layout and reference naming.
tutorials/tutorial_02_ct_to_vtk.py Updated tutorial to surface-only output (no VTU mesh).
tests/test_vtk_to_usd_library.py Removed shebang to avoid Windows py.exe interpreter mis-resolution.
tests/test_tutorials.py Updated tutorial expectations (surface-only output).
tests/test_transform_tools.py Removed shebang to avoid Windows py.exe interpreter mis-resolution.
tests/test_segment_heart_simpleware.py Removed shebang to avoid Windows py.exe interpreter mis-resolution.
tests/test_segment_heart_simpleware_trimmed_branches.py Removed shebang to avoid Windows py.exe interpreter mis-resolution.
tests/test_segment_chest_total_segmentator.py Removed shebang to avoid Windows py.exe interpreter mis-resolution.
tests/test_register_time_series_images.py Removed shebang to avoid Windows py.exe interpreter mis-resolution.
tests/test_register_images_icon.py Removed shebang to avoid Windows py.exe interpreter mis-resolution.
tests/test_register_images_greedy.py Removed shebang to avoid Windows py.exe interpreter mis-resolution.
tests/test_register_images_ants.py Removed shebang to avoid Windows py.exe interpreter mis-resolution.
tests/test_labelmap_tools.py Removed shebang to avoid Windows py.exe interpreter mis-resolution.
tests/test_image_tools.py Removed shebang to avoid Windows py.exe interpreter mis-resolution.
tests/test_experiments.py Removed shebang to avoid Windows py.exe interpreter mis-resolution.
tests/test_download_heart_data.py Removed shebang to avoid Windows py.exe interpreter mis-resolution.
tests/test_convert_vtk_to_usd.py Removed shebang to avoid Windows py.exe interpreter mis-resolution.
tests/test_convert_image_4d_to_3d.py Removed shebang to avoid Windows py.exe interpreter mis-resolution.
tests/test_contour_tools.py Removed shebang to avoid Windows py.exe interpreter mis-resolution.
tests/conftest.py Updated fixtures to rely on auto-splitting Slicer-Heart-CT into slice_???.mha.
statistics.md Removed netgen from dependency summary list.
src/physiotwin4d/workflow_convert_image_to_vtk.py Dropped volume mesh extraction/output; surface-only workflow API.
src/physiotwin4d/data_download_tools.py Auto-split Slicer-Heart-CT into per-phase .mha frames on download.
src/physiotwin4d/contour_tools.py Removed netgen meshing and VTU save helpers; surface utilities remain.
src/physiotwin4d/cli/visualize_pca_modes.py Removed shebang to avoid Windows py.exe interpreter mis-resolution.
src/physiotwin4d/cli/reconstruct_highres_4d_ct.py Removed shebang to avoid Windows py.exe interpreter mis-resolution.
src/physiotwin4d/cli/fit_statistical_model_to_patient.py Removed shebang to avoid Windows py.exe interpreter mis-resolution.
src/physiotwin4d/cli/download_data.py Removed shebang to avoid Windows py.exe interpreter mis-resolution.
src/physiotwin4d/cli/create_statistical_model.py Removed shebang to avoid Windows py.exe interpreter mis-resolution.
src/physiotwin4d/cli/convert_vtk_to_usd.py Removed shebang to avoid Windows py.exe interpreter mis-resolution.
src/physiotwin4d/cli/convert_image_to_vtk.py Updated CLI help/behavior for surface-only export; removed mesh args/outputs.
src/physiotwin4d/cli/convert_image_to_usd.py Removed shebang to avoid Windows py.exe interpreter mis-resolution.
src/physiotwin4d/cli/convert_image_4d_to_3d.py Removed shebang to avoid Windows py.exe interpreter mis-resolution.
README.md Removed netgen mention and updated optional-license note accordingly.
pyproject.toml Removed netgen-mesher dependency and mypy ignore entries.
experiments/Reconstruct4DCT/reconstruct_4d_ct.py Removed shebang to avoid Windows py.exe interpreter mis-resolution.
experiments/Reconstruct4DCT/reconstruct_4d_ct_class.py Removed shebang to avoid Windows py.exe interpreter mis-resolution.
experiments/Lung-VesselsAirways/0-GenData.py Removed shebang to avoid Windows py.exe interpreter mis-resolution.
experiments/Lung-GatedCT_To_USD/Experiment_SubSurfaceScatter.py Removed shebang to avoid Windows py.exe interpreter mis-resolution.
experiments/Lung-GatedCT_To_USD/Experiment_SegReg.py Removed shebang to avoid Windows py.exe interpreter mis-resolution.
experiments/Lung-GatedCT_To_USD/Experiment_CombineModels.py Removed shebang to avoid Windows py.exe interpreter mis-resolution.
experiments/Lung-GatedCT_To_USD/Experiment_ArrangeOnStage.py Removed shebang to avoid Windows py.exe interpreter mis-resolution.
experiments/Lung-GatedCT_To_USD/2-paint_dirlab_models.py Removed shebang to avoid Windows py.exe interpreter mis-resolution.
experiments/Lung-GatedCT_To_USD/1-make_dirlab_models.py Removed shebang to avoid Windows py.exe interpreter mis-resolution.
experiments/Lung-GatedCT_To_USD/0-register_dirlab_4dct.py Removed shebang to avoid Windows py.exe interpreter mis-resolution.
experiments/Heart-VTKSeries_To_USD/1-heart_vtkseries_to_usd.py Removed shebang to avoid Windows py.exe interpreter mis-resolution.
experiments/Heart-VTKSeries_To_USD/0-download_and_convert_4d_to_3d.py Simplified to rely on DownloadSlicerHeartCTData auto-splitting.
experiments/Heart-Statistical_Model_To_Patient/heart_model_to_patient.py Removed shebang to avoid Windows py.exe interpreter mis-resolution.
experiments/Heart-Statistical_Model_To_Patient/heart_model_to_patient-CHOPValve.py Removed shebang to avoid Windows py.exe interpreter mis-resolution.
experiments/Heart-Statistical_Model_To_Patient/heart_model_to_model_registration_pca.py Removed shebang to avoid Windows py.exe interpreter mis-resolution.
experiments/Heart-Statistical_Model_To_Patient/heart_model_to_model_icp_itk.py Removed shebang to avoid Windows py.exe interpreter mis-resolution.
experiments/Heart-Simpleware_Segmentation/simpleware_heart_segmentation.py Removed shebang to avoid Windows py.exe interpreter mis-resolution.
experiments/Heart-GatedCT_To_USD/4-merge_dynamic_and_static_usd.py Removed shebang to avoid Windows py.exe interpreter mis-resolution.
experiments/Heart-GatedCT_To_USD/3-transform_dynamic_and_static_contours.py Removed shebang to avoid Windows py.exe interpreter mis-resolution.
experiments/Heart-GatedCT_To_USD/2-generate_segmentation.py Removed shebang to avoid Windows py.exe interpreter mis-resolution.
experiments/Heart-GatedCT_To_USD/1-register_images.py Removed shebang to avoid Windows py.exe interpreter mis-resolution.
experiments/Heart-GatedCT_To_USD/0-download_and_convert_4d_to_3d.py Simplified to rely on DownloadSlicerHeartCTData auto-splitting.
experiments/Heart-Create_Statistical_Model/5-compute_pca_model.py Removed shebang to avoid Windows py.exe interpreter mis-resolution.
experiments/Heart-Create_Statistical_Model/4-surfaces_aligned_correspond_to_pca_inputs.py Removed shebang to avoid Windows py.exe interpreter mis-resolution.
experiments/Heart-Create_Statistical_Model/3-registration_based_correspondence.py Removed shebang to avoid Windows py.exe interpreter mis-resolution.
experiments/Heart-Create_Statistical_Model/2-input_surfaces_to_surfaces_aligned.py Removed shebang to avoid Windows py.exe interpreter mis-resolution.
experiments/Heart-Create_Statistical_Model/1-input_meshes_to_input_surfaces.py Removed shebang to avoid Windows py.exe interpreter mis-resolution.
experiments/DisplacementField_To_USD/displacement_field_to_usd.py Removed shebang to avoid Windows py.exe interpreter mis-resolution.
experiments/Convert_VTK_To_USD/convert_vtk_to_usd_using_class.py Removed shebang to avoid Windows py.exe interpreter mis-resolution.
experiments/Convert_VTK_To_USD/convert_chop_tpv25_valve_to_usd.py Removed shebang to avoid Windows py.exe interpreter mis-resolution.
experiments/Convert_VTK_To_USD/convert_chop_heart_vtk_to_usd.py Removed shebang to avoid Windows py.exe interpreter mis-resolution.
experiments/Convert_VTK_To_USD/convert_chop_alterra_valve_to_usd.py Removed shebang to avoid Windows py.exe interpreter mis-resolution.
experiments/Colormap-VTK_To_USD/colormap_vtk_to_usd.py Removed shebang to avoid Windows py.exe interpreter mis-resolution.
docs/tutorials.rst Updated tutorial narrative/examples for surface-only workflow.
docs/developer/architecture.rst Updated workflow description to surface-only outputs.
docs/cli_scripts/overview.rst Updated CLI description to surface-only outputs.
docs/cli_scripts/download_data.rst Documented auto-splitting Slicer-Heart-CT into slice_???.mha.
docs/architecture.rst Updated architecture docs for surface-only image-to-VTK workflow.
docs/api/workflows.rst Updated workflow listing/description for surface-only export.
data/Slicer-Heart-CT/README.md Documented auto-splitting downloaded .seq.nrrd into slices.
data/DirLab-4DCT/Convert4DCTToMHD.py Removed shebang to avoid Windows py.exe interpreter mis-resolution.
.github/scripts/build_dashboard.py Removed shebang to avoid Windows py.exe interpreter mis-resolution.

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

Comment thread src/physiotwin4d/data_download_tools.py
Comment thread tutorials/tutorial_03_create_statistical_model.py

@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: 3

Caution

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

⚠️ Outside diff range comments (1)
tests/conftest.py (1)

453-462: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Docstring omits image shape/axis order.

Path instructions for tests/**/*.py require every test docstring to state image shape and axis order (e.g. LPS world frame). The updated docstring only says "return time points" without noting these are per-frame 3D ITK volumes in LPS world space.

As per path instructions, "State image shape and axis order in every test docstring, for example 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/conftest.py` around lines 453 - 462, Update the test_images docstring
to state that the returned time points are per-frame 3D ITK volumes and
explicitly identify their axis order/world frame as LPS, while preserving the
existing resampling description.

Source: Path instructions

🧹 Nitpick comments (1)
docs/cli_scripts/overview.rst (1)

56-57: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Stale "meshes/" entry in Output Organization example.

Line 57 was updated to describe surface-only output, but the "Output Organization" example directory tree at line 116 still lists a meshes/ folder with # VTK mesh files, which is now inconsistent with the removal of volumetric mesh generation from this workflow.

📝 Suggested fix
    output_directory/
    ├── intermediate/          # Segmentations, registrations
-   └── meshes/               # VTK mesh files
+   ├── surfaces/             # VTK surface (VTP) files
    └── usd/                  # Final USD files for Omniverse

Also applies to: 112-117

🤖 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 `@docs/cli_scripts/overview.rst` around lines 56 - 57, Update the Output
Organization example associated with physiotwin4d-convert-image-to-vtk to remove
the stale meshes/ directory and its VTK mesh files comment, keeping the
directory tree consistent with surface-only anatomy-group VTK output.
🤖 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 `@data/Slicer-Heart-CT/README.md`:
- Around line 20-33: Update the directory-structure fenced code block in the
README to include the text language identifier, preserving its existing contents
and formatting.

In `@src/physiotwin4d/data_download_tools.py`:
- Around line 94-103: Make the Slicer-Heart conversion in the surrounding
download flow atomic: replace the single-file existence check and direct save
into data_dir with a temporary-directory conversion using ConvertImage4DTo3D,
then atomically move or rename the completed output into place only after
save_3d_images succeeds. Ensure failed or interrupted conversions leave no
partial slice_???.mha files and concurrent callers cannot treat an incomplete
split as valid, following the existing download/extract helper pattern.

In `@tutorials/tutorial_03_create_statistical_model.py`:
- Around line 73-76: Update the fallback assignment in the sample-file discovery
flow to exclude the reference mesh file before populating sample_files, while
preserving the existing input_meshes/*.vtk behavior. Use the reference mesh
filename already established by the tutorial’s PCA setup so it cannot be
included as both alignment target and training sample.

---

Outside diff comments:
In `@tests/conftest.py`:
- Around line 453-462: Update the test_images docstring to state that the
returned time points are per-frame 3D ITK volumes and explicitly identify their
axis order/world frame as LPS, while preserving the existing resampling
description.

---

Nitpick comments:
In `@docs/cli_scripts/overview.rst`:
- Around line 56-57: Update the Output Organization example associated with
physiotwin4d-convert-image-to-vtk to remove the stale meshes/ directory and its
VTK mesh files comment, keeping the directory tree consistent with surface-only
anatomy-group VTK output.
🪄 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

Run ID: 86ceb226-5a02-4a10-81eb-25e73ee2e419

📥 Commits

Reviewing files that changed from the base of the PR and between db3b4b5 and 67543c5.

📒 Files selected for processing (80)
  • .github/scripts/build_dashboard.py
  • README.md
  • data/DirLab-4DCT/Convert4DCTToMHD.py
  • data/Slicer-Heart-CT/README.md
  • docs/api/workflows.rst
  • docs/architecture.rst
  • docs/cli_scripts/download_data.rst
  • docs/cli_scripts/overview.rst
  • docs/developer/architecture.rst
  • docs/tutorials.rst
  • experiments/Colormap-VTK_To_USD/colormap_vtk_to_usd.py
  • experiments/Convert_VTK_To_USD/convert_chop_alterra_valve_to_usd.py
  • experiments/Convert_VTK_To_USD/convert_chop_heart_vtk_to_usd.py
  • experiments/Convert_VTK_To_USD/convert_chop_tpv25_valve_to_usd.py
  • experiments/Convert_VTK_To_USD/convert_vtk_to_usd_using_class.py
  • experiments/DisplacementField_To_USD/displacement_field_to_usd.py
  • experiments/Heart-Create_Statistical_Model/1-input_meshes_to_input_surfaces.py
  • experiments/Heart-Create_Statistical_Model/2-input_surfaces_to_surfaces_aligned.py
  • experiments/Heart-Create_Statistical_Model/3-registration_based_correspondence.py
  • experiments/Heart-Create_Statistical_Model/4-surfaces_aligned_correspond_to_pca_inputs.py
  • experiments/Heart-Create_Statistical_Model/5-compute_pca_model.py
  • experiments/Heart-GatedCT_To_USD/0-download_and_convert_4d_to_3d.py
  • experiments/Heart-GatedCT_To_USD/1-register_images.py
  • experiments/Heart-GatedCT_To_USD/2-generate_segmentation.py
  • experiments/Heart-GatedCT_To_USD/3-transform_dynamic_and_static_contours.py
  • experiments/Heart-GatedCT_To_USD/4-merge_dynamic_and_static_usd.py
  • experiments/Heart-Simpleware_Segmentation/simpleware_heart_segmentation.py
  • experiments/Heart-Statistical_Model_To_Patient/heart_model_to_model_icp_itk.py
  • experiments/Heart-Statistical_Model_To_Patient/heart_model_to_model_registration_pca.py
  • experiments/Heart-Statistical_Model_To_Patient/heart_model_to_patient-CHOPValve.py
  • experiments/Heart-Statistical_Model_To_Patient/heart_model_to_patient.py
  • experiments/Heart-VTKSeries_To_USD/0-download_and_convert_4d_to_3d.py
  • experiments/Heart-VTKSeries_To_USD/1-heart_vtkseries_to_usd.py
  • experiments/Lung-GatedCT_To_USD/0-register_dirlab_4dct.py
  • 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/Experiment_ArrangeOnStage.py
  • experiments/Lung-GatedCT_To_USD/Experiment_CombineModels.py
  • experiments/Lung-GatedCT_To_USD/Experiment_SegReg.py
  • experiments/Lung-GatedCT_To_USD/Experiment_SubSurfaceScatter.py
  • experiments/Lung-VesselsAirways/0-GenData.py
  • experiments/Reconstruct4DCT/reconstruct_4d_ct.py
  • experiments/Reconstruct4DCT/reconstruct_4d_ct_class.py
  • pyproject.toml
  • src/physiotwin4d/cli/convert_image_4d_to_3d.py
  • src/physiotwin4d/cli/convert_image_to_usd.py
  • src/physiotwin4d/cli/convert_image_to_vtk.py
  • src/physiotwin4d/cli/convert_vtk_to_usd.py
  • src/physiotwin4d/cli/create_statistical_model.py
  • src/physiotwin4d/cli/download_data.py
  • src/physiotwin4d/cli/fit_statistical_model_to_patient.py
  • src/physiotwin4d/cli/reconstruct_highres_4d_ct.py
  • src/physiotwin4d/cli/visualize_pca_modes.py
  • src/physiotwin4d/contour_tools.py
  • src/physiotwin4d/data_download_tools.py
  • src/physiotwin4d/workflow_convert_image_to_vtk.py
  • statistics.md
  • tests/conftest.py
  • tests/test_contour_tools.py
  • tests/test_convert_image_4d_to_3d.py
  • tests/test_convert_vtk_to_usd.py
  • tests/test_download_heart_data.py
  • tests/test_experiments.py
  • tests/test_image_tools.py
  • tests/test_labelmap_tools.py
  • tests/test_register_images_ants.py
  • tests/test_register_images_greedy.py
  • tests/test_register_images_icon.py
  • tests/test_register_time_series_images.py
  • tests/test_segment_chest_total_segmentator.py
  • tests/test_segment_heart_simpleware.py
  • tests/test_segment_heart_simpleware_trimmed_branches.py
  • tests/test_transform_tools.py
  • tests/test_tutorials.py
  • tests/test_vtk_to_usd_library.py
  • tutorials/tutorial_02_ct_to_vtk.py
  • tutorials/tutorial_03_create_statistical_model.py
  • utils/ai_agent_github_reviews.py
  • utils/generate_api_map.py
  • utils/setup_feature_worktree.py
💤 Files with no reviewable changes (62)
  • experiments/Lung-GatedCT_To_USD/Experiment_ArrangeOnStage.py
  • tests/test_image_tools.py
  • tests/test_experiments.py
  • experiments/Heart-Simpleware_Segmentation/simpleware_heart_segmentation.py
  • experiments/Heart-GatedCT_To_USD/2-generate_segmentation.py
  • experiments/Lung-GatedCT_To_USD/0-register_dirlab_4dct.py
  • experiments/Heart-Create_Statistical_Model/2-input_surfaces_to_surfaces_aligned.py
  • experiments/Lung-VesselsAirways/0-GenData.py
  • experiments/Lung-GatedCT_To_USD/Experiment_SubSurfaceScatter.py
  • utils/setup_feature_worktree.py
  • src/physiotwin4d/cli/create_statistical_model.py
  • experiments/Heart-Statistical_Model_To_Patient/heart_model_to_patient-CHOPValve.py
  • experiments/DisplacementField_To_USD/displacement_field_to_usd.py
  • tests/test_vtk_to_usd_library.py
  • experiments/Heart-Statistical_Model_To_Patient/heart_model_to_model_registration_pca.py
  • experiments/Lung-GatedCT_To_USD/Experiment_SegReg.py
  • experiments/Reconstruct4DCT/reconstruct_4d_ct_class.py
  • src/physiotwin4d/cli/reconstruct_highres_4d_ct.py
  • tests/test_segment_chest_total_segmentator.py
  • experiments/Convert_VTK_To_USD/convert_chop_heart_vtk_to_usd.py
  • src/physiotwin4d/cli/convert_vtk_to_usd.py
  • experiments/Heart-GatedCT_To_USD/3-transform_dynamic_and_static_contours.py
  • experiments/Lung-GatedCT_To_USD/2-paint_dirlab_models.py
  • experiments/Heart-GatedCT_To_USD/1-register_images.py
  • experiments/Heart-VTKSeries_To_USD/1-heart_vtkseries_to_usd.py
  • src/physiotwin4d/cli/convert_image_4d_to_3d.py
  • utils/generate_api_map.py
  • experiments/Heart-Create_Statistical_Model/3-registration_based_correspondence.py
  • experiments/Heart-Create_Statistical_Model/1-input_meshes_to_input_surfaces.py
  • src/physiotwin4d/cli/fit_statistical_model_to_patient.py
  • src/physiotwin4d/cli/visualize_pca_modes.py
  • tests/test_register_images_ants.py
  • tests/test_register_images_greedy.py
  • experiments/Convert_VTK_To_USD/convert_vtk_to_usd_using_class.py
  • tests/test_convert_image_4d_to_3d.py
  • experiments/Convert_VTK_To_USD/convert_chop_tpv25_valve_to_usd.py
  • tests/test_register_time_series_images.py
  • tests/test_download_heart_data.py
  • tests/test_register_images_icon.py
  • experiments/Heart-Create_Statistical_Model/5-compute_pca_model.py
  • tests/test_transform_tools.py
  • tests/test_convert_vtk_to_usd.py
  • experiments/Convert_VTK_To_USD/convert_chop_alterra_valve_to_usd.py
  • experiments/Lung-GatedCT_To_USD/Experiment_CombineModels.py
  • tests/test_contour_tools.py
  • experiments/Lung-GatedCT_To_USD/1-make_dirlab_models.py
  • experiments/Colormap-VTK_To_USD/colormap_vtk_to_usd.py
  • tests/test_segment_heart_simpleware.py
  • tests/test_tutorials.py
  • tests/test_labelmap_tools.py
  • experiments/Heart-GatedCT_To_USD/4-merge_dynamic_and_static_usd.py
  • data/DirLab-4DCT/Convert4DCTToMHD.py
  • experiments/Heart-Statistical_Model_To_Patient/heart_model_to_patient.py
  • src/physiotwin4d/cli/download_data.py
  • experiments/Reconstruct4DCT/reconstruct_4d_ct.py
  • utils/ai_agent_github_reviews.py
  • experiments/Heart-Statistical_Model_To_Patient/heart_model_to_model_icp_itk.py
  • tests/test_segment_heart_simpleware_trimmed_branches.py
  • experiments/Heart-Create_Statistical_Model/4-surfaces_aligned_correspond_to_pca_inputs.py
  • .github/scripts/build_dashboard.py
  • src/physiotwin4d/cli/convert_image_to_usd.py
  • pyproject.toml

Comment thread data/Slicer-Heart-CT/README.md
Comment thread src/physiotwin4d/data_download_tools.py
Comment thread tutorials/tutorial_03_create_statistical_model.py
Copilot AI review requested due to automatic review settings July 13, 2026 03:26

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 83 out of 83 changed files in this pull request and generated 4 comments.

Comment thread src/physiotwin4d/workflow_convert_image_to_vtk.py Outdated
Comment thread src/physiotwin4d/data_download_tools.py
Comment thread tutorials/tutorial_03_create_statistical_model.py
Comment thread tests/test_workflow_convert_image_to_vtk.py

@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: 1

Caution

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

⚠️ Outside diff range comments (1)
docs/tutorials.rst (1)

213-226: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Code example doesn't match the described extract_label_surfaces behavior.

The snippet omits extract_label_surfaces=SAVE_LABEL_SURFACES, but the prose right below states that enabling label surfaces "passes extract_label_surfaces=True" — and the actual tutorial script does pass it. As written, copying this snippet verbatim won't reproduce the documented behavior.

📝 Suggested fix
       result = workflow.process(
           input_image=ct_image,
           surface_target_reduction=0.5,
+          extract_label_surfaces=SAVE_LABEL_SURFACES,
       )
🤖 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 `@docs/tutorials.rst` around lines 213 - 226, Update the `workflow.process`
example in `docs/tutorials.rst` to pass
`extract_label_surfaces=SAVE_LABEL_SURFACES`, matching the documented behavior
and tutorial script while preserving the existing arguments.
🧹 Nitpick comments (1)
src/physiotwin4d/workflow_convert_image_to_vtk.py (1)

190-209: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Avoid re-converting the full labelmap array on every label.

_extract_label_surface calls itk.GetArrayFromImage(labelmap_image) internally, and process() invokes it once per (group, label_id) pair against the same seg_result["labelmap"] object. For taxonomies with many labels across groups, this repeats a full-volume ITK→NumPy copy on every label instead of once, adding avoidable I/O-bound overhead when extract_label_surfaces=True.

♻️ Cache the labelmap array once and reuse it across labels
     def _extract_label_surface(
-        self, labelmap_image: Any, label_id: int
+        self, labelmap_image: Any, label_id: int, labelmap_arr: Optional[Any] = None
     ) -> Optional[pv.PolyData]:
         """Extract a smoothed triangulated surface for one individual label.
         ...
         """
-        arr = itk.GetArrayFromImage(labelmap_image)
+        arr = labelmap_arr if labelmap_arr is not None else itk.GetArrayFromImage(
+            labelmap_image
+        )
         label_mask_arr = (arr == label_id).astype(np.uint8)
         if int(label_mask_arr.sum()) == 0:
             return None
         label_mask = itk.GetImageFromArray(label_mask_arr)
         label_mask.CopyInformation(labelmap_image)
         return self._contour_tools.extract_contours(label_mask)
+        labelmap_arr_cache: Optional[Any] = None
         for group in groups_to_process:
             ...
             if extract_label_surfaces:
                 self.log_info("  Extracting label surfaces for: %s", group)
+                if labelmap_arr_cache is None:
+                    labelmap_arr_cache = itk.GetArrayFromImage(seg_result["labelmap"])
                 for label_id, label_name in zip(label_ids, label_names, strict=True):
                     label_surface = self._extract_label_surface(
-                        seg_result["labelmap"], label_id
+                        seg_result["labelmap"], label_id, labelmap_arr_cache
                     )

Also applies to: 310-325

🤖 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_convert_image_to_vtk.py` around lines 190 - 209,
Cache the NumPy conversion of seg_result["labelmap"] once in process() and pass
or reuse that array when handling each (group, label_id) pair. Update
_extract_label_surface to consume the cached array while preserving mask
creation, metadata copying, empty-label handling, and contour extraction
behavior.
🤖 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 `@tests/test_workflow_convert_image_to_vtk.py`:
- Around line 37-58: Update the test_extract_label_surface_isolates_single_label
docstring to state that its input is synthetic and document the (10, 10, 10)
image shape and the array’s axis order. Preserve the existing
regression-behavior description and test logic.

---

Outside diff comments:
In `@docs/tutorials.rst`:
- Around line 213-226: Update the `workflow.process` example in
`docs/tutorials.rst` to pass `extract_label_surfaces=SAVE_LABEL_SURFACES`,
matching the documented behavior and tutorial script while preserving the
existing arguments.

---

Nitpick comments:
In `@src/physiotwin4d/workflow_convert_image_to_vtk.py`:
- Around line 190-209: Cache the NumPy conversion of seg_result["labelmap"] once
in process() and pass or reuse that array when handling each (group, label_id)
pair. Update _extract_label_surface to consume the cached array while preserving
mask creation, metadata copying, empty-label handling, and contour extraction
behavior.
🪄 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

Run ID: c00f20b2-86ea-4d30-80cc-eda0c3bc3612

📥 Commits

Reviewing files that changed from the base of the PR and between 67543c5 and 2bbf58f.

📒 Files selected for processing (10)
  • data/Slicer-Heart-CT/README.md
  • docs/tutorials.rst
  • src/physiotwin4d/cli/convert_image_to_vtk.py
  • src/physiotwin4d/data_download_tools.py
  • src/physiotwin4d/workflow_convert_image_to_vtk.py
  • src/physiotwin4d/workflow_fit_statistical_model_to_patient.py
  • tests/test_workflow_convert_image_to_vtk.py
  • tests/test_workflow_fit_statistical_model_to_patient.py
  • tutorials/tutorial_02_ct_to_vtk.py
  • tutorials/tutorial_03_create_statistical_model.py
🚧 Files skipped from review as they are similar to previous changes (3)
  • data/Slicer-Heart-CT/README.md
  • src/physiotwin4d/data_download_tools.py
  • tutorials/tutorial_03_create_statistical_model.py

Comment thread tests/test_workflow_convert_image_to_vtk.py
Copilot AI review requested due to automatic review settings July 13, 2026 08:24

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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@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: 1

🤖 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 `@tests/test_tutorials.py`:
- Around line 166-169: Update the tutorial 04 dataset guard in the relevant test
setup to require both kcl_dir / "average_mesh.vtk" and kcl_dir / "pca_mean.vtu"
before running. Preserve the existing pytest.skip message and behavior when
either file is missing.
🪄 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

Run ID: d3814f5a-c90d-4bc7-b2c4-3eec7f13c13e

📥 Commits

Reviewing files that changed from the base of the PR and between 2bbf58f and 1a45664.

📒 Files selected for processing (3)
  • src/physiotwin4d/workflow_convert_image_to_vtk.py
  • tests/test_tutorials.py
  • tests/test_workflow_convert_image_to_vtk.py
🚧 Files skipped from review as they are similar to previous changes (2)
  • tests/test_workflow_convert_image_to_vtk.py
  • src/physiotwin4d/workflow_convert_image_to_vtk.py

Comment thread tests/test_tutorials.py
@aylward aylward merged commit 4cfbfbc into Project-MONAI:main Jul 13, 2026
10 checks passed
@aylward aylward deleted the tutorial02 branch July 13, 2026 14:05
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