dicom2ply converts DICOM RT Structure Set (RTSTRUCT) contours into geometric data.
Each ROI can be exported as point clouds, meshes, masks, slices, voxel coordinates, metadata, and geometry summaries.
Modern rewrite of the original project by Christopher M. Poole (https://github.com/christopherpoole/dicom2ply).
- Extract ROI contours from RTSTRUCT
- Reconstruct 3D coordinates using CT slice geometry
- Export one binary PLY point cloud per ROI
- --names
- --filter-name
- --filter-pattern
- --list-rois
- --ct-summary
- --dump-ct-index
- Binary mask NIfTI (--nifti)
- Float32 mask NIfTI (--float-nifti)
- ROI statistics JSON (--json)
- Minimal metadata JSON (--save-metadata)
- Consolidated metadata JSON (--meta-all)
- PNG mask slices (--png-slices)
- Marching-cubes meshes: PLY, STL, OBJ (--mesh, --stl, --obj)
- Voxel coordinates (--coords)
- Bounding box JSON (--bbox)
- HU→RGB PLY (--ply-rgb)
- LAS/LAZ point clouds (--las)
- Triangulated contour meshes (--tri-mesh)
- Dry-run mode (--dry-run)
- Batch processing via YAML (--config)
- Structured logging (--debug)
- Progress indicator [1/3] Exporting ROI 'GTV'
- ROI statistics
- ROI voxel coordinates
- ROI bounding box
- ROI mask stack
- ROI mesh generation
- src/ layout
- Modular codebase
- Full test suite
- Python 3.10+
pip install -e .
Optional dependencies:
pip install dicom2ply[imageio]
pip install dicom2ply[nifti]
pip install dicom2ply[yaml]
pip install dicom2ply[laspy]
pip install dicom2ply[opencv]
pip install dicom2ply[test]
dicom2ply <dicom_dir> <output_dir> [options]
- dicom_dir: directory containing CT slices and one RTSTRUCT
- output_dir: directory for output files
--names ROI1 ROI2
--filter-name ROI1
--filter-pattern "*GTV*"
If no selection flags are provided, all ROIs are exported.
--list-rois
--ct-summary
--dump-ct-index
--list-rois prints ROI names and basic statistics.
--ct-summary prints CT geometry summary.
--dump-ct-index writes CT slice index to ct_index.json.
| Flag | Output |
|---|---|
| --nifti | Binary mask NIfTI |
| --float-nifti | Float32 mask NIfTI |
| --json | ROI statistics JSON |
| --save-metadata | Minimal metadata JSON |
| --meta-all | Consolidated metadata JSON |
| --png-slices | PNG mask slices |
| --mesh | PLY mesh |
| --stl | STL mesh |
| --obj | OBJ mesh |
| --coords | Voxel coordinates (.npy) |
| --bbox | Bounding box JSON |
| --ply-rgb | HU→RGB PLY |
| --las | LAS/LAZ point cloud |
| --tri-mesh | Triangulated contour mesh PLY |
--dry-run
Shows selected ROIs and exits without writing files.
--config config.yaml
Example:
- dicom_dir: ./dicom
output_dir: ./out
filter_name: ["GTV"]
mesh: true--debug
Enables detailed logging.
Progress indicator:
[1/3] Exporting ROI 'GTV'
dicom2ply ./dicom ./out \
--filter-pattern "*TV" \
--json --mesh --png-slices --save-metadata \
--ply-rgb --las --tri-mesh
dicom2ply ./dicom ./out --ct-summary
dicom2ply ./dicom ./out --dump-ct-index
dicom2ply ./dicom ./out --bbox
dicom2ply ./dicom ./out --dry-run
dicom2ply ./dicom ./out --meta-all
from dicom2ply.patient import Patient
p = Patient("/path/to/dicom")
p.dump_ply(directory="/path/to/out")
p.dump_exporters(directory="/path/to/out", export_ply_rgb=True, export_las=True)
roi = p.get_roi("GTV")
roi.export_mask_nifti_float("GTV_float.nii.gz")
roi.export_all_slices_png("GTV_slices")
roi.export_mesh_ply("GTV_mesh.ply")
coords = roi.get_voxel_coordinates()
bbox = roi.bounding_box
stats = roi.export_json()src/dicom2ply/
cli.py
contour.py
ct_cache.py
geometry.py
masking.py
patient.py
exporters.py
roi.py
tests/
.github/workflows/tests.yml
pyproject.toml
README.md
pytest
Covers:
- ROI geometry reconstruction
- Contour parsing
- CT slice lookup
- PLY writing
- Extended exporters
- CLI execution
- ROI filtering and listing
- Metadata export
- Bounding box export
- CT summary and CT index export
- YAML config
- Logging and error propagation
- Axial CT slices with consistent spacing
- Standard RTSTRUCT contour encoding
- No gantry tilt
- No interpolation between missing slices
- Mesh export requires a non-empty mask volume