Skip to main content

DICOM RT Structure and Registration

Project description

pydicomRT

pydicomRT is a Python library for handling Radiation Therapy DICOM files. It provides utilities to create, modify, parse, and validate RTSTRUCT datasets; convert between RTSTRUCT and volumetric masks; and handle spatial/deformable registration and dose. It integrates smoothly with pydicom, numpy, and SimpleITK.


Project Goals

  • Lower the development barrier for RT applications
    Provide intuitive APIs and tools that allow researchers and engineers to work with radiation therapy–related DICOM files more easily, without requiring deep knowledge of the complex DICOM standard.

  • Enable seamless integration between Python 3D libraries and pydicom
    Build a robust bridge so that common Python 3D image processing libraries (e.g., numpy, SimpleITK) can work seamlessly with pydicom, accelerating medical imaging and radiotherapy application development.


Features

  • Build RTSTRUCT datasets and manage Regions of Interest (ROIs)
  • Convert between 3D numpy masks and DICOM contours
  • Validate RTSTRUCT, Spatial REG, Deformable REG, and RTDOSE datasets
  • Load and sort DICOM image series with orientation/spacing sanity checks
  • Generate RTDOSE datasets and convert RTDOSE DICOM files to SimpleITK images
  • Export Spatial (REG) and Deformable Spatial (REG-DR) registrations from SimpleITK transforms
  • Parse deformable registration grids into NumPy displacement fields
  • SimpleITK helpers for image building, resampling, and registration (rigid, demons, bspline, soft_demons)
  • Rigid registration (rigid_registration): tunable Mattes mutual information and gradient-descent settings (histogram bins, learning rate, iterations, convergence); demons multiscale path: stricter resampling validation and clearer multiscale documentation
  • Coordinate transformation utilities between pixel and patient spaces
  • CT modality IOD helpers, plus CTBuilder to emit multi-slice CT DICOM datasets from SimpleITK images or numpy volumes (patient/study/series metadata and common orientations)
  • SimpleITK preprocessing: bilateral and median denoising, and N4 bias field correction (n4bfc)
  • Spatial / deformable REG parsing and transform extraction refined (inverse-matrix handling, cleaner registration dictionaries, displacement-grid extraction)

Quick Links

  • Examples: example/try_demon_reg.py, example/try_sort_dcms.py
  • Deformable REG builder demo: test/reg/df_reg_build_test.py
  • RTSTRUCT API: src/pydicomrt/rs
  • Registration API: src/pydicomrt/reg
  • Utilities: src/pydicomrt/utils
  • Architecture Doc: docs/architecture.md

Installation

Dependencies

  • Python >= 3.10
  • pydicom >= 2.0.0
  • numpy >= 1.26.4
  • opencv-python >= 4.10.0
  • scipy >= 1.10.3
  • simpleitk >= 2.5.0

Install via pip

pip install pydicomrt

Install from source

git clone https://github.com/higumalu/pydicomRT.git
cd pydicomRT
pip install .

Usage Examples

Create an RTSTRUCT Dataset and Add ROI

import numpy as np
from pydicomrt.rs.make_contour_sequence import add_contour_sequence_from_mask3d
from pydicomrt.rs.add_new_roi import create_roi_into_rs_ds
from pydicomrt.rs.builder import create_rtstruct_dataset
from pydicomrt.utils.image_series_loader import load_sorted_image_series

# Load DICOM image series
ds_list = load_sorted_image_series("path/to/dicom/images")

# Create an empty RTSTRUCT dataset
rs_ds = create_rtstruct_dataset(ds_list)

# Create an ROI (Region of Interest)
rs_ds = create_roi_into_rs_ds(rs_ds, [0, 255, 0], 1, "CTV", "CTV")

# Create a 3D mask
mask = np.zeros((len(ds_list), 512, 512))
mask[100:200, 100:400, 100:400] = 1
mask[120:180, 200:300, 200:300] = 0

# Add 3D mask to RTSTRUCT dataset
rs_ds = add_contour_sequence_from_mask3d(rs_ds, ds_list, 1, mask)

# Save the RTSTRUCT dataset
rs_ds.save_as("path/to/output.dcm", write_like_original=False)

Spatial Registration (Rigid) and DICOM REG Export

This example estimates a rigid transform between two CT series using SimpleITK and stores it in a DICOM Spatial Registration (REG) object.

import numpy as np
import SimpleITK as sitk
from pydicomrt.utils.image_series_loader import load_sorted_image_series
from pydicomrt.utils.sitk_transform import SimpleITKImageBuilder
from pydicomrt.reg.method.rigid import rigid_registration
from pydicomrt.reg.type_transform import affine_to_homogeneous_matrix
from pydicomrt.reg.builder import SpatialRegistrationBuilder

# Load CT series as pydicom datasets
fixed_ds = load_sorted_image_series("/path/to/CT_fixed")
moving_ds = load_sorted_image_series("/path/to/CT_moving")

# Convert to SimpleITK images
fixed_img = SimpleITKImageBuilder().from_ds_list(fixed_ds)
moving_img = SimpleITKImageBuilder().from_ds_list(moving_ds)

# Run rigid registration in physical space (returns sitk.Transform)
rigid_tfm = rigid_registration(fixed_img, moving_img)

# Convert to 4x4 row-major list for DICOM REG
tfm_4x4 = affine_to_homogeneous_matrix(rigid_tfm).astype(np.float32).ravel().tolist()

# Build a DICOM Spatial Registration dataset and save
builder = SpatialRegistrationBuilder(fixed_ds)
builder.set_uid_prefix("1.2.826.0.1.3680043.2.1125.")  # Optional but helps keep UIDs consistent
builder.add_rigid_registration(moving_ds, tfm_4x4)
reg_ds = builder.build()
reg_ds.save_as("/path/to/output_reg.dcm", write_like_original=False)

Notes:

  • DICOM stores transforms as a 4x4 row-major matrix in the fixed image frame. Ensure transform directions match your use-case.
  • You can set a custom UID root globally via the DICOM_UID_PREFIX environment variable.

Deformable Spatial Registration (Demons) Export

This workflow performs a rigid pre-align, runs demons registration, and exports the resulting displacement field into a DICOM Deformable Spatial Registration dataset.

import numpy as np
import SimpleITK as sitk
from pydicomrt.utils.image_series_loader import load_sorted_image_series
from pydicomrt.utils.sitk_transform import SimpleITKImageBuilder, resample_to_reference_image
from pydicomrt.reg.method.rigid import rigid_registration
from pydicomrt.reg.method.demons import demons_registration
from pydicomrt.reg.type_transform import affine_to_homogeneous_matrix
from pydicomrt.reg.builder import DeformableSpatialRegistrationBuilder

fixed_ds = load_sorted_image_series("/path/to/CT_fixed")
moving_ds = load_sorted_image_series("/path/to/CT_moving")
fixed_img = SimpleITKImageBuilder().from_ds_list(fixed_ds)
moving_img = SimpleITKImageBuilder().from_ds_list(moving_ds)

# Ensure voxel grids match before registration
moving_img = resample_to_reference_image(fixed_img, moving_img)

# Rigid pre-alignment
rigid_tfm = rigid_registration(fixed_img, moving_img)
rigid_matrix = affine_to_homogeneous_matrix(rigid_tfm).astype(np.float32).ravel().tolist()
moving_rigid = sitk.Resample(
    moving_img,
    fixed_img,
    rigid_tfm,
    sitk.sitkLinear,
    -1000.0,
    moving_img.GetPixelIDValue(),
)

# Demons deformable registration (returns registered image, transform, displacement field)
reg_img, deform_tfm, dvf = demons_registration(fixed_img, moving_rigid, verbose=False)

# Export to DICOM Deformable Spatial Registration
identity = np.eye(4, dtype=np.float32).ravel().tolist()

builder = DeformableSpatialRegistrationBuilder(fixed_ds)
builder.add_deformable_registration(
    moving_ds_list=moving_ds,
    vectorial_field_transform=deform_tfm,
    pre_transform=rigid_matrix,
    post_transform=identity,
)
reg_dr = builder.build()
reg_dr.save_as("/path/to/output_dr.dcm", write_like_original=False)

demons_registration returns a SimpleITK displacement-field transform (deform_tfm) and a DVF image (dvf). The builder converts the transform into the DICOM VectorGridData representation automatically.


Parse a Deformable Registration Dataset

from pydicom import dcmread
from pydicomrt.reg.parser import get_deformable_reg_list

reg_ds = dcmread("/path/to/output_dr.dcm")
reg_entries = get_deformable_reg_list(reg_ds)
field = reg_entries[0]["DeformableRegistrationGrid"]["VectorGridData"]
print(field.shape)  # (z, y, x, 3) float32 displacement vectors in mm

Create an RTDOSE Dataset from a SimpleITK Image

import SimpleITK as sitk
from pydicom import dcmread
from pydicomrt.dose.builder import generate_base_dataset, cp_information_from_ds, add_dose_grid_to_ds

reference = dcmread("path/to/reference_ct_or_plan.dcm")
dose_img = sitk.ReadImage("path/to/dose_image.nii.gz")

dose_ds = generate_base_dataset()
dose_ds = cp_information_from_ds(dose_ds, reference)
dose_ds = add_dose_grid_to_ds(dose_ds, dose_img)

dose_ds.save_as("path/to/output_dose.dcm", write_like_original=False)

To convert an RTDOSE DICOM dataset back to SimpleITK, use pydicomrt.dose.sitk_transform.get_dose_sitk_image.


Extract Contour Information from RTSTRUCT Dataset

from pydicomrt.rs.parser import get_roi_number_to_name, get_contour_dict

# Get ROI mapping
roi_map = get_roi_number_to_name(rs_ds)
print(roi_map)  # Output: {1: 'CTV'}

# Get contour dictionary
ctr_dict = get_contour_dict(rs_ds)

Validate RTSTRUCT Dataset

from pydicomrt.rs.checker import check_rs_iod

# Check whether the RTSTRUCT dataset conforms to IOD specification
result = check_rs_iod(rs_ds)
print(result)  # Output: {'result': True, 'content': []}

Convert RTSTRUCT to 3D Mask

from pydicomrt.rs.rs_to_volume import rtstruct_to_mask_dict, calc_image_series_affine_mapping
from pydicomrt.utils.image_series_loader import load_sorted_image_series

# Load DICOM image series
ds_list = load_sorted_image_series("path/to/dicom/images")

# Calculate affine mapping and mask volume shape
affine_mapping, mask_volume_shape = calc_image_series_affine_mapping(ds_list)

# Convert RTSTRUCT to 3D mask dictionary
mask_dict = rtstruct_to_mask_dict(rs_ds, affine_mapping, mask_volume_shape)

Module Structure

  • rs: RTSTRUCT-related functionalities

    • builder: Create RTSTRUCT datasets
    • add_new_roi: Add new ROIs
    • make_contour_sequence: Create contour sequences
    • parser: Parse RTSTRUCT datasets
    • checker: Validate RTSTRUCT datasets
    • rs_to_volume: Convert between RTSTRUCT and volume data
    • packer: Pack contour data
    • contour_process_method: Contour processing methods
    • rs_ds_iod: RTSTRUCT IOD definitions
  • reg: Spatial/deformable registration

    • builder: Build DICOM REG / Deformable REG datasets
    • parser: Extract spatial/deformable transforms (e.g., get_deformable_reg_list)
    • check: Validate registration datasets
    • method: SimpleITK registration helpers (rigid, bspline, demons, soft_demons)
    • ds_reg_ds_iod: Deformable spatial registration IOD definitions
    • s_reg_ds_iod: Spatial registration IOD definitions
    • type_transform: Transform conversions (affine → homogeneous, displacement fields → DICOM grids)
  • dose: Dose distribution functionalities

    • builder: Create dose datasets
    • sitk_transform: Convert dose datasets to SimpleITK images
    • dose_ds_iod: Dose IOD definitions
  • ct: CT image data functionalities

    • builder: CTBuilder — build CT Image DICOM slices from a sitk.Image or numpy volume (with reference series for metadata)
    • ct_ds_iod: CT IOD definitions
  • utils: Utility tools

    • image_series_loader: Load and sort DICOM image series
    • coordinate_transform: Coordinate transformation utilities
    • validate_dcm_info: Validate DICOM metadata
    • sitk_transform: SimpleITK conversions, SimpleITKImageBuilder, and resampling helpers (origin, spacing, and direction accept numpy arrays and are normalized for SimpleITK)
    • sitk_image_process: Bilateral / median denoise and N4 bias field correction (bilateral_denoise, median_denoise, n4bfc)
    • rs_from_altas: Build RTSTRUCT datasets from atlas inputs

Contributing

Issues and pull requests are welcome!


Reference


License

This project is licensed under the MIT License - see the LICENSE file for details.


Author

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pydicomrt-0.8.0.tar.gz (62.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pydicomrt-0.8.0-py3-none-any.whl (70.7 kB view details)

Uploaded Python 3

File details

Details for the file pydicomrt-0.8.0.tar.gz.

File metadata

  • Download URL: pydicomrt-0.8.0.tar.gz
  • Upload date:
  • Size: 62.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for pydicomrt-0.8.0.tar.gz
Algorithm Hash digest
SHA256 113e212d757bc323a6d70a97dd34148c84d6d30a69e9d142e51e04bd27aabbce
MD5 446db1c956239a8c6dbee44863ac6b59
BLAKE2b-256 767f93cf84afc22b5a2a327d3a89b300cd12c1b0fd85609704d81d71bb30e66b

See more details on using hashes here.

Provenance

The following attestation bundles were made for pydicomrt-0.8.0.tar.gz:

Publisher: publish-pypi.yml on higumalu/pydicomRT

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pydicomrt-0.8.0-py3-none-any.whl.

File metadata

  • Download URL: pydicomrt-0.8.0-py3-none-any.whl
  • Upload date:
  • Size: 70.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for pydicomrt-0.8.0-py3-none-any.whl
Algorithm Hash digest
SHA256 e3338fa1be2cd9d0ab348ac0130f4cd05b38ed3e6f3dde7c064603189899641a
MD5 de539612937583f98226b8221b4a0749
BLAKE2b-256 4dde1ce6ffa436a1eca47958fdbbec12c6276ec4d969635513f64bcaf245fb05

See more details on using hashes here.

Provenance

The following attestation bundles were made for pydicomrt-0.8.0-py3-none-any.whl:

Publisher: publish-pypi.yml on higumalu/pydicomRT

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page