Repository navigation
Support line2 meshes, NIfTI images and label map interpolation - #16
Merged
Merged
Conversation
Read .vtu via lnmmeshio, filter by any element field (material_ids deprecated), export into the input mesh. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Read .nii/.nii.gz images via nibabel (RAS to LPS, cropped to the mesh), pixel type from options. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Average all voxels within the region of each element in a NIfTI label map, e.g. terminal unit regions. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
FourCYamlReader becomes LnmmeshioReader (reads .4C.yaml and .vtu), MeshReader becomes TrimeshReader. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
There was a problem hiding this comment.
🟡 Changes recommended
Four unresolved moderate review findings remain in mesh filtering, image-folder detection, and label-map memory handling.
Get a fresh assessment by requesting another Copilot review.
Pull request overview
Adds line2/VTU mesh support, NIfTI loading, label-map interpolation, element filtering, and discretization export.
Changes:
- Adds unified mesh readers and configurable element filtering.
- Adds NIfTI RAS→LPS conversion and label-map interpolation.
- Adds VTU cell-data export, visualization updates, documentation, dependencies, and tests.
File summaries
| File | Reviewed change |
|---|---|
tests/unittests/i2pp/core/visualizers/test_discretization_visualizer.py |
Tests line rendering. |
tests/unittests/i2pp/core/test_run.py |
Updates export fixtures. |
tests/unittests/i2pp/core/test_export_data.py |
Tests discretization export routing. |
tests/unittests/i2pp/core/test_discretization_helpers.py |
Tests VTU and line cells. |
tests/unittests/i2pp/core/interpolators/test_interpolator_types.py |
Tests label-map registration. |
tests/unittests/i2pp/core/interpolators/test_interpolator_label_map.py |
Tests label-map interpolation. |
tests/unittests/i2pp/core/image_readers/test_nifti_reader.py |
Tests NIfTI loading and cropping. |
tests/unittests/i2pp/core/exporters/test_export_format.py |
Tests export format registration. |
tests/unittests/i2pp/core/exporters/test_discretization_exporter.py |
Tests VTU cell-data export. |
tests/unittests/i2pp/core/discretization_readers/test_trimesh_reader.py |
Tests the renamed mesh reader. |
tests/unittests/i2pp/core/discretization_readers/test_lnmmeshio_reader.py |
Tests unified reading and filtering. |
tests/unittests/i2pp/core/discretization_readers/test_fourc_yaml_reader.py |
Updates legacy reader tests. |
tests/unittests/i2pp/core/discretization_readers/test_discretization_format.py |
Tests reader selection and VTU support. |
tests/unittests/i2pp/core/configuration_validator/test_validator_labelmap.py |
Tests label-map validation. |
tests/unittests/i2pp/core/configuration_validator/test_validator_export.py |
Tests export validation. |
tests/unittests/i2pp/core/configuration_validator/test_validator_element_filter.py |
Tests element-filter validation. |
templates/config/example_config.yaml |
Documents new configuration options. |
src/i2pp/core/visualizers/visualizer.py |
Supports mesh rendering options. |
src/i2pp/core/visualizers/discretization_visualizer.py |
Renders line cells as tubes. |
src/i2pp/core/run.py |
Integrates label maps and exports. |
src/i2pp/core/interpolators/interpolator.py |
Centralizes outlier filtering. |
src/i2pp/core/interpolators/interpolator_types.py |
Registers label-map interpolation. |
src/i2pp/core/interpolators/interpolator_label_map.py |
Implements label-map interpolation. Moderate (1 vote): Retaining all labels and pixel values defeats slice-by-slice memory savings; use accumulated statistics or bounded chunks. |
src/i2pp/core/interpolators/interpolator_all_voxel.py |
Removes duplicated filtering logic. |
src/i2pp/core/interpolate_element_data.py |
Passes label-map settings to interpolators. |
src/i2pp/core/import_image.py |
Detects NIfTI inputs. Moderate (3 votes): Mixed NIfTI/DICOM/PNG folders silently ignore NIfTI files; reject these combinations. |
src/i2pp/core/image_readers/nifti_reader.py |
Implements NIfTI loading, orientation conversion, and cropping. |
src/i2pp/core/image_readers/label_map.py |
Implements label-map lookup and caching. |
src/i2pp/core/image_readers/image_format.py |
Registers NIfTI support. |
src/i2pp/core/exporters/export_format.py |
Registers discretization export. |
src/i2pp/core/exporters/discretization_exporter.py |
Writes results into VTU cell data. |
src/i2pp/core/export_data.py |
Routes discretization exports. |
src/i2pp/core/discretization_readers/trimesh_reader.py |
Renames the trimesh reader. Moderate (3 votes): .mesh element filters reach an unimplemented runtime path and fail; implement filtering or reject the option during validation. |
src/i2pp/core/discretization_readers/lnmmeshio_reader.py |
Adds unified reading and filtering. Moderate (1 vote): Filtering can leave surface node sets referencing removed nodes, causing KeyError; skip absent nodes and omit empty surfaces before scaling. |
src/i2pp/core/discretization_readers/fourc_yaml_reader.py |
Removes the superseded reader implementation. |
src/i2pp/core/discretization_readers/discretization_reader.py |
Adds element metadata and fields. |
src/i2pp/core/discretization_readers/discretization_format.py |
Registers readers and VTU support. |
src/i2pp/core/discretization_helpers.py |
Supports line and triangle cells. |
src/i2pp/core/configuration_validator/validator.py |
Validates filters, label maps, and exports. |
requirements.txt |
Locks the NIfTI dependency. |
requirements.in |
Adds the NIfTI dependency. |
README.md |
Documents the new features and workflows. |
Review details
Suppressed comments (3)
src/i2pp/core/discretization_readers/lnmmeshio_reader.py:212
- After
_filter_discretizationreplacesraw_dis.nodeswith only nodes referenced by selected elements,raw_dis.surfacenodesetsstill contains the original surface nodes. Indexing every surface node here therefore raisesKeyErrorwhenever a filtered-out node belongs to a surface, so filtered 4C meshes with surfaces cannot load. Skip nodes absent fromnode_id_to_idxand omit empty surfaces before applying the surface scaling.
for node in surf.nodes:
surf_node_ids.append(node.id)
position = node_id_to_idx[node.id]
nodes_scaling[position] = surface_node_scaling
src/i2pp/core/discretization_readers/trimesh_reader.py:69
- The validator now normalizes
material_idsand the documentedelement_filterfor every discretization format, but this branch makes.meshinputs call_filter_discretization, which is still an unconditionalnot implemented yetstub and cannot receive the filter. Any supported.meshconfiguration using the documented filter consequently fails at runtime; implement filtering for the trimesh representation or reject this option for.meshduring validation.
src/i2pp/core/interpolators/interpolator_label_map.py:123 - Although the docstring says processing is slice-by-slice to limit memory, these lists retain every selected label and pixel value until the final concatenation, so peak memory still scales with the entire cropped volume and duplicates the image data. A patient-sized label-map run can therefore consume substantially more memory than expected; accumulate per-label statistics (and outlier state) or process bounded chunks instead of retaining all voxels.
voxel_labels = []
voxel_values = []
for k, slice_coord in enumerate(grid.slice):
slice_points[:, 0] = slice_coord
- Files reviewed: 41/42 changed files
- Comments generated: 1
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Enables inferring element properties for line2 meshes, e.g. lung trees generated by pneumogen, including terminal unit properties from their voxel regions.
Changes
.vtufiles are read via lnmmeshio, keeping all cell data as element fields.element_filter: {field, values}selects elements by any element field (e.g.block_id,MAT).material_idsis deprecated and translated with a warning.export.type: discretizationwrites every field returned by the user function as cell data into a copy of the input.vtu. Unselected cells are NaN, so runs on different selections can be chained.output_parameter_nameis now only allowed forjson..nii/.nii.gzfiles are read via nibabel (RAS→LPS), cropped to the mesh; modality viapixel_type(default CT).method: labelmapaverages all voxels of each element's region in a NIfTI label map (e.g. pneumogen terminal unit labels). Coarser label maps are supported.LnmmeshioReaderandTrimeshReader.Testing
234 unit tests pass. The label map interpolation was verified on a patient lung tree against a direct per-label mean, with 0 HU difference.
🤖 Generated with Claude Code.