{"id":13673762,"url":"https://github.com/KitwareMedical/dicom-anonymizer","last_synced_at":"2025-04-28T11:30:41.920Z","repository":{"id":40261948,"uuid":"242974244","full_name":"KitwareMedical/dicom-anonymizer","owner":"KitwareMedical","description":"Tool to anonymize DICOM files according to the DICOM standard","archived":false,"fork":false,"pushed_at":"2025-01-20T14:18:59.000Z","size":163,"stargazers_count":119,"open_issues_count":8,"forks_count":50,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-04-08T12:08:06.192Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/KitwareMedical.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"custom":["https://www.kitware.eu/contact-us/","kitware.eu"]}},"created_at":"2020-02-25T10:37:52.000Z","updated_at":"2025-03-20T18:25:33.000Z","dependencies_parsed_at":"2023-11-16T17:27:57.857Z","dependency_job_id":"ff71df35-1198-453b-b700-4d37b76aef21","html_url":"https://github.com/KitwareMedical/dicom-anonymizer","commit_stats":{"total_commits":65,"total_committers":10,"mean_commits":6.5,"dds":"0.27692307692307694","last_synced_commit":"1690b78e547a3caf61fcbe880a27921ed8768bfd"},"previous_names":[],"tags_count":11,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KitwareMedical%2Fdicom-anonymizer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KitwareMedical%2Fdicom-anonymizer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KitwareMedical%2Fdicom-anonymizer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KitwareMedical%2Fdicom-anonymizer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/KitwareMedical","download_url":"https://codeload.github.com/KitwareMedical/dicom-anonymizer/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251304677,"owners_count":21567919,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-02T11:00:21.825Z","updated_at":"2025-04-28T11:30:41.192Z","avatar_url":"https://github.com/KitwareMedical.png","language":"Python","funding_links":["https://www.kitware.eu/contact-us/","kitware.eu"],"categories":["Tools","Libraries"],"sub_categories":["Tabular / structured","Python"],"readme":"# DicomAnonymizer\n\nPython package to anonymize DICOM files.\nThe anonymization answer to the standard . More information about dicom fields for anonymization can be found [here](https://dicom.nema.org/medical/dicom/current/output/html/part15.html#table_E.1-1).\n\nThe default behaviour of this package is to anonymize DICOM fields referenced in the 2023e DICOM standard. These fields are referenced in [dicomfields](dicomanonymizer/dicom_anonymization_databases/dicomfields_2023.py).  \nAnother standard can be selected, see *Change the DICOM anonymization standard*. \n\nDicom fields are separated into different groups. Each groups will be anonymized in a different way.\n\n| Group | Action | Action definition |\n| --- | --- | --- |\n| D_TAGS | replace | Replace with a non-zero length value that may be a dummy value and consistent with the VR** |\n| Z_TAGS | empty | Replace with a zero length value, or a non-zero length value that may be a dummy value and consistent with the VR** |\n| X_TAGS | delete | Completely remove the tag |\n| U_TAGS | replace_UID | Replace all UID's random ones. Same UID will have the same replaced value |\n| Z_D_TAGS | empty_or_replace | Replace with a non-zero length value that may be a dummy value and consistent with the VR** |\n| X_Z_TAGS | delete_or_empty | Replace with a zero length value, or a non-zero length value that may be a dummy value and consistent with the VR** |\n| X_D_TAGS | delete_or_replace | Replace with a non-zero length value that may be a dummy value and consistent with the VR** |\n| X_Z_D_TAGS | delete_or_empty_or_replace | Replace with a non-zero length value that may be a dummy value and consistent with the VR** |\n| X_Z_U_STAR_TAGS | delete_or_empty_or_replace_UID | If it's a UID, then all numbers are randomly replaced. Else, replace with a zero length value, or a non-zero length value that may be a dummy value and consistent with the VR**|\n| ALL_TAGS | | Contains all previous defined tags\n\n\n# How to install it?\n\nInstallation can be done via pip `pip install dicom-anonymizer` or conda `conda install -c conda-forge dicom-anonymizer`.\n\n\n# Local Development Setup\n\nTo get started with local development, follow these steps:\n\n1. Create a Virtual Environment:\n   - On Windows:\n     ```sh\n     virtualenv env\n     .\\env\\Scripts\\activate.bat\n     ```\n   - On MacOS/Linux:\n     ```sh\n     python -m venv env\n     source env/bin/activate\n     ```\n\n2. Install Dependencies:\n   - Install an editable version of the package and the development requirements:\n     ```sh\n     pip install -e .[dev]\n     ```\n\n3. Set Up Pre-Commit Hooks:\n   - Install the pre-commit hooks to ensure code quality:\n     ```sh\n     pre-commit install\n     ```\n\n\n## How to test it?\n\nTo run the unit tests, use the following command:\n\n```sh\npytest\n```\n\n\n# How to build it?\nThese instructions rely on wheel build-package format. Install it if you have not done it already using:\n`pip install wheel`\n\nThe sources files can be packaged by using:\n`python ./setup.py bdist_wheel`\n\nThis command will generate a wheel package in `dist` folder which can be then installed as a python package using\n`pip install ./dist/dicom_anonymizer-1.0.13-1-py2.py3-none-any.whl`\n\nOn Windows, if you see a warning message\n`'./dist/dicom_anonymizer-1.0.13-1-py2.py3-none-any.whl' looks like a filename, but the file does not exist`,\nthis could be due to pip not being able to handle relative path (See issue https://github.com/pypa/pip/issues/10808). As a work-around, change directory to `dist` and then install it using\n`pip install dicom_anonymizer-1.0.13-1-py2.py3-none-any.whl`\n\n\nInstalling this package will also install an executable named `dicom-anonymizer`. In order to use it, please refer to the next section.\n\n\n\n# How to use it?\n\nThis package allows to anonymize a selection of DICOM field (defined or overridden).\nThe way on how the DICOM fields are anonymized can also be overridden.\n\n- **[required]** InputPath = Full path to a single DICOM image or to a folder which contains dicom files\n- **[required]** OutputPath = Full path to the anonymized DICOM image or to a folder. This folder has to exist.\n- [optional] ActionName = Defined an action name that will be applied to the DICOM tag.\n- [optional] Dictionary = Path to a JSON file which defines actions that will be applied on specific dicom tags (see below)\n\n\n\n## Default behaviour\n\nYou can use the default anonymization behaviour describe above.\n\n```python\ndicom-anonymizer Input Output\n```\n\n\n## Private tags\n\nDefault behavior of the dicom anonymizer is to delete private tags.\nBut you can bypass it:\n- Solution 1: Use regexp to define which private tag you want to keep/update (cf [custom rules](#custom-rules))\n- Solution 2: Use dicom-anonymizer.exe option to keep all private tags : `--keepPrivateTags`\n\n\n\n## Custom rules\nYou can manually add new rules in order to have different behaviors with certain tags.\nThis will allow you to override default rules:\n\n**Executable**:\n```python\ndicom-anonymizer InputFilePath OutputFilePath -t '(0x0001, 0x0001)' ActionName -t '(0x0001, 0x0005)' ActionName2\n```\nThis will apply the `ActionName` to the tag `'(0x0001, 0x0001)'` and `ActionName2` to `'(0x0001, 0x0005)'`\n\n**Note**: ActionName has to be defined in [actions list](#actions-list)\n\nExample 1: The default behavior of the patient's ID is to be replaced by an empty or null value. If you want to keep this value, then you'll have to run :\n```python\npython anonymizer.py InputFilePath OutputFilePath -t '(0x0010, 0x0020)' keep\n```\nThis command will override the default behavior executed on this tag and the patient's ID will be kept.\n\nExample 2: We just want to change the study date from 20080701 to 20080000, then we'll use the regexp\n```python\npython anonymizer.py InputFilePath OutputFilePath -t '(0x0008, 0x0020)' 'regexp' '0701$' '0000'\n```\n\nExample 3: Change the tag value with an arbitrary value\n```python\npython anonymizer.py InputFilePath OutputFilePath -t '(0x0010, 0x0010)' 'replace_with_value' 'new_value'\n```\n\n### DICOMDIR\n\n\u003e DICOMDIR anonymization is not specified. It is therefore discouraged and it is recommended to regenerate new DICOMDIR files after anonymizing the original DICOM files.\n\nDICOMDIR files can have a `(0x0004, 0x1220)  Directory Record Sequence` tag that can contain patient information.  \nHowever, this tag is not part of the standard tag to anonymize set. If you still want dicom-anonymizer to anonymize it, you have to instruct it explicitly:\n\n```python\npython anonymizer.py InputFilePath OutputFilePath -t '(0x0004, 0x1220)' replace\n```\n\n## Custom rules with dictionary file\n\nInstead of having a big command line with several new actions, you can create your own dictionary by creating a json file `dictionary.json` :\n```json\n{\n    \"(0x0002, 0x0002)\": \"ActionName\",\n    \"(0x0003, 0x0003)\": \"ActionName\",\n    \"(0x0004, 0x0004)\": \"ActionName\",\n    \"(0x0005, 0x0005)\": \"ActionName\"\n}\n```\nSame as before, the `ActionName` has to be defined in the [actions list](#actions-list).\n\n```python\ndicom-anonymizer InputFilePath OutputFilePath --dictionary dictionary.json\n```\n\nIf you want to use the **regexp** action in a dictionary:\n```json\n{\n    \"(0x0002, 0x0002)\": \"ActionName\",\n    \"(0x0008, 0x0020)\": {\n        \"action\": \"regexp\",\n        \"find\": \"0701$\",\n        \"replace\": \"0000\"\n    }\n}\n```\n\n## Custom/overrides actions\n\nHere is a small example which keeps all metadata but updates the series description\nby adding a suffix passed as a parameter.\n\n```python\nimport argparse\nfrom dicomanonymizer import ALL_TAGS, anonymize, keep\n\n\ndef main():\n    parser = argparse.ArgumentParser(add_help=True)\n    parser.add_argument(\n        \"input\",\n        help=\"Path to the input dicom file or input directory which contains dicom files\",\n    )\n    parser.add_argument(\n        \"output\",\n        help=\"Path to the output dicom file or output directory which will contains dicom files\",\n    )\n    args = parser.parse_args()\n\n    deletePrivateTags = False\n\n    input_dicom_path = args.input\n    output_dicom_path = args.output\n\n    extra_anonymization_rules = {}\n\n    # Per https://www.hhs.gov/hipaa/for-professionals/privacy/special-topics/de-identification/index.html\n    # it is all right to retain only the year part of the birth date for\n    # de-identification purposes.\n    def set_date_to_year(dataset, tag):\n        element = dataset.get(tag)\n        if element is not None:\n            element.value = f\"{element.value[:4]}0101\" # YYYYMMDD format\n\n    # ALL_TAGS variable is defined on file dicomfields.py\n    # the 'keep' method is already defined into the dicom-anonymizer\n    # It will overrides the default behaviour\n    for i in ALL_TAGS:\n        extra_anonymization_rules[i] = keep\n\n    extra_anonymization_rules[(0x0010, 0x0030)] = set_date_to_year # Patient's Birth Date\n\n    # Launch the anonymization\n    anonymize(\n        input_dicom_path,\n        output_dicom_path,\n        extra_anonymization_rules,\n        delete_private_tags=False,\n    )\n\n\nif __name__ == \"__main__\":\n    main()\n```\n\nSee the full application in the `examples` folder.\n\nIn your own file, you'll have to define:\n- Your custom functions. Be careful, your functions always have in inputs a dataset and a tag\n- A dictionary which map your functions to a tag\n\n## Anonymize dicom tags for a dataset\n\nYou can also anonymize dicom fields in-place for pydicom's DataSet using `anonymize_dataset`. See this example:\n```python\nimport pydicom\n\nfrom dicomanonymizer import anonymize_dataset\n\ndef main():\n\n    # Create a list of tags object that should contains id, type and value\n    fields = [\n        { # Replaced by Anonymized\n        'id': (0x0040, 0xA123),\n        'type': 'LO',\n        'value': 'Annie de la Fontaine',\n        },\n        { # Replaced with empty value\n        'id': (0x0008, 0x0050),\n        'type': 'TM',\n        'value': 'bar',\n        },\n        { # Deleted\n        'id': (0x0018, 0x4000),\n        'type': 'VR',\n        'value': 'foo',\n        }\n    ]\n\n    # Create a readable dataset for pydicom\n    data = pydicom.Dataset()\n\n    # Add each field into the dataset\n    for field in fields:\n        data.add_new(field['id'], field['type'], field['value'])\n\n    anonymize_dataset(data)\n\nif __name__ == \"__main__\":\n    main()\n```\n\nSee the full application in the `examples` folder.\n\nFor more information about the pydicom's Dataset, please refer [here](https://pydicom.github.io/pydicom/stable/reference/generated/pydicom.dataset.Dataset.html).\n\nYou can also add `extra_anonymization_rules` as above:\n```python\n    anonymize_dataset(data_ds, extra_anonymization_rules, delete_private_tags=True)\n```\n\n# Actions list\n\n| Action | Action definition |\n| --- | --- |\n| empty | Replace with a zero length value, or a non-zero length value that may be a dummy value and consistent with the VR** |\n| delete | Completely remove the tag |\n| keep | Do nothing on the tag |\n| replace_UID | Replace all UID's number with a random one in order to keep consistent. Same UID will have the same replaced value |\n| empty_or_replace | Replace with a non-zero length value that may be a dummy value and consistent with the VR** |\n| delete_or_empty | Replace with a zero length value, or a non-zero length value that may be a dummy value and consistent with the VR** |\n| delete_or_replace | Replace with a non-zero length value that may be a dummy value and consistent with the VR** |\n| deleteOrEmptyOrReplace | Replace with a non-zero length value that may be a dummy value and consistent with the VR** |\n| delete_or_empty_or_replace_UID | If it's a UID, then all numbers are randomly replaced. Else, replace with a zero length value, or a non-zero length value that may be a dummy value and consistent with the VR** |\n|regexp| Find a value in the tag using a regexp and replace it with an arbitrary value. See the examples in this file to learn how to use.|\n|replace_with_value| Replace the tag value with an arbitrary value. See the examples in this file to learn how to use.\n\n\n** VR: Value Representation\n\nWork originally done by Edern Haumont\n\n# Change the DICOM anonymization standard\n\nYou can customize the DICOM standard that will be used to anonymize the dataset by giving an argument `base_rules_gen` to the function `anonymize_dicom_file` or `anonymize_dataset`.  \nThe value should be a function returning a dict of anonymization rules. Use the function `initialize_actions` to create such dict from a anonymization database from the folder `dicomanonymizer/dicom_anonymization_databases`.\n\nExample:\n```python\nfrom dicomanonymizer.simpledicomanonymizer import anonymize_dataset, initialize_actions\n\nanonymize_dataset(\n    dataset, base_rules_gen=lambda: initialize_actions(\"dicomfields_2024b\")\n)\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FKitwareMedical%2Fdicom-anonymizer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FKitwareMedical%2Fdicom-anonymizer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FKitwareMedical%2Fdicom-anonymizer/lists"}