<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: kaveen</title>
    <description>The latest articles on DEV Community by kaveen (@kaveenai).</description>
    <link>https://dev.to/kaveenai</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4173950%2F72455eb1-c13a-400d-97ed-79cdedf69741.jpg</url>
      <title>DEV Community: kaveen</title>
      <link>https://dev.to/kaveenai</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kaveenai"/>
    <language>en</language>
    <item>
      <title>[OC] I built a free, open-source HIPAA DICOM anonymizer for medical imaging</title>
      <dc:creator>kaveen</dc:creator>
      <pubDate>Fri, 09 Oct 2026 18:07:12 +0000</pubDate>
      <link>https://dev.to/kaveenai/oc-i-built-a-free-open-source-hipaa-dicom-anonymizer-for-medical-imaging-1emi</link>
      <guid>https://dev.to/kaveenai/oc-i-built-a-free-open-source-hipaa-dicom-anonymizer-for-medical-imaging-1emi</guid>
      <description>&lt;p&gt;I just released &lt;strong&gt;dicom-clean&lt;/strong&gt; — an open-source CLI tool for HIPAA-compliant DICOM de-identification. Here's how it works and why I built it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;Medical imaging files (CT scans, MRIs, X-rays) use a format called &lt;strong&gt;DICOM&lt;/strong&gt;, which contains two things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Metadata&lt;/strong&gt; — patient name, birth date, MRN, hospital, referring physician, etc.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pixel data&lt;/strong&gt; — the actual image&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;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)).&lt;/p&gt;

&lt;p&gt;But existing options are problematic:&lt;/p&gt;

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

&lt;p&gt;So I built &lt;strong&gt;dicom-clean&lt;/strong&gt; to be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ &lt;strong&gt;100% offline&lt;/strong&gt; (air-gapped compatible)&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Simple CLI&lt;/strong&gt; (one command)&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Zero-install&lt;/strong&gt; (standalone &lt;code&gt;.exe&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Free and open source&lt;/strong&gt; (AGPL-3.0)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What It Does
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Strips All 18 HIPAA Patient Identifiers
&lt;/h3&gt;

&lt;p&gt;The tool blanks out 40+ scalar PHI tags and deletes 8 sequences that may carry nested PHI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;HIPAA_TAGS_TO_BLANK&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mh"&gt;0x0010&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0x0010&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;  &lt;span class="c1"&gt;# PatientName
&lt;/span&gt;    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mh"&gt;0x0010&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0x0020&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;  &lt;span class="c1"&gt;# PatientID
&lt;/span&gt;    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mh"&gt;0x0010&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0x0030&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;  &lt;span class="c1"&gt;# PatientBirthDate
&lt;/span&gt;    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mh"&gt;0x0010&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0x1040&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;  &lt;span class="c1"&gt;# PatientAddress
&lt;/span&gt;    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mh"&gt;0x0008&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0x0080&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;  &lt;span class="c1"&gt;# InstitutionName
&lt;/span&gt;    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mh"&gt;0x0008&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0x0090&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;  &lt;span class="c1"&gt;# ReferringPhysicianName
&lt;/span&gt;    &lt;span class="c1"&gt;# ... 40+ more
&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;HIPAA_TAGS_TO_REMOVE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mh"&gt;0x0008&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0x1110&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;  &lt;span class="c1"&gt;# ReferencedStudySequence
&lt;/span&gt;    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mh"&gt;0x0008&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mh"&gt;0x1115&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;  &lt;span class="c1"&gt;# ReferencedSeriesSequence
&lt;/span&gt;    &lt;span class="c1"&gt;# ... 6 more
&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;h3&gt;
  
  
  2. Deterministic UID Pseudonymization
&lt;/h3&gt;

&lt;p&gt;DICOM uses &lt;strong&gt;UIDs&lt;/strong&gt; (Unique Identifiers) to link files together. A study has a &lt;code&gt;StudyInstanceUID&lt;/code&gt;, each series has a &lt;code&gt;SeriesInstanceUID&lt;/code&gt;, and each image has a &lt;code&gt;SOPInstanceUID&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;My solution: &lt;strong&gt;SHA-256 with an optional salt&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;pseudonymize_uid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;original_uid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;salt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Deterministically pseudonymize a DICOM UID.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;original_uid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;original_uid&lt;/span&gt;
    &lt;span class="n"&gt;digest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hashlib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sha256&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;salt&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;original_uid&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;hexdigest&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;digest&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# 128 bits
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2.25.&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;number&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why this works:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Deterministic&lt;/strong&gt; — Same input + salt → same output, always&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reversible relationships&lt;/strong&gt; — All files from one study get consistent pseudonyms&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Non-reversible&lt;/strong&gt; — Without the salt, you can't reverse it&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Valid format&lt;/strong&gt; — Output is a proper DICOM UID (&lt;code&gt;2.25.&amp;lt;128-bit-int&amp;gt;&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Image Integrity
&lt;/h3&gt;

&lt;p&gt;The pixel data is &lt;strong&gt;never touched&lt;/strong&gt;. Same for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Modality&lt;/code&gt; (CT, MR, US, etc.)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PixelData&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;TransferSyntaxUID&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PhotometricInterpretation&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Rows&lt;/code&gt; / &lt;code&gt;Columns&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;BitsAllocated&lt;/code&gt; / &lt;code&gt;BitsStored&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;PixelSpacing&lt;/code&gt; / &lt;code&gt;SliceThickness&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Window/Level tags&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So the image looks identical in any DICOM viewer — only the metadata changes.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Date Reduction
&lt;/h3&gt;

&lt;p&gt;HIPAA permits keeping the year but not the month/day. So:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="p"&gt;Before: StudyDate = "20250315"
After:  StudyDate = "20250101"
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Tech Stack
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;pydicom&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;DICOM parsing &amp;amp; writing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Typer&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;CLI framework&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Rich&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Terminal UI (panels, progress bars, tables)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;PyInstaller&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Standalone &lt;code&gt;.exe&lt;/code&gt; build&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  What It Looks Like
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;dicom-clean sanitize patient.dcm output&lt;span class="se"&gt;\ &lt;/span&gt;&lt;span class="nt"&gt;--salt&lt;/span&gt; &lt;span class="s2"&gt;"my-secret"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output shows a live progress bar and a colored summary table:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Total Files Scanned: 1,250&lt;/li&gt;
&lt;li&gt;Successfully Anonymized: 1,248&lt;/li&gt;
&lt;li&gt;Skipped (Non-DICOM): 2&lt;/li&gt;
&lt;li&gt;Errors / Failed: 0&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Directory Batch Processing
&lt;/h2&gt;

&lt;p&gt;The tool recursively processes directories and preserves the original subfolder structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;dicom-clean sanitize C:&lt;span class="se"&gt;\H&lt;/span&gt;ospital_Data C:&lt;span class="se"&gt;\C&lt;/span&gt;lean_Output &lt;span class="nt"&gt;--salt&lt;/span&gt; &lt;span class="s2"&gt;"hospital-2025"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Robustness
&lt;/h2&gt;

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

&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Windows Standalone (No Python Required)
&lt;/h3&gt;

&lt;p&gt;Download &lt;code&gt;dicom-clean.exe&lt;/code&gt; from the &lt;a href="https://github.com/kaveen-ai/dicom-clean/releases" rel="noopener noreferrer"&gt;Releases page&lt;/a&gt; and run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dicom-clean.exe sanitize input.dcm output\ --salt "my-secret"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  From Source
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/kaveen-ai/dicom-clean.git
&lt;span class="nb"&gt;cd &lt;/span&gt;dicom-clean
pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt
python anonymizer.py &lt;span class="nt"&gt;--help&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Design Tradeoffs
&lt;/h2&gt;

&lt;p&gt;Some decisions I made and why:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. SHA-256 hashing vs random UUIDs for UIDs&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Hash preserves relationships across files&lt;/li&gt;
&lt;li&gt;✅ Deterministic (reproducible)&lt;/li&gt;
&lt;li&gt;❌ Requires salt management for security&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;2. Blank tags vs delete tags&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Blanking preserves tag structure (PACS-safe)&lt;/li&gt;
&lt;li&gt;✅ Downstream tools don't break&lt;/li&gt;
&lt;li&gt;❌ Leaves an empty tag with metadata footprint&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;3. AGPL-3.0 + Commercial dual-license&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Free for open-source use&lt;/li&gt;
&lt;li&gt;✅ Commercial license funds development&lt;/li&gt;
&lt;li&gt;❌ AGPL can be a dealbreaker for some hospitals&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;4. Single-file CLI vs library-first&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Standalone &lt;code&gt;.exe&lt;/code&gt; for non-technical users&lt;/li&gt;
&lt;li&gt;✅ The core &lt;code&gt;DicomAnonymizer&lt;/code&gt; class is importable as a library&lt;/li&gt;
&lt;li&gt;✅ CLI is just a thin Typer wrapper&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The &lt;code&gt;DicomAnonymizer&lt;/code&gt; Class
&lt;/h2&gt;

&lt;p&gt;If you want to use the engine programmatically:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;anonymizer&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;DicomAnonymizer&lt;/span&gt;

&lt;span class="n"&gt;anonymizer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;DicomAnonymizer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;salt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;my-hospital-secret&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;remove_private_tags&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;reduce_dates_to_year&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;summary&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;anonymizer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;anonymize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;input_path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;patient.dcm&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;output_path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;output/&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Anonymized &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;summary&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;anonymized&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; files&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The class handles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;UID pseudonymization&lt;/li&gt;
&lt;li&gt;HIPAA tag blanking&lt;/li&gt;
&lt;li&gt;Private tag removal&lt;/li&gt;
&lt;li&gt;Date reduction&lt;/li&gt;
&lt;li&gt;File meta sanitization&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;p&gt;I'm planning:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GitHub Actions CI&lt;/strong&gt; — test matrix across Python 3.10-3.13&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PyPI publication&lt;/strong&gt; — &lt;code&gt;pip install dicom-clean&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Docker image&lt;/strong&gt; — for hospital IT deployments&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pixel OCR redaction&lt;/strong&gt; — for burned-in PHI in images (commercial edition)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Feedback Welcome
&lt;/h2&gt;

&lt;p&gt;I'd love feedback from anyone working with DICOM data, healthcare IT, or medical imaging.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Star on GitHub:&lt;/strong&gt; &lt;a href="https://github.com/kaveen-ai/dicom-clean" rel="noopener noreferrer"&gt;github.com/kaveen-ai/dicom-clean&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Report bugs:&lt;/strong&gt; &lt;a href="https://github.com/kaveen-ai/dicom-clean/issues" rel="noopener noreferrer"&gt;Issues&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Discussions:&lt;/strong&gt; &lt;a href="https://github.com/kaveen-ai/dicom-clean/discussions" rel="noopener noreferrer"&gt;GitHub Discussions&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What would you like to see next?&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Tags:&lt;/strong&gt; &lt;code&gt;python&lt;/code&gt; &lt;code&gt;healthcare&lt;/code&gt; &lt;code&gt;opensource&lt;/code&gt; &lt;code&gt;dicom&lt;/code&gt; &lt;code&gt;privacy&lt;/code&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>opensource</category>
      <category>privacy</category>
      <category>healthcare</category>
    </item>
  </channel>
</rss>
