Skip to main content

PHI-finder

CI/CD Codecov

Local testing (docker required)

conda create -n phi-finder python==3.11
conda activate phi-finder
pip install -e .[dev,test] --no-cache-dir
pytest .

Building

python -m pip install --upgrade build

python -m build

pip install dist/phi_finder-0.1.16-py3-none-any.whl

Basic usage (headers only)

import pydicom as dicom
from phi_finder.dicom_tools import anonymise_dicom

path = "/path/to/some/dicom.dcm"
dcm = dicom.dcmread(path)
anonymised_dcm = anonymise_dicom.anonymise_image(dcm)
anonymised_dcm.save_as('/path/to/some/dicom_anon.dcm')

More advanced usage

import pydicom as dicom
from presidio_image_redactor import (
    DicomImageRedactorEngine, ImageAnalyzerEngine, ContrastSegmentedImageEnhancer)
from phi_finder.dicom_tools import anonymise_dicom

path = "/path/to/some/dicom.dcm"
dcm = dicom.dcmread(path)
score_threshold=.15
analyser = anonymise_dicom._build_presidio_analyser(score_threshold, "en_core_web_lg")
image_redactor = DicomImageRedactorEngine(
    image_analyzer_engine=ImageAnalyzerEngine(
        analyzer_engine=analyser, 
        image_preprocessor=ContrastSegmentedImageEnhancer(),
        ))
anonymised_dcm = anonymise_dicom.anonymise_image(dcm,score_threshold=score_threshold,
                                                 analyser=analyser,
                                                 image_redactor=image_redactor,
                                                 )
anonymised_dcm.save_as('/path/to/some/dicom_anon.dcm')

De-identifying a file and generating its HTML report

html_report builds a self-contained HTML report describing what was removed: the names of the scrubbed header fields, plus a before/after diff of every long free-text field (e.g. a radiology report). The snapshot must be taken before anonymise_image, which mutates the dataset in place.

import pydicom as dicom
from phi_finder.dicom_tools import anonymise_dicom, html_report

path = "/path/to/some/dicom.dcm"
dcm = dicom.dcmread(path)

# Record the free-text fields before they are redacted.
note_snapshot = html_report.snapshot_long_text(dcm)

anonymised_dcm = anonymise_dicom.anonymise_image(dcm)
anonymised_dcm.save_as('/path/to/some/dicom_anon.dcm')

report = html_report.build_html_report(
    html_report.read_flagged_headers(anonymised_dcm),
    n_images=1,
    session_id="my-session",
    use_case="Standard",
    note_diffs=html_report.collect_note_diffs(note_snapshot, anonymised_dcm),
)
with open('/path/to/some/deidentification_report.html', 'w', encoding='utf-8') as f:
    f.write(report)

note_diffs is optional — omit it (along with snapshot_long_text / collect_note_diffs) to get a report that lists only the names of the scrubbed header fields.

Warning: a report built with note_diffs reproduces the original clinical-note text, since the struck-through spans are the PHI itself.

De-identifying headers with the DICOM PS3.15 profile

The use_case argument selects how header values are de-identified:

use_case Standard headers Private headers Patient characteristics
"Standard" (default), "Aggressive", or any other value Presidio + GLiNER NER redaction Presidio + GLiNER NER redaction Sex kept; age → 000Y; birth date → year
"PS3.15" / "dicom_default" PS3.15 Basic Profile Removed Removed
"PS3.15_Rtn. Pat." / "dicom_retain_patient" PS3.15 Basic Profile Removed Kept (age, sex, size, weight, …)
"dicom_default_scan_private" PS3.15 Basic Profile NER-scrubbed (kept) Removed
"dicom_retain_patient_scan_private" PS3.15 Basic Profile NER-scrubbed (kept) Kept (age, sex, size, weight, …)

Matching is case-insensitive and separator-tolerant (see the note at the end of this section).

By default anonymise_image scans the header values with the Presidio NER pipeline (and GLiNER, when supplied). Passing use_case="PS3.15" (or its friendlier alias use_case="dicom_default") instead de-identifies the headers with the DICOM PS3.15 Annex E Basic Application Level Confidentiality Profile. In this mode the NER engines are not run on the headers.

import pydicom as dicom
from phi_finder.dicom_tools import anonymise_dicom

path = "/path/to/some/dicom.dcm"
dcm = dicom.dcmread(path)
anonymised_dcm = anonymise_dicom.anonymise_image(dcm, use_case="PS3.15")
anonymised_dcm.save_as('/path/to/some/dicom_anon.dcm')

Retain Patient Characteristics

Use use_case="PS3.15_Rtn. Pat." (or its friendlier alias use_case="dicom_retain_patient") to apply the basic profile together with the PS3.15 Retain Patient Characteristics Option. Direct identifiers (patient name, birth date, etc.) are still removed, but patient characteristics such as age, sex, size, weight, ethnic group and smoking status are kept.

import pydicom as dicom
from phi_finder.dicom_tools import anonymise_dicom

path = "/path/to/some/dicom.dcm"
dcm = dicom.dcmread(path)
anonymised_dcm = anonymise_dicom.anonymise_image(dcm, use_case="PS3.15_Rtn. Pat.")
anonymised_dcm.save_as('/path/to/some/dicom_anon.dcm')

Scanning private headers

Both DICOM modes have a _scan_private variant — use_case="dicom_default_scan_private" and use_case="dicom_retain_patient_scan_private". The standard headers are handled exactly as in the matching profile above, but instead of removing private attributes (the Basic Profile default), they are kept and their text values are scanned with the Presidio/GLiNER pipeline.

import pydicom as dicom
from phi_finder.dicom_tools import anonymise_dicom

path = "/path/to/some/dicom.dcm"
dcm = dicom.dcmread(path)
anonymised_dcm = anonymise_dicom.anonymise_image(dcm, use_case="dicom_default_scan_private")
anonymised_dcm.save_as('/path/to/some/dicom_anon.dcm')

The use_case match is case-insensitive and tolerant of separator spelling, so "PS3.15", "ps3.15", "PS3_15", "PS3-15" and the alias "dicom_default" all select the plain profile, and "PS3.15_Rtn. Pat.", "PS3.15 Retain Patient Characteristics" or the alias "dicom_retain_patient" select the retain variant. Appending _scan_private to either alias selects the private-header-scanning variant. Any other value (e.g. "Standard", or "NER Only") falls back to the Presidio/GLiNER pipeline.

Note: use_case only controls how the headers are handled. Burned-in pixel PHI is still redacted only when an image_redactor is passed, exactly as in the examples above.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

phi_finder-0.1.17.tar.gz (80.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

phi_finder-0.1.17-py3-none-any.whl (82.6 kB view details)

Uploaded Python 3

File details

Details for the file phi_finder-0.1.17.tar.gz.

File metadata

  • Download URL: phi_finder-0.1.17.tar.gz
  • Upload date:
  • Size: 80.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.11.15

File hashes

Hashes for phi_finder-0.1.17.tar.gz
Algorithm Hash digest
SHA256 9e46e98ebb1d6cb1fb8cfc28e78cf5241db7d8024e28053a9d4f67df47b8da10
MD5 add0a579b8e6fa11a49b2a1c8d20f09b
BLAKE2b-256 05df05aed2f5e4f98c344a25a9db7112b127d7d876a14d1dcb44a24e2cdf71dd

See more details on using hashes here.

File details

Details for the file phi_finder-0.1.17-py3-none-any.whl.

File metadata

  • Download URL: phi_finder-0.1.17-py3-none-any.whl
  • Upload date:
  • Size: 82.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.11.15

File hashes

Hashes for phi_finder-0.1.17-py3-none-any.whl
Algorithm Hash digest
SHA256 de34141bcc79c93d5eca060ea60db15f9dbab1da9b45f648f92be7f01fac83e3
MD5 5e90d6f1623f6b3c420f47ab00a63af8
BLAKE2b-256 6c60b00cf67143b9d591755c68cde010e22fd631d21f762a56e62ed1ce00fc9b

See more details on using hashes here.

Release history Release notifications | RSS feed

2025.8.1

2 files

2025.7.2

2 files

2025.7.1

2 files

2025.7.0

2 files

2025.6.0

2 files

2025.5.3

2 files

2025.5.2

2 files

2025.5.1

2 files

2025.5.0

2 files

0.1.18

2 files

This release

0.1.17 This release

2 files

0.1.16

2 files

0.1.15

2 files

0.1.14

2 files

0.1.13

2 files

0.1.12

2 files

0.1.11

2 files

0.1.10

2 files

0.1.9

2 files

0.1.8

2 files

0.1.7

2 files

0.1.6

2 files

0.1.5

2 files

0.1.4

2 files

0.1.3

2 files

0.1.2

2 files

0.1.1

2 files

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