dicom-anonymizer


Namedicom-anonymizer JSON
Version 1.0.12 PyPI version JSON
download
home_pageNone
SummaryProgram to anonymize dicom files with default and custom rules
upload_time2024-03-26 13:22:34
maintainerNone
docs_urlNone
authorNone
requires_python>=3.8
licenseNone
keywords dicom anonymizer medical
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # DicomAnonymizer

Python package to anonymize DICOM files.
The anonymization answer to the standard . More information about dicom fields for anonymization can be found [here](http://dicom.nema.org/dicom/2013/output/chtml/part15/chapter_E.html#table_E.1-1).

The default behaviour of this package is to anonymize DICOM fields referenced in [dicomfields](dicomanonymizer/dicomfields.py).

Dicom fields are separated into different groups. Each groups will be anonymized in a different way.

| Group | Action | Action definition |
| --- | --- | --- |
| D_TAGS | replace | Replace with a non-zero length value that may be a dummy value and consistent with the VR** |
| 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** |
| X_TAGS | delete | Completely remove the tag |
| U_TAGS | replace_UID | Replace all UID's random ones. Same UID will have the same replaced value |
| Z_D_TAGS | empty_or_replace | Replace with a non-zero length value that may be a dummy value and consistent with the VR** |
| 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** |
| X_D_TAGS | delete_or_replace | Replace with a non-zero length value that may be a dummy value and consistent with the VR** |
| 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** |
| 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**|
| ALL_TAGS | | Contains all previous defined tags


# How to install it?

Installation can be done via pip `pip install dicom-anonymizer` or conda `conda install -c conda-forge dicom-anonymizer`.

# How to test it?
- One time set up:
  - virtual environment for this package and activate it. For
  example set up using `virtualenv venv` and activate using
  `venv\Scripts\activate.bat` (on Windows)
  - Install editable version and development requirements using
  `pip install -e .[dev]`
- Run unit test using `pytest`

# How to build it?
These instructions rely on wheel build-package format. Install it if you have not done it already using:
`pip install wheel`

The sources files can be packaged by using:
`python ./setup.py bdist_wheel`

This command will generate a wheel package in `dist` folder which can be then installed as a python package using
`pip install ./dist/dicom_anonymizer-1.0.12-py2.py3-none-any.whl`

On Windows, if you see a warning message
`'./dist/dicom_anonymizer-1.0.12-py2.py3-none-any.whl' looks like a filename, but the file does not exist`,
this 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
`pip install dicom_anonymizer-1.0.12-py2.py3-none-any.whl`


Installing this package will also install an executable named `dicom-anonymizer`. In order to use it, please refer to the next section.



# How to use it?

This package allows to anonymize a selection of DICOM field (defined or overridden).
The way on how the DICOM fields are anonymized can also be overridden.

- **[required]** InputPath = Full path to a single DICOM image or to a folder which contains dicom files
- **[required]** OutputPath = Full path to the anonymized DICOM image or to a folder. This folder has to exist.
- [optional] ActionName = Defined an action name that will be applied to the DICOM tag.
- [optional] Dictionary = Path to a JSON file which defines actions that will be applied on specific dicom tags (see below)



## Default behaviour

You can use the default anonymization behaviour describe above.

```python
dicom-anonymizer Input Output
```


## Private tags

Default behavior of the dicom anonymizer is to delete private tags.
But you can bypass it:
- Solution 1: Use regexp to define which private tag you want to keep/update (cf [custom rules](#custom-rules))
- Solution 2: Use dicom-anonymizer.exe option to keep all private tags : `--keepPrivateTags`



## Custom rules
You can manually add new rules in order to have different behaviors with certain tags.
This will allow you to override default rules:

**Executable**:
```python
dicom-anonymizer InputFilePath OutputFilePath -t '(0x0001, 0x0001)' ActionName -t '(0x0001, 0x0005)' ActionName2
```
This will apply the `ActionName` to the tag `'(0x0001, 0x0001)'` and `ActionName2` to `'(0x0001, 0x0005)'`

**Note**: ActionName has to be defined in [actions list](#actions-list)

Example 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 :
```python
python anonymizer.py InputFilePath OutputFilePath -t '(0x0010, 0x0020)' keep
```
This command will override the default behavior executed on this tag and the patient's ID will be kept.

Example 2: We just want to change the study date from 20080701 to 20080000, then we'll use the regexp
```python
python anonymizer.py InputFilePath OutputFilePath -t '(0x0008, 0x0020)' 'regexp' '0701$' '0000'
```


## Custom rules with dictionary file

Instead of having a big command line with several new actions, you can create your own dictionary by creating a json file `dictionary.json` :
```json
{
    "(0x0002, 0x0002)": "ActionName",
    "(0x0003, 0x0003)": "ActionName",
    "(0x0004, 0x0004)": "ActionName",
    "(0x0005, 0x0005)": "ActionName"
}
```
Same as before, the `ActionName` has to be defined in the [actions list](#actions-list).

```python
dicom-anonymizer InputFilePath OutputFilePath --dictionary dictionary.json
```

If you want to use the **regexp** action in a dictionary:
```json
{
    "(0x0002, 0x0002)": "ActionName",
    "(0x0008, 0x0020)": {
        "action": "regexp",
        "find": "0701$",
        "replace": "0000"
    }
}
```

## Custom/overrides actions

Here is a small example which keeps all metadata but updates the series description
by adding a suffix passed as a parameter.

```python
import argparse
from dicomanonymizer import ALL_TAGS, anonymize, keep

def main():
    parser = argparse.ArgumentParser(add_help=True)
    parser.add_argument('input', help='Path to the input dicom file or input directory which contains dicom files')
    parser.add_argument('output', help='Path to the output dicom file or output directory which will contains dicom files')
    parser.add_argument('--suffix', action='store', help='Suffix that will be added at the end of series description')
    args = parser.parse_args()

    input_dicom_path = args.input
    output_dicom_path = args.output

    extra_anonymization_rules = {}

    def setup_series_description(dataset, tag):
        element = dataset.get(tag)
        if element is not None:
            element.value = f'{element.value}-{args.suffix}'

    # ALL_TAGS variable is defined on file dicomfields.py
    # the 'keep' method is already defined into the dicom-anonymizer
    # It will overrides the default behaviour
    for i in ALL_TAGS:
        extra_anonymization_rules[i] = keep

    if args.suffix:
        extra_anonymization_rules[(0x0008, 0x103E)] = setup_series_description

    # Launch the anonymization
    anonymize(input_dicom_path, output_dicom_path, extra_anonymization_rules, delete_private_tags=False)

if __name__ == '__main__':
    main()
```

See the full application in the `examples` folder.

In your own file, you'll have to define:
- Your custom functions. Be careful, your functions always have in inputs a dataset and a tag
- A dictionary which map your functions to a tag

## Anonymize dicom tags for a dataset

You can also anonymize dicom fields in-place for pydicom's DataSet using `anonymize_dataset`. See this example:
```python
import pydicom

from dicomanonymizer import anonymize_dataset

def main():

    # Create a list of tags object that should contains id, type and value
    fields = [
        { # Replaced by Anonymized
        'id': (0x0040, 0xA123),
        'type': 'LO',
        'value': 'Annie de la Fontaine',
        },
        { # Replaced with empty value
        'id': (0x0008, 0x0050),
        'type': 'TM',
        'value': 'bar',
        },
        { # Deleted
        'id': (0x0018, 0x4000),
        'type': 'VR',
        'value': 'foo',
        }
    ]

    # Create a readable dataset for pydicom
    data = pydicom.Dataset()

    # Add each field into the dataset
    for field in fields:
        data.add_new(field['id'], field['type'], field['value'])

    anonymize_dataset(data)

if __name__ == "__main__":
    main()
```

See the full application in the `examples` folder.

For more information about the pydicom's Dataset, please refer [here](https://pydicom.github.io/pydicom/stable/reference/generated/pydicom.dataset.Dataset.html).

You can also add `extra_anonymization_rules` as above:
```python
    anonymize_dataset(data_ds, extra_anonymization_rules, delete_private_tags=True)
```

# Actions list

| Action | Action definition |
| --- | --- |
| empty | Replace with a zero length value, or a non-zero length value that may be a dummy value and consistent with the VR** |
| delete | Completely remove the tag |
| keep | Do nothing on the tag |
| clean | Don't use it for now. This is not implemented |
| replace_UID | Replace all UID's number with a random one in order to keep consistent. Same UID will have the same replaced value |
| empty_or_replace | Replace with a non-zero length value that may be a dummy value and consistent with the VR** |
| 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** |
| delete_or_replace | Replace with a non-zero length value that may be a dummy value and consistent with the VR** |
| deleteOrEmptyOrReplace | Replace with a non-zero length value that may be a dummy value and consistent with the VR** |
| 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** |
|regexp| These action is not a common action. It allows to use regexp to modify values|


** VR: Value Representation

Work originally done by Edern Haumont

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "dicom-anonymizer",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.8",
    "maintainer_email": null,
    "keywords": "dicom, anonymizer, medical",
    "author": null,
    "author_email": "Laurenn Lam <laurenn.lam@kitware.com>",
    "download_url": "https://files.pythonhosted.org/packages/8c/65/4a5463d1efa2510dc58b4fba0c574e1d9b0d5819989ca0de7640e2beef8c/dicom_anonymizer-1.0.12.tar.gz",
    "platform": null,
    "description": "# 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](http://dicom.nema.org/dicom/2013/output/chtml/part15/chapter_E.html#table_E.1-1).\n\nThe default behaviour of this package is to anonymize DICOM fields referenced in [dicomfields](dicomanonymizer/dicomfields.py).\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# How to test it?\n- One time set up:\n  - virtual environment for this package and activate it. For\n  example set up using `virtualenv venv` and activate using\n  `venv\\Scripts\\activate.bat` (on Windows)\n  - Install editable version and development requirements using\n  `pip install -e .[dev]`\n- Run unit test using `pytest`\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.12-py2.py3-none-any.whl`\n\nOn Windows, if you see a warning message\n`'./dist/dicom_anonymizer-1.0.12-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.12-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\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\ndef main():\n    parser = argparse.ArgumentParser(add_help=True)\n    parser.add_argument('input', help='Path to the input dicom file or input directory which contains dicom files')\n    parser.add_argument('output', help='Path to the output dicom file or output directory which will contains dicom files')\n    parser.add_argument('--suffix', action='store', help='Suffix that will be added at the end of series description')\n    args = parser.parse_args()\n\n    input_dicom_path = args.input\n    output_dicom_path = args.output\n\n    extra_anonymization_rules = {}\n\n    def setup_series_description(dataset, tag):\n        element = dataset.get(tag)\n        if element is not None:\n            element.value = f'{element.value}-{args.suffix}'\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    if args.suffix:\n        extra_anonymization_rules[(0x0008, 0x103E)] = setup_series_description\n\n    # Launch the anonymization\n    anonymize(input_dicom_path, output_dicom_path, extra_anonymization_rules, delete_private_tags=False)\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| clean | Don't use it for now. This is not implemented |\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| These action is not a common action. It allows to use regexp to modify values|\n\n\n** VR: Value Representation\n\nWork originally done by Edern Haumont\n",
    "bugtrack_url": null,
    "license": null,
    "summary": "Program to anonymize dicom files with default and custom rules",
    "version": "1.0.12",
    "project_urls": {
        "Bug Tracker": "https://github.com/KitwareMedical/dicom-anonymizer/issues",
        "Homepage": "https://github.com/KitwareMedical/dicom-anonymizer"
    },
    "split_keywords": [
        "dicom",
        " anonymizer",
        " medical"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "4dafbf9bed1d1fb236082fd19aecee7bd4f84f11a8d22898b2529bc83b59ce71",
                "md5": "276d7835f006e75a13225c043428bffb",
                "sha256": "3593555f11ba7cbe910b949bca67b30e21292632d1942f2e2b580942764de1c7"
            },
            "downloads": -1,
            "filename": "dicom_anonymizer-1.0.12-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "276d7835f006e75a13225c043428bffb",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.8",
            "size": 25441,
            "upload_time": "2024-03-26T13:22:32",
            "upload_time_iso_8601": "2024-03-26T13:22:32.516511Z",
            "url": "https://files.pythonhosted.org/packages/4d/af/bf9bed1d1fb236082fd19aecee7bd4f84f11a8d22898b2529bc83b59ce71/dicom_anonymizer-1.0.12-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "8c654a5463d1efa2510dc58b4fba0c574e1d9b0d5819989ca0de7640e2beef8c",
                "md5": "117d4fb102ce0b3999566819147c5fb9",
                "sha256": "2318a8c06e7f655d6d7920471a60a0369a05f9079dfdff8875274b0cbd3756a5"
            },
            "downloads": -1,
            "filename": "dicom_anonymizer-1.0.12.tar.gz",
            "has_sig": false,
            "md5_digest": "117d4fb102ce0b3999566819147c5fb9",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.8",
            "size": 23138,
            "upload_time": "2024-03-26T13:22:34",
            "upload_time_iso_8601": "2024-03-26T13:22:34.283869Z",
            "url": "https://files.pythonhosted.org/packages/8c/65/4a5463d1efa2510dc58b4fba0c574e1d9b0d5819989ca0de7640e2beef8c/dicom_anonymizer-1.0.12.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-03-26 13:22:34",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "KitwareMedical",
    "github_project": "dicom-anonymizer",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "dicom-anonymizer"
}
        
Elapsed time: 0.43818s