pyCERR - A Python-based Computational Environment for Radiological Research
pyCERR provides a convenient data structure for radiological imaging metadata and their associations: scans, segmentations, radiotherapy dose, treatment plans and deformable registrations for a patient are held together in a single container. Utilities are provided to extract, transform and organize this metadata, and to visualize the results of image processing.
On this foundation, pyCERR supports a wide range of applications in radiology and radiation oncology research:
- Image analysis: IBSI-compliant radiomics and texture maps, PET SUV computation, DCE-MRI uptake features and optimal mass transport (urOMT) analysis
- Segmentation: contouring, structure operations, consensus contours and auto-segmentation with pre-trained AI models
- Registration: deformable image registration (plastimatch, ANTs) with tools for registration quality assurance
- Dosimetry and outcomes: dose-volume histograms and metrics, gamma dose comparison, and normal tissue complication / tumor control probability models
- Treatment planning: IMRT dose calculation and fluence optimization, including lattice radiotherapy
- AI workflows: data preparation for model training and inference, on a workstation or in the cloud
Quick Start
Create a virtual environment with uv, install pyCERR with the desktop viewer, and launch Python:
uv venv --python 3.12
source .venv/bin/activate # Windows: .venv\Scripts\activate
uv pip install "pycerr[viewer]"
python
In Python, load an example dataset and show it in the desktop viewer:
from cerr import plan_container as pc
from cerr.viewer.pycerr_gui import show
from cerr import datasets
dcmDir = datasets.fetch_sample_data('head_and_neck') # local if present, else downloaded
planC = pc.loadDcmDir(dcmDir)
v = show(planC)
The desktop viewer needs the viewer extra. A plain pycerr install covers
everything else, including the Jupyter viewer; see Install pyCERR.
Features
All data for a patient lives in a single PlanC container — scans, structures
(segmentations), dose, treatment plans (beams) and deformations — defined in
cerr.plan_container. Around it, pyCERR provides:
Data import / export
- DICOM import of CT/MR/PT/US/NM scans plus RTSTRUCT, RTDOSE and RTPLAN —
pc.loadDcmDir - NIfTI import/export of scans, segmentations and dose —
pc.loadNiiScan/loadNiiStructure/loadNiiDose,.saveNii - Full-
PlanCHDF5 serialization —pc.saveToH5/pc.loadFromH5 - DICOM RTSTRUCT export —
cerr.dcm_export.rtstruct_iod
Segmentation & contours
- Lazy polygon → binary-mask rasterization —
cerr.contour.rasterseg.getStrMask - Import label maps / binary masks as structures —
cerr.dataclasses.structure.importStructureMask
Radiomics (IBSI-compliant)
- Scalar features: morphology, first-order, GLCM / GLRLM / GLSZM / GLDZM / NGTDM / NGLDM (IBSI-1)
- Convolutional texture / filter-response maps: mean, LoG, Laws, Gabor, wavelet (IBSI-2)
cerr.radiomics.ibsi1.computeScalarFeatures, configured via JSON settings
Dosimetry & outcomes
- Dose–volume histograms and metrics (Dx, Vx, MOHx, MOCx, mean dose) —
cerr.dvh - Radiotherapy outcome models (NTCP/TCP: LKB, logistic, Cox, Appelt) —
cerr.roe - IMRT planning / beamlet (influence-matrix) dose calculation —
cerr.imrtp
Image processing
- Deformable image registration via plastimatch / ANTs —
cerr.registration - Resampling, intensity preprocessing and masking —
cerr.utils - Semi-quantitative DCE-MRI features —
cerr.mri_metrics - Helpers for AI model training / inference pipelines —
cerr.utils.ai_pipeline
Visualization — three interchangeable viewers driven by the same planC
(a PyQt5 CERR-style desktop GUI, a Jupyter/Colab notebook viewer, and
napari 2D/3D); see visualize scan, dose and segmentation below.
Documentation
- Example notebooks (grouped by topic): https://github.com/cerr/pyCERR-Notebooks
- API reference — https://pycerr.readthedocs.io (built from
docs/; build locally withcd docs && make html) - Desktop GUI scripting API —
cerr/viewer/API_pycerr_gui.md - Test suite & coverage —
tests/README.md
Install pyCERR
pyCERR is published on PyPI as pycerr and
supports Python 3.9–3.13 (3.12 recommended). Install it into an isolated
virtual environment. The steps below use uv;
install it first if you don't have it (curl -LsSf https://astral.sh/uv/install.sh | sh
on macOS/Linux, winget install --id=astral-sh.uv on Windows, or brew install uv).
1. Create and activate a virtual environment
uv venv --python 3.12 # creates .venv/, downloading Python 3.12 if needed
source .venv/bin/activate # Windows: .venv\Scripts\activate
2. Install pyCERR with the extras you need
uv pip install pycerr # core: I/O, radiomics, DVH, registration, Jupyter viewer
uv pip install "pycerr[viewer]" # + PyQt5 desktop viewer (pycerr_gui), ROE and IMRTP GUIs
uv pip install "pycerr[viewer,napari]" # + napari 2D/3D viewer
| Extra | Adds | Needed for |
|---|---|---|
| (none) | core dependencies, ipywidgets |
Python API, headless/batch processing, containers, cerr.viewer.pycerr_nbviewer (Jupyter / Colab) |
viewer |
PyQt5, pyvista, pyvistaqt |
cerr.viewer.pycerr_gui desktop viewer (incl. 3D view), ROE and IMRTP GUIs |
napari |
napari[all], napari-animation |
cerr.viewer.pycerr_napari |
ants |
antspyx |
ANTs-based registration, cerr.registration.ants_reg |
gpu |
cupy-cuda13x and NVIDIA CUDA 13 runtime wheels |
optional GPU acceleration of the urOMT solver |
Extras can be combined, e.g. uv pip install "pycerr[viewer,napari,ants]".
The viewer extra is not in the base install because PyQt5 has no aarch64
Linux wheel; on arm64 Linux (ARM servers, Apple Silicon Docker images) install
plain pycerr. Launching pycerr_gui without the extra raises an ImportError
naming the install command.
AI segmentation models (cerr.ai_models) additionally need model_installer,
which is distributed from GitHub only:
uv pip install "model_installer @ git+https://github.com/cerr/model_installer.git"
Install the latest development version
uv pip install "pycerr[viewer] @ git+https://github.com/cerr/pyCERR.git@main"
or, to work on pyCERR itself, clone the repository and make an editable install:
git clone https://github.com/cerr/pyCERR.git
cd pyCERR
uv venv --python 3.12
source .venv/bin/activate
uv pip install -e ".[viewer,napari]" pytest
Jupyter
Install JupyterLab in the same environment to run the example notebooks:
uv pip install jupyterlab
jupyter lab
In Google Colab, install with !pip install pycerr (the notebook viewer needs no extra).
Example Notebooks
Example notebooks are hosted at https://github.com/cerr/pyCERR-Notebooks/. Clone this repository to use notebooks as a starting point.
git clone https://github.com/cerr/pyCERR-Notebooks.git
Example snippets
Run Python from the virtual environment created above and try out the following code samples.
Import modules for planC and viewer
import numpy as np
from cerr import plan_container as pc
from cerr.viewer import pycerr_gui # desktop viewer (pycerr_gui.show, ...); needs pycerr[viewer]
Read DICOM directory contents to planC
dcmDir = r"\\path\to\Data\dicom\directory"
planC = pc.loadDcmDir(dcmDir)
Read NifTi scan to planC
scanNiiFileName = r"\\path\to\Data\scan.nii.gz"
planC = pc.loadNiiScan(scanNiiFileName, imageType = "CT SCAN")
Read NifTi scan in a specified orientation to planC
planC = pc.loadNiiScan(scanNiiFileName, imageType = "CT SCAN", direction='LPS') # 3-letter orientation code, e.g. 'LPS', 'RAS'
Read NifTi scan and append to an existing planC
planC = pc.loadNiiScan(scanNiiFileName, imageType = "CT SCAN", direction='LPS', initplanC=planC)
Read NifTi segmentation to planC
structNiiFileName = r"\\path\to\Data\structure.nii.gz"
assocScanNum = 0
labelDict = {'GTV_P': 1, 'GTV_N': 2} # structure name -> label value
planC = pc.loadNiiStructure(structNiiFileName, assocScanNum, planC, labelDict)
Export Structures to DICOM
from cerr.dcm_export import rtstruct_iod
structDcmFileName = r"\\path\to\Data\structure.dcm"
structNums = [0,2,3]
exportOpts = {'seriesDescription': "Exported by pyCERR"}
rtstruct_iod.create(structNums,structDcmFileName,planC,exportOpts)
Export Scan, Structure and Dose to NifTi
scanNiiFileName = r"\\path\to\Data\scan.nii.gz"
scanNum = 0
planC.scan[scanNum].saveNii(scanNiiFileName)
structNiiFileName = r"\\path\to\Data\structure.nii.gz"
structNum = 0
planC.structure[structNum].saveNii(structNiiFileName, planC)
doseNiiFileName = r"\\path\to\Data\dose.nii.gz"
doseNum = 0
planC.dose[doseNum].saveNii(doseNiiFileName)
visualize scan, dose and segmentation
pyCERR ships three interchangeable viewers under the cerr.viewer sub-package,
all driven by the same planC:
| Viewer | Module | Install | Best for |
|---|---|---|---|
| PyQt5 desktop | cerr.viewer.pycerr_gui (show) |
pycerr[viewer] |
CERR-style slice viewer: contouring, registration QA, IMRTP/ROE, scripting API |
| notebook | cerr.viewer.pycerr_nbviewer (showNB) |
pycerr |
Jupyter / JupyterLab / VS Code / Google Colab |
| napari 2D/3D | cerr.viewer.pycerr_napari (showNapari) |
pycerr[napari] |
quick interactive review, 3D rendering |
PyQt5 desktop viewer
from cerr.viewer import pycerr_gui
viewer = pycerr_gui.show(planC) # opens the CERR-style desktop GUI
# ... or launch empty and drag-and-drop a DICOM directory / NIfTI file in.
# The viewer exposes a scripting API (set_scan/set_dose/goto_structure,
# registration-QA setup, DVH export, save_screenshot, ...); see
# cerr/viewer/API_pycerr_gui.md for the full reference.
Notebook viewer (Jupyter / Colab)
from cerr.viewer import pycerr_nbviewer
viewer = pycerr_nbviewer.showNB(planC, scan_nums=[0], struct_nums=strNumList,
dose_nums=[0])
napari viewer
from cerr.viewer import pycerr_napari
scanNumList = [0]
doseNumList = [0]
numStructs = len(planC.structure)
strNumList = np.arange(numStructs)
displayMode = '2d' # '2d' or '3d'
vectDict = {}
viewer, scan_layer, struct_layer, dose_layer, dvf_layer = \
pycerr_napari.showNapari(planC, scan_nums=scanNumList, struct_nums=strNumList,\
dose_nums=doseNumList, vectors_dict=vectDict, displayMode = '2d')
Compute DVH-based metrics
from cerr import dvh
structNum = 0
doseNum = 0
dosesV, volsV, isErr = dvh.getDVH(structNum, doseNum, planC)
binWidth = 0.025
doseBinsV,volHistV = dvh.doseHist(dosesV, volsV, binWidth)
percent = 70
dvh.MOHx(doseBinsV,volHistV,percent)
Compute radiomics
import os
from cerr import datasets
from cerr.radiomics import ibsi1
scanNum = 0
structNum = 0
# JSON settings file: resampling, intensity discretization and feature classes.
# A sample is shipped with pyCERR; copy and edit it for your own analysis.
settingsFile = os.path.join(os.path.dirname(datasets.__file__),
'radiomics_settings', 'original_settings.json')
featDict, diagDict = ibsi1.computeScalarFeatures(scanNum, structNum, settingsFile, planC)
# featDict maps feature names to values (IBSI-1: shape, first-order, GLCM, GLRLM, GLSZM, ...)
Compute texture
import os
from cerr import datasets
from cerr.radiomics import texture_utils
scanNum = 0
structNum = 0
# JSON settings file for a convolutional filter (IBSI-2). Samples shipped with pyCERR:
# mean_filter.json, LoG_filter.json, Rot_inv_laws_energy_filter.json, gabor_filter.json
settingsFile = os.path.join(os.path.dirname(datasets.__file__),
'convolutional_filter_settings', 'LoG_filter.json')
planC = texture_utils.generateTextureMapFromPlanC(planC, scanNum, structNum, settingsFile)
# The texture map is added as a new scan, cropped around the structure
textureScanNum = len(planC.scan) - 1
texture3M = planC.scan[textureScanNum].getScanArray()
Metadata
Release files for pycerr 2.3.3
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| pycerr-2.3.3.tar.gz | 28.4 MB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pycerr-2.3.3-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 54.2 MB
Release files / pycerr-2.3.3.tar.gz
| Download URL | pycerr-2.3.3.tar.gz |
|---|---|
| Size | 28.4 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
4294f99f56629366a9c78ca704904c4a74e532ae71590bc445a28ccd08714eca
|
|
BLAKE2b-256 checksum How to use checksums |
193519d5ec2749a8cfffb4b37f539aacea62bf8d7872087b5080427ff65d0a8e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 15, 2026.
Transparency logRelease files / pycerr-2.3.3-py3-none-any.whl
| Download URL | pycerr-2.3.3-py3-none-any.whl |
|---|---|
| Size | 25.9 MB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
1e2e7590f61795a765c39c4437ed9ba101d1a1e98b3a3c2b857af74150228010
|
|
BLAKE2b-256 checksum How to use checksums |
26672ff00aed2cff566b87c89c089d83bdda9c0353fb3daf1a8345fb541f9c60
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 15, 2026.
Transparency log