Research current as of July 2026
This review compares the leading open-source de-identification libraries, spanning two sub-categories:
- Free-text / unstructured PII detection & redaction — Presidio, scrubadub
- 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.
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.
-
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. -
DICOM-to-image conversion (
pl-dicom_filter) The input DICOM images are converted to PNG format using the Save as Image option ofpl-dicom_filter. This produces image files suitable for OCR-based processing while preserving the original DICOM files for later reconstruction. -
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. -
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. -
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.
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.
-
Locate text in image pixels (
pl-dcm_txtlocr) OCR is applied directly to the DICOM images usingpl-dcm_txtlocrto detect and locate burned-in text. The detected text and its locations are used to identify images that may contain protected health information (PHI). -
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. -
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. -
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.
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.
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.
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_UIDaction, applied toStudyInstanceUID/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
deidversion of this pipeline: Kitware deletes private tags by default, with no recipe line needed (opt out via--keepPrivateTagsif 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)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.
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)
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.
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:
deidhandles 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.