Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

De-Identification / PII-Anonymization Libraries — Comparative Review

Research current as of July 2026


1. De-Identification / PII-Anonymization Libraries — Comparative Review

This review compares the leading open-source de-identification libraries, spanning two sub-categories:

  1. Free-text / unstructured PII detection & redaction — Presidio, scrubadub
  2. Clinical/healthcare & DICOM-specific de-identification — Philter, deid, dicom-anonymizer
Library License Last commit / recent activity Commit frequency Project lifespan Weekly downloads / installs Noteworthy users Community participation (issues/discussions) Speed / benchmarks Size / footprint ChRIS packaging distance Other common observations
Microsoft Presidio (Image Redactor module) MIT Active through 2026; regular releases and ongoing commits High Started 2018–2019 (~8 years) ~1M+ weekly PyPI downloads (presidio-analyzer) Microsoft, Azure samples, healthcare, finance, LLM guardrail projects Strong — active GitHub Discussions, responsive maintainers, healthy issue/PR activity Fast rule-based recognizers; GPU acceleration available for ML models Large (spaCy/Transformers, Docker, image support) 3/5 — real adapter work; handles pixels only, no metadata General-purpose PII detection for text, images, and structured data; highly extensible
scrubadub Apache-2.0¹ Last stable release 2023; limited recent activity Moderate → Low Started 2015–2016 (~10 years) Hundreds of thousands of weekly PyPI downloads IDEO, Datascope Analytics, LeapBeyond; widely used in tutorials and research Moderate — plugin ecosystem, but lower activity than Presidio Fast regex-based detection; optional NLP detectors increase runtime Lightweight 5/5 — not DICOM-aware at all; would need OCR, bounding-box, pixel-writing, and UID layers built from scratch Simple API, plugin architecture, best suited for lightweight text scrubbing
Philter BSD-3-Clause Limited ongoing maintenance; activity mainly through forks Low–Moderate Started 2018 (~8 years) No meaningful PyPI adoption UCSF, hospitals, biomedical NLP and clinical research groups Small academic community Excellent published recall on clinical PHI datasets; optimized for healthcare text Lightweight–Moderate 5/5 — not DICOM-aware at all; same gap as scrubadub Specialized for HIPAA clinical text rather than general-purpose PII
deid (PyDICOM ecosystem) MIT Active but lower-volume maintenance Moderate Started ~2018 (~8 years) No widely reported package download statistics Medical imaging researchers, radiology departments, imaging AI projects Small but active medical imaging community Designed for DICOM metadata and pixel PHI removal; no widely adopted benchmark suite Lightweight (built on pydicom) 3/5 — real adapter/container work; handles both metadata and (coordinate-based, "best effort") pixel masking Recipe-based DICOM de-identification; integrates directly with pydicom; focused on medical imaging rather than free-text PII
dicom-anonymizer (Kitware) BSD-3-Clause Maintained with occasional releases/commits; maintainers state no new features planned absent external funding Low–Moderate ~8–10 years No widely reported package download statistics Hospitals, PACS administrators, medical imaging and radiology workflows Small niche community Performance largely limited by DICOM file I/O; no standardized public benchmarks Small–Moderate (depends on pydicom or DCMTK) 2/5 — mostly adapter work; already reads/writes DICOM and implements the full PS3.15 tag-action taxonomy, metadata only Focused on anonymizing DICOM metadata (and, in some implementations, pixel data); suitable for batch imaging workflows rather than general text de-identification
pl-pfdicom_tagSub (FNNDSC/ChRIS) MIT Active, tied to FNNDSC's own plugin release cadence Tied to FNNDSC's cadence; no independent public commit-frequency data Actively developed in-house at FNNDSC N/A — not a public package, distributed as a container image ChRIS/FNNDSC itself Internal FNNDSC issue tracker, not a broad external community by design Not independently benchmarked Minimal — pure Python + pfmisc/pftree N/A — already is the artifact, not a candidate to become one Header/metadata only (no pixel handling); built-in regex tag matching (re:), MD5 hashing, deterministic pseudonym naming, string masking for date truncation, recursive directory traversal, and multithreading — all as first-class syntax rather than requiring custom code

¹ scrubadub's repository license is Apache-2.0; its setup.py incorrectly states MIT.


2. Current De-identification Workflow (with pixel scrubbing)

The current de-identification pipeline consists of five stages that together remove protected health information (PHI) from both DICOM metadata and image pixels while preserving the information required to reconstruct valid DICOM files.

  1. Header tag extraction (pl-pfdicom_tagExtract) DICOM header tags and their values are extracted from the original DICOM files. These extracted tags serve as metadata for downstream processing, including DICOM reconstruction after pixel scrubbing. The extracted metadata can also be used to determine which fields should be anonymized later in the pipeline.

  2. DICOM-to-image conversion (pl-dicom_filter) The input DICOM images are converted to PNG format using the Save as Image option of pl-dicom_filter. This produces image files suitable for OCR-based processing while preserving the original DICOM files for later reconstruction.

  3. Pixel scrubbing (pl-image_textRemove) OCR is applied to the PNG images to detect burned-in text. Using a user-specified list of DICOM tags, the plugin identifies corresponding text regions and removes or masks PHI from the image pixels, producing pixel-scrubbed images.

  4. DICOM reconstruction (pl-dicommake) New DICOM files are generated from the pixel-scrubbed images using the metadata extracted during the first step. This reconstructs valid DICOM objects along with UID remapping while incorporating the cleaned image data.

  5. Header tag anonymization (pl-pfdicom_tagSub) Finally, user-specified DICOM header fields are anonymized by replacing selected tag values with user-defined replacements. This removes or modifies sensitive metadata while preserving the overall DICOM structure and compatibility.


3. Current De-identification Workflow (without pixel scrubbing)

When pixel scrubbing is not required, the workflow focuses on identifying potentially sensitive images, filtering them as needed, anonymizing DICOM metadata, and producing minimally identifying DICOM files.

  1. Locate text in image pixels (pl-dcm_txtlocr) OCR is applied directly to the DICOM images using pl-dcm_txtlocr to detect and locate burned-in text. The detected text and its locations are used to identify images that may contain protected health information (PHI).

  2. Filter DICOMs (pl-dicom_filter) DICOM files are filtered based on the OCR results and additional user-specified criteria, such as modality, SOP Instance UID, Study/Series attributes, or other metadata filters. This allows users to exclude images that are known to contain PHI or otherwise should not be included in subsequent processing.

  3. Header tag anonymization (pl-pfdicom_tagSub) Selected DICOM header fields are anonymized by replacing user-specified tag values with user-defined replacements. This removes or modifies identifying metadata while allowing important fields to be retained in anonymized form when required.

  4. Re-DICOMization (pl-dicomize) Finally, new DICOM files are generated from the processed pixel data. During this step, Patient, Study, Series, and SOP Instance UIDs are remapped while preserving the relationships between them. All existing DICOM metadata is discarded except:

    • user-specified tags that should be retained (including those anonymized in the previous step), and
    • the minimum set of DICOM attributes required for standards-compliant DICOM files and correct pixel rendering.

    The resulting DICOM files contain only the metadata necessary for downstream visualization and analysis, minimizing the risk of exposing identifying information while preserving interoperability.


4. Proposed De-Identification Workflow (Presidio + deid Pixel Scrubbing → Kitware dicom-anonymizer Header Anonymization)

This pipeline anonymizes both DICOM metadata and image pixels, using Kitware's dicom-anonymizer for the header stage in place of deid. Per the corrected ordering, pixel redaction happens first, while the original headers are still intact, since both pixel tools use header values to improve detection.

4.1 Pixel scrubbing using known scanner templates (deid)

The original, still-identified DICOM files are processed first with deid's DicomCleaner, which detects and removes burned-in annotations using its built-in database of scanner- and manufacturer-specific pixel regions. This template-matching step relies on tags like Manufacturer, ManufacturerModelName, and modality-specific fields still being present and unmodified — which is only guaranteed if this stage runs before header anonymization. These predefined templates cover many common scanner models without requiring OCR.

4.2 OCR-based pixel scrubbing (Presidio Image Redactor)

The output of stage 1 is then processed using Microsoft Presidio Image Redactor. OCR (Tesseract) detects text within the image, while Presidio's use_metadata=True option pulls the original PatientName, PatientID, and other identifying header values to build a custom per-image recognizer — this is the specific mechanism that requires headers to still be intact at this point. Any detected sensitive text is redacted directly in the pixel data, providing a catch-all for scanners or layouts deid's coordinate database doesn't cover.

Checkpoint — intermediate PHI exposure: After stages 1–2, the files have had their pixels cleaned but their headers are still fully identified. This intermediate output must be treated as PHI throughout: written only to access-restricted scratch storage, excluded from any logging that captures file contents or paths, and deleted (not just overwritten) once stage 3 completes. Nothing downstream of this checkpoint should read from or retain this intermediate state.

4.3 Header tag anonymization (Kitware dicom-anonymizer)

The pixel-scrubbed files from stage 2 now go through Kitware's dicom-anonymizer for metadata anonymization. Since Kitware's tool doesn't ship the same built-in pseudonymization/date-shifting conveniences deid's recipe format provides, each of those behaviors is implemented explicitly:

  • Deterministic pseudonymization (PatientID, PatientName, AccessionNumber) — a custom Python action function backed by a pseudonym table (dict or persistent store) that's kept alive across the entire batch, so the same original ID always maps to the same pseudonym across every file in a study.
  • UID remapping — Kitware's built-in replace_UID action, applied to StudyInstanceUID/SeriesInstanceUID/SOPInstanceUID. Its "same UID → same replacement" guarantee only holds within a single running process, so the batch must run as one continuous process/session rather than per-file invocations, to preserve study/series relationships.
  • Date shifting — no built-in jitter, so implemented as a custom function applying a per-patient offset (derived from the same pseudonym table) to StudyDate, SeriesDate, PatientBirthDate, etc., rather than Kitware's simpler default date-anonymization behavior.
  • Private tag removal — this one is actually simpler than the deid version of this pipeline: Kitware deletes private tags by default, with no recipe line needed (opt out via --keepPrivateTags if some need to be kept).
import pydicom
from pathlib import Path
from dicomanonymizer.simpledicomanonymizer import anonymize_dataset, replace_UID

pseudonym_table = {}   # persists across the whole batch — do not reset per file
date_offset_table = {}

def pseudonymize_id(dataset, tag):
    element = dataset.get(tag)
    if element is None:
        return
    original = str(element.value)
    if original not in pseudonym_table:
        pseudonym_table[original] = f"ANON-{len(pseudonym_table) + 1:06d}"
    element.value = pseudonym_table[original]

def shift_date(dataset, tag):
    element = dataset.get(tag)
    if element is None:
        return
    patient_id = str(dataset.get((0x0010, 0x0020), "")).strip() or "unknown"
    if patient_id not in date_offset_table:
        import random
        date_offset_table[patient_id] = random.randint(-365, 365)
    offset = date_offset_table[patient_id]
    original_date = pydicom.valuerep.DA(element.value)
    from datetime import timedelta
    shifted = original_date + timedelta(days=offset)
    element.value = shifted.strftime("%Y%m%d")

extra_rules = {
    (0x0010, 0x0020): pseudonymize_id,   # PatientID
    (0x0010, 0x0010): pseudonymize_id,   # PatientName
    (0x0008, 0x0050): pseudonymize_id,   # AccessionNumber
    (0x0008, 0x0020): shift_date,        # StudyDate
    (0x0010, 0x0030): shift_date,        # PatientBirthDate
    (0x0020, 0x000D): replace_UID,       # StudyInstanceUID
    (0x0020, 0x000E): replace_UID,       # SeriesInstanceUID
}

def anonymize_headers(inputdir: str, outputdir: str):
    Path(outputdir).mkdir(parents=True, exist_ok=True)
    for dcm_path in Path(inputdir).rglob("*.dcm"):
        ds = pydicom.dcmread(str(dcm_path))
        anonymize_dataset(ds, extra_rules, delete_private_tags=True)
        ds.save_as(Path(outputdir) / dcm_path.name)

4.4 Audit log generation (pydicom)

The audit log is built directly from the pseudonym_table and date_offset_table populated during stage 3, rather than from deid's get_identifiers()/replace_identifiers() pair, since Kitware's tool doesn't produce that mapping structure natively:

import json

audit_log = {
    "id_mappings": pseudonym_table,
    "date_offsets_by_patient": date_offset_table,
}
with open("/secure/audit/audit_log.json", "w") as f:
    json.dump(audit_log, f, indent=2)

This log is the only artifact in the whole pipeline that ties original identities back to their anonymized counterparts — it must be stored separately from the anonymized dataset output, under the same access restrictions as the intermediate PHI noted after stage 2.

4.5 End-to-end workflow

DICOM in
  → [1] deid DicomCleaner (template-based pixel scrub, uses original Manufacturer/model tags)
  → [2] Presidio Image Redactor (OCR pixel scrub, uses original PatientName/PatientID for recall)
  → ⚠ intermediate: pixels clean, headers still identified — treat as PHI, restricted storage, no logging, delete after step 3
  → [3] Kitware dicom-anonymizer (header anonymization: pseudonymize IDs, shift dates, remap UIDs, strip private tags)
  → [4] audit log written from step 3's pseudonym/offset tables, stored separately
  → DICOM out (de-identified)

5. Plugin Workflow Representation

This pipeline can be implemented as a sequence of modular plugins:

Raw DICOM Dataset (headers + pixels intact)
        |
        v
+-----------------------------+
| Pixel Scrubbing             |
|                              |
| - deid DicomCleaner         |
|   (template-based, uses      |
|   original Manufacturer /    |
|   ManufacturerModelName)     |
| - Presidio Image Redactor   |
|   (OCR pixel scrub, uses     |
|   original PatientName /     |
|   PatientID for recall)      |
+-----------------------------+
        |
        v
   ⚠ intermediate: pixels clean,
     headers still identified —
     treat as PHI: restricted
     storage, no logging, delete
     after the next stage
        |
        v
+-----------------------------+
| Header Anonymization        |
|                              |
| - Kitware dicom-anonymizer  |
| - pseudonymize PatientID /   |
|   PatientName / Accession    |
| - shift dates (per-patient   |
|   offset)                    |
| - remap Study/Series/SOP     |
|   UIDs (replace_UID)         |
| - strip private tags         |
|   (default behavior)         |
+-----------------------------+
        |
        v
+-----------------------------+
| Audit Generation            |
|                              |
| - pydicom-based log built    |
|   from the header stage's    |
|   pseudonym/date-offset      |
|   tables                     |
| - stored separately from     |
|   the de-identified output   |
+-----------------------------+
        |
        v
De-identified DICOM Dataset

This diagram mirrors the end-to-end workflow in Section 4.5 exactly — pixel scrubbing first (while headers are still intact for recall), then header anonymization, then the audit log built from that stage's output.

Each stage can be independently configured, version-controlled, and executed as part of a reproducible workflow.


6. Rationale for Adopting an OSS-Based DICOM De-identification Pipeline

The primary challenge in DICOM de-identification is removing protected health information (PHI) from both metadata and image pixels while preserving the clinical value and interoperability of the data. An OSS-based de-identification pipeline addresses current limitations by providing a configurable, transparent, and maintainable solution.

Addressing current limitations:

  • Comprehensive PHI removal — Current DICOM workflows require handling multiple sources of PHI, including DICOM header tags and burned-in pixel annotations. A combination of specialized OSS tools provides broader coverage than relying on a single approach:

    • deid handles DICOM metadata anonymization, UID remapping, date transformations, and scanner-specific pixel cleaning.
    • Presidio provides OCR-based pixel text detection for cases not covered by predefined scanner templates.
  • Improved reproducibility — Recipe-based de-identification enables defining and version-controlling anonymization policies. The same DICOM transformation rules can be consistently applied across datasets, workflows, and deployments.

  • Greater auditability and transparency — OSS tools expose the underlying de-identification logic and allow workflows to maintain clear records of applied transformations. Audit logs and explicit recipes make it easier to review, validate, and troubleshoot anonymization results.

  • Scalable integration — The modular design of OSS components aligns with a plugin-based architecture. Each stage of de-identification can be executed as a discrete processing step, allowing workflows to scale from individual studies to large imaging datasets.

  • Reduced maintenance burden — Implementing custom DICOM anonymization logic from scratch would require continuous maintenance of complex standards, UID handling, metadata rules, and pixel-processing algorithms. Leveraging mature community-maintained libraries reduces duplicated effort and benefits from ongoing improvements.

  • Flexible customization for diverse use cases — Different institutions and research projects require different anonymization policies. Recipe-driven configuration allows customizing DICOM tag removal/replacement/preservation, UID generation and relationship preservation, pixel PHI detection strategies, and institution-specific compliance requirements.

Benefits: Adopting an OSS-based DICOM de-identification pipeline provides a robust foundation for privacy-preserving medical imaging workflows. It improves reliability, simplifies maintenance, and enables reproducible de-identification pipelines while preserving the flexibility required for different clinical and research scenarios. This approach supports large-scale medical imaging data sharing and analysis while maintaining transparency, extensibility, and control over the de-identification process.

About

Monorepo containing various OSS deidentification libraries and e2e anonymization pipeline scripts

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages