Skip to main content

Python versions License PyPI version CI Docs OpenSSF Scorecard codecov

dicom-dre

DICOM de-identification for both metadata and burned-in pixel text.

Burned-in text is the more difficult case. The engine blanks it from rules you define rather than from OCR or heuristic text detection: you specify which scanner models burn text into which regions of the frame, and the engine blanks those regions. That rule set is the device catalog.

  • Rule-based pixel blanking. The device catalog identifies an instance by its scanner and acquisition settings and blanks the fixed regions recorded for it. Coverage is exactly what you put in the catalog: it only blanks devices and regions you have mapped and validated, and unmatched devices pass through untouched.

  • Lossless redaction. Editing a JPEG normally means decompressing it and recompressing it, which slightly degrades the whole image. For JPEG Baseline images the engine instead edits the compressed data directly and blanks only the masked blocks, so every pixel outside those blocks stays bit-for-bit identical.

  • Deterministic and offline. No lookups and no network calls. UIDs and replacement identifiers are re-derived by hashing, so the same input plus the same parameters always produces the same output.

  • Simple, embeddable API. Call it from your own DICOM pipeline in a few lines, and supply your own identifiers (PatientID, AccessionNumber, date jitter) or let it derive them for you.

Metadata is handled alongside the pixels: description fields such as SeriesDescription and StudyDescription are redacted to remove likely PHI while preserving clinical meaning, and every attribute is scrubbed against a configurable de-identification profile.

Tailoring the device catalog and allowlist to the scanners in your PACS and the vocabulary your site uses is the substantive work of adopting dicom-dre. Once that investment is made, the result is a repeatable, auditable pipeline you can trust to process DICOM at your site.

Note: Output is not de-identified under HIPAA Safe Harbor or Expert Determination and must be validated by a qualified person before sharing. The bundled catalog and allowlist were derived from a single PACS at one site and are unlikely to be complete elsewhere. It also does not address re-identification vectors in the image content itself, such as facial reconstruction from volumetric imaging. Always treat output as retaining residual PHI risk. See Limitations and portability.

Motivation

dicom-dre is a ground-up Python implementation that replaces the Java-based MIRC-CTP anonymizer used at our site. De-identification is increasingly the work of data scientists, and their tooling is Python, so the pipeline needed to fit naturally into that ecosystem rather than sit behind a separate Java service. MIRC-CTP also configured de-identification profiles through XML, which limited the operations we could express over DICOM attributes. dicom-dre is informed by the de-identification approaches proven in CTP and builds them around code-defined profiles:

  • Profiles as code. De-identification profiles are Python, not XML, so a profile can apply arbitrary logic to an attribute (conditional edits, cross-attribute derivation, deterministic hashing) and is versioned, tested, and reviewed with the rest of the codebase.

  • Native Python integration. The engine is an importable library with an embeddable API, so it runs inside an existing Python pipeline without a separate Java service.

  • Lossless burned-in text removal. The JPEG Baseline scrubber is a port of the PixelMed JPEG Selective Block Redaction Codec (also used by CTP). It edits the compressed data directly, so pixels outside the masked blocks stay bit-for-bit identical rather than being degraded by a decompress and recompress cycle.

  • Deterministic and offline. UIDs and replacement identifiers are re-derived by hashing, with no lookup tables and no network calls, so the same input and parameters always produce the same output.

Install

Requires Python 3.12.

uv pip install dicom-dre    # or: pip install dicom-dre

Quick start

# De-identify a file or a directory tree into out/
dicom-dre deidentify scan.dcm -o out/
dicom-dre deidentify studies/ -o out/ -r

# Choose a profile, set parameters, run in parallel (-j sets worker count)
dicom-dre deidentify studies/ -o out/ \
    --profile default -p PATIENT_ID=TEST -p ACCESSION_NUMBER=TESTING -j 8

Sources are read but never modified. The command exits non-zero if any instance is quarantined.

from dicom_dre import DeidParameters, ProfileSpec, deidentify_paths

for item in deidentify_paths(
    sources=["studies/"],
    output_dir="out/",
    recursive=True,
    profile_spec=ProfileSpec(name="default"),
    parameters=DeidParameters(patient_id="TEST"),
):
    print(item.input_file, item.result.outcome)

Architecture

The CLI and the Python API share one pipeline orchestrator (pipeline.py). For each instance it runs three stages in order (catalog filter, pixel scrub, metadata scrub) and resolves the instance to exactly one outcome. The metadata scrub draws on three inputs: the derived identifiers and UIDs, the site-tailored redaction allowlist, and the selected de-identification profile.

flowchart TD
    IN[CLI or Python API] --> CAT{Device catalog match?}
    CAT -- deny rule --> FILTERED[FILTERED]
    CAT -- matched --> PIX{Scrub regions?}
    PIX -- yes --> BLANK[Blank pixel regions]
    PIX -- no --> META[Metadata scrub]
    BLANK --> META
    META --> OUT[DEIDENTIFIED]

    PARAMS[Derived or supplied IDs] --> META
    ALLOW[(Redaction allowlist)] --> REDACT[Unstructured text redactor]
    REDACT --> META
    PROFILE[De-identification profile] --> META

Outcomes

Each instance resolves to exactly one outcome:

Outcome Meaning
DEIDENTIFIED Metadata scrubbed, pixels blanked as required, written to output.
FILTERED Matched a deny rule (e.g. unsupported modality/device); not emitted.
QUARANTINED Processing failed; not emitted.

Profiles

Each profile applies the DICOM PS3.15 Basic Application Confidentiality Profile (strict is allow-list based) plus a set of PS3.15 options, recorded in DeidentificationMethodCodeSequence (0012,0064).

Profile PS3.15 method Options applied Dates
default DICOM-PS3.15E-Basic Clean Structured Content (113104), Clean Descriptors (113105), Retain Patient Characteristics (113108) Shifted per study by a derived jitter
lds DICOM-PS3.15E-Basic-LDS Clean Descriptors (113105), Retain Patient Characteristics (113108) Retained unchanged (limited data set)
lds-no-dob DICOM-PS3.15E-Basic-LDS-No-DOB Clean Descriptors (113105), Retain Patient Characteristics (113108) Retained unchanged except PatientBirthDate/Time, which are removed
strict Allow-list (Basic Profile not emitted) Clean Graphics (113103), Clean Structured Content (113104) Removed; a minimal set of technical time elements is retained

default, lds, and lds-no-dob re-derive UIDs by hashing; strict retains a fixed allow-list of elements and discards the rest.

See De-identification Profiles.

Free-text redaction tools

Description attributes such as SeriesDescription and StudyDescription are among the most useful fields for understanding what a study contains, yet because a technologist can type into them freely at the imaging device, they frequently pick up PHI. Redaction keeps the useful vocabulary while masking the rest, and it is driven by an allowlist you tailor to your site.

Redaction works token by token. A token is a run of text between delimiters: each value is split at whitespace, punctuation, and letter/digit boundaries (so MR512 becomes MR and 512). Every token is compared case-insensitively against the allowlist; tokens on the list pass through, and the rest are masked character-for-character with X. Before tokenizing, a set of regular expressions masks structured identifiers regardless of the allowlist, including dates, times, phone numbers, SSNs, ZIP+4 codes, email addresses, URLs, and long hexadecimal strings, while bare 1 to 5 digit numbers are allowed through.

Because the allowlist must match your site's vocabulary, the redactor subcommands exist to build and maintain it. Export every SeriesDescription, StudyDescription, and ProtocolName value from your PACS database to a CSV, then run these commands over that export to review the distinct tokens and decide which belong on the allowlist:

# Preview redactions and review flagged tokens, adding good ones to the allowlist
dicom-dre redactor quality-check input.csv --interactive
# List the distinct tokens in the export to curate the allowlist
dicom-dre redactor show-tokens --input input.csv
# Add one or more tokens to the allowlist directly
dicom-dre redactor allow-token TERM1 TERM2
# Redact every cell of a CSV against the current allowlist
dicom-dre redactor redact --input input.csv --output output.csv

See the redactor guide.

Documentation

Full documentation: https://susom.github.io/dicom-dre/

Development

uv run pytest

The JPEG DCT accelerator is an optional compiled C extension roughly 300x faster than the pure-Python fallback. Check its status with:

dicom-dre accelerator-status

Contributions are welcome via pull request. Changes to de-identification policy (catalog, scrub regions, profiles, or allowlist) require local evidence and regression fixtures.

License

Apache-2.0; provided "AS IS" without warranty (see LICENSE). The JPEG DCT-domain scrubber is a port of the PixelMed JPEG Selective Block Redaction Codec, distributed under that codec's BSD license; see the source header in src/dicom_dre/jpeg_dct_scrubber.py and the NOTICE file.

Metadata

Release files for dicom-dre 1.4.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for dicom-dre 1.4.1
File Size Uploaded
dicom_dre-1.4.1.tar.gz 482.1 kB Details

Built distributions (wheels)

Table of built distributions (wheels) for dicom-dre 1.4.1
File
dicom_dre-1.4.1-cp312-cp312-win_amd64.whl CPython 3.12 CPython 3.12 Windows x86-64 Details
dicom_dre-1.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl CPython 3.12 CPython 3.12 Linux glibc 2.28+ ARM64, Linux glibc 2.17+ ARM64 Details
dicom_dre-1.4.1-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl CPython 3.12 CPython 3.12 Linux glibc 2.5+ x86-64, Linux glibc 2.28+ x86-64 Details
dicom_dre-1.4.1-cp312-cp312-macosx_11_0_arm64.whl CPython 3.12 CPython 3.12 macOS 11.0+ ARM64 Details

Total release size: 1.5 MB

Release files / dicom_dre-1.4.1.tar.gz

Download URL dicom_dre-1.4.1.tar.gz
Size 482.1 kB
Tags Source
SHA-256 checksum
How to use checksums
228e3e6c4af326ad95047e8b9d405d37df8c27f6e464e9960a28d051e5b0fa9d
BLAKE2b-256 checksum
How to use checksums
98f3b4e315f7ef50f276db69f1c95f5e3ba3278e695acc83b0cf1d067140de12
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 Aug 20, 2026.

Transparency log

Release files / dicom_dre-1.4.1-cp312-cp312-win_amd64.whl

Download URL dicom_dre-1.4.1-cp312-cp312-win_amd64.whl
Size 248.6 kB
Tags CPython 3.12 Windows x86-64
SHA-256 checksum
How to use checksums
3495609e8c5e610a9139d1f5bbc7911f1a203568740816869a9c6b56d5c9cd70
BLAKE2b-256 checksum
How to use checksums
7736718bf5b20f1351885c7d514670e22d3d82026b88ce89f876eaa0bbd5d085
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 Aug 20, 2026.

Transparency log

Release files / dicom_dre-1.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl

Download URL dicom_dre-1.4.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl
Size 276.4 kB
Tags CPython 3.12 Linux glibc 2.17+ ARM64 Linux glibc 2.28+ ARM64
SHA-256 checksum
How to use checksums
236f9eeadeb6b12351f01e7016316136d6fa57f6e5eaddc6625b3e5ac5a43a53
BLAKE2b-256 checksum
How to use checksums
ca9018041f5ef0ba3b3a40f80bb1259a5299ceca95b104451aae55dac3908628
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 Aug 20, 2026.

Transparency log

Release files / dicom_dre-1.4.1-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl

Download URL dicom_dre-1.4.1-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl
Size 276.4 kB
Tags CPython 3.12 Linux glibc 2.28+ x86-64 Linux glibc 2.5+ x86-64
SHA-256 checksum
How to use checksums
7a535240839807db083b1c804a1912553226ae25b50c7618c75f26aae49f4386
BLAKE2b-256 checksum
How to use checksums
c716a7be6bb9180103e554f7dbcd0fff40f72c42c4e00950127510b1487b5f7a
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 Aug 20, 2026.

Transparency log

Release files / dicom_dre-1.4.1-cp312-cp312-macosx_11_0_arm64.whl

Download URL dicom_dre-1.4.1-cp312-cp312-macosx_11_0_arm64.whl
Size 245.7 kB
Tags CPython 3.12 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
833347c84f0a44501e428ff90d8a3979767de1954024b5fbd5eb6654333b6561
BLAKE2b-256 checksum
How to use checksums
a871f5c26aa8f27e65b9517d002bf3e75f8a09d2b3ec5ab80c41452d86c9af66
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 Aug 20, 2026.

Transparency log
Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page