I just released dicom-clean — an open-source CLI tool for HIPAA-compliant DICOM de-identification. Here's how it works and why I built it.

The Problem

Medical imaging files (CT scans, MRIs, X-rays) use a format called DICOM, which contains two things:

  1. Metadata — patient name, birth date, MRN, hospital, referring physician, etc.
  2. Pixel data — the actual image

When hospitals want to share DICOM data for research, AI training, or vendor evaluation, they must remove the patient identifiers first — this is required by HIPAA Safe Harbor (45 CFR §164.514(b)(2)).

But existing options are problematic:

  • Commercial tools (RSNA CTP, DicomCleaner) cost $5,000+/year
  • Cloud solutions upload patient data → HIPAA violation risk
  • DCMTK / GDCM work but have steep learning curves (C++ toolchain, complex syntax)

So I built dicom-clean to be:

  • ✅ 100% offline (air-gapped compatible)
  • ✅ Simple CLI (one command)
  • ✅ Zero-install (standalone .exe)
  • ✅ Free and open source (AGPL-3.0)

What It Does

1. Strips All 18 HIPAA Patient Identifiers

The tool blanks out 40+ scalar PHI tags and deletes 8 sequences that may carry nested PHI:

HIPAA_TAGS_TO_BLANK = ( (0x0010, 0x0010), # PatientName  (0x0010, 0x0020), # PatientID  (0x0010, 0x0030), # PatientBirthDate  (0x0010, 0x1040), # PatientAddress  (0x0008, 0x0080), # InstitutionName  (0x0008, 0x0090), # ReferringPhysicianName  # ... 40+ more ) HIPAA_TAGS_TO_REMOVE = ( (0x0008, 0x1110), # ReferencedStudySequence  (0x0008, 0x1115), # ReferencedSeriesSequence  # ... 6 more ) 

Design decision: I blank the scalar tags (preserving tag + VR) rather than deleting them, so downstream PACS and DICOM viewers don't break when they expect those fields.

2. Deterministic UID Pseudonymization

DICOM uses UIDs (Unique Identifiers) to link files together. A study has a StudyInstanceUID, each series has a SeriesInstanceUID, and each image has a SOPInstanceUID.

If you just replace these with random UUIDs, you lose the relationships between files — a PACS server won't be able to group images from the same study.

My solution: SHA-256 with an optional salt.

def pseudonymize_uid(original_uid: str, salt: str = "") -> str: """Deterministically pseudonymize a DICOM UID.""" if not original_uid: return original_uid digest = hashlib.sha256( (salt + str(original_uid)).encode("utf-8") ).hexdigest() number = int(digest[:32], 16) # 128 bits  return f"2.25.{number}" 

Why this works:

  • Deterministic — Same input + salt → same output, always
  • Reversible relationships — All files from one study get consistent pseudonyms
  • Non-reversible — Without the salt, you can't reverse it
  • Valid format — Output is a proper DICOM UID (2.25.<128-bit-int>)

3. Image Integrity

The pixel data is never touched. Same for:

  • Modality (CT, MR, US, etc.)
  • PixelData
  • TransferSyntaxUID
  • PhotometricInterpretation
  • Rows / Columns
  • BitsAllocated / BitsStored
  • PixelSpacing / SliceThickness
  • Window/Level tags

So the image looks identical in any DICOM viewer — only the metadata changes.

4. Date Reduction

HIPAA permits keeping the year but not the month/day. So:

Before: StudyDate = "20250315" After: StudyDate = "20250101" 

Tech Stack

Component Purpose
pydicom DICOM parsing & writing
Typer CLI framework
Rich Terminal UI (panels, progress bars, tables)
PyInstaller Standalone .exe build

What It Looks Like

$ dicom-clean sanitize patient.dcm output\ --salt "my-secret" 

The output shows a live progress bar and a colored summary table:

  • Total Files Scanned: 1,250
  • Successfully Anonymized: 1,248
  • Skipped (Non-DICOM): 2
  • Errors / Failed: 0

Directory Batch Processing

The tool recursively processes directories and preserves the original subfolder structure:

$ dicom-clean sanitize C:\Hospital_Data C:\Clean_Output --salt "hospital-2025" 

Robustness

  • Non-DICOM files are skipped with a warning instead of crashing
  • Per-file errors are collected into a summary
  • Uses try/except for InvalidDicomError, OSError, IOError, and generic exceptions
  • Exit code 1 if any file failed, 0 otherwise

Installation

Windows Standalone (No Python Required)

Download dicom-clean.exe from the Releases page and run:

dicom-clean.exe sanitize input.dcm output\ --salt "my-secret" 

From Source

git clone https://github.com/kaveen-ai/dicom-clean.git cd dicom-clean pip install -r requirements.txt python anonymizer.py --help 

Design Tradeoffs

Some decisions I made and why:

1. SHA-256 hashing vs random UUIDs for UIDs

  • ✅ Hash preserves relationships across files
  • ✅ Deterministic (reproducible)
  • ❌ Requires salt management for security

2. Blank tags vs delete tags

  • ✅ Blanking preserves tag structure (PACS-safe)
  • ✅ Downstream tools don't break
  • ❌ Leaves an empty tag with metadata footprint

3. AGPL-3.0 + Commercial dual-license

  • ✅ Free for open-source use
  • ✅ Commercial license funds development
  • ❌ AGPL can be a dealbreaker for some hospitals

4. Single-file CLI vs library-first

  • ✅ Standalone .exe for non-technical users
  • ✅ The core DicomAnonymizer class is importable as a library
  • ✅ CLI is just a thin Typer wrapper

The DicomAnonymizer Class

If you want to use the engine programmatically:

from anonymizer import DicomAnonymizer anonymizer = DicomAnonymizer( salt="my-hospital-secret", remove_private_tags=True, reduce_dates_to_year=True, ) summary = anonymizer.anonymize( input_path="patient.dcm", output_path="output/", ) print(f"Anonymized {summary.anonymized} files") 

The class handles:

  • UID pseudonymization
  • HIPAA tag blanking
  • Private tag removal
  • Date reduction
  • File meta sanitization

What's Next

I'm planning:

  • GitHub Actions CI — test matrix across Python 3.10-3.13
  • PyPI publication — pip install dicom-clean
  • Docker image — for hospital IT deployments
  • Pixel OCR redaction — for burned-in PHI in images (commercial edition)

Feedback Welcome

I'd love feedback from anyone working with DICOM data, healthcare IT, or medical imaging.

What would you like to see next?

Tags: python healthcare opensource dicom privacy