Package: dicom-anonymizer
DicomAnonymizerPython package to anonymize DICOM files.
The anonymization answer to the standard . More information about dicom fields for anonymization can be foundhere.The default behaviour of this package is to anonymize DICOM fields referenced indicomfields.Dicom fields are separated into different groups. Each groups will be anonymized in a different way.GroupActionAction definitionD_TAGSreplaceReplace with a non-zero length value that may be a dummy value and consistent with the VR**Z_TAGSemptyReplace with a zero length value, or a non-zero length value that may be a dummy value and consistent with the VR**X_TAGSdeleteCompletely remove the tagU_TAGSreplace_UIDReplace all UID's random ones. Same UID will have the same replaced valueZ_D_TAGSempty_or_replaceReplace with a non-zero length value that may be a dummy value and consistent with the VR**X_Z_TAGSdelete_or_emptyReplace with a zero length value, or a non-zero length value that may be a dummy value and consistent with the VR**X_D_TAGSdelete_or_replaceReplace with a non-zero length value that may be a dummy value and consistent with the VR**X_Z_D_TAGSdelete_or_empty_or_replaceReplace with a non-zero length value that may be a dummy value and consistent with the VR**X_Z_U_STAR_TAGSdelete_or_empty_or_replace_UIDIf 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_TAGSContains all previous defined tagsHow to build it ?These instructions rely on wheel build-package format. Install it if you have not done it already using:pip install wheelThe sources files can be packaged by using:python ./setup.py bdist_wheelThis command will generate a wheel package indistfolder which can be then installed as a python package usingpip install ./dist/dicom_anonymizer-1.0.11-py2.py3-none-any.whlOn Windows, if you see a warning message'./dist/dicom_anonymizer-1.0.11-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 issuehttps://github.com/pypa/pip/issues/10808). As a work-around, change directory todistand then install it usingpip install dicom_anonymizer-1.0.11-py2.py3-none-any.whlInstalling this package will also install an executable nameddicom-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 behaviourYou can use the default anonymization behaviour describe above.dicom-anonymizerInputOutputPrivate tagsDefault 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 (cfcustom rules)Solution 2: Use dicom-anonymizer.exe option to keep all private tags :--keepPrivateTagsCustom rulesYou can manually add new rules in order to have different behaviors with certain tags.
This will allow you to override default rules:Executable:dicom-anonymizerInputFilePathOutputFilePath-t'(0x0001, 0x0001)'ActionName-t'(0x0001, 0x0005)'ActionName2This will apply theActionNameto the tag'(0x0001, 0x0001)'andActionName2to'(0x0001, 0x0005)'Note: ActionName has to be defined inactions listExample 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 :pythonanonymizer.pyInputFilePathOutputFilePath-t'(0x0010, 0x0020)'keepThis 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 regexppythonanonymizer.pyInputFilePathOutputFilePath-t'(0x0008, 0x0020)''regexp''0701$''0000'Custom rules with dictionary fileInstead of having a big command line with several new actions, you can create your own dictionary by creating a json filedictionary.json:{"(0x0002, 0x0002)":"ActionName","(0x0003, 0x0003)":"ActionName","(0x0004, 0x0004)":"ActionName","(0x0005, 0x0005)":"ActionName"}Same as before, theActionNamehas to be defined in theactions list.dicom-anonymizerInputFilePathOutputFilePath--dictionarydictionary.jsonIf you want to use theregexpaction in a dictionary:{"(0x0002, 0x0002)":"ActionName","(0x0008, 0x0020)":{"action":"regexp","find":"0701$","replace":"0000"}}Custom/overrides actionsHere is a small example which keeps all metadata but updates the series description
by adding a suffix passed as a parameter.importargparsefromdicomanonymizerimport*defmain():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.inputoutput_dicom_path=args.outputextraAnonymizationRules={}defsetupSeriesDescription(dataset,tag):element=dataset.get(tag)ifelementisnotNone:element.value=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 behaviourforiinallTags:extraAnonymizationRules[i]=keepifargs.suffix:extraAnonymizationRules[(0x0008,0x103E)]=setupSeriesDescription# Launch the anonymizationanonymize(input_dicom_path,output_dicom_path,extraAnonymizationRules)if__name__=="__main__":main()In your own file, you'll have to define:Your custom functions. Be careful, your functions always have in inputs a dataset and a tagA dictionary which map your functions to a tagAnonymize dicom tags without dicom fileIf for some reason, you need to anonymize dicom fields without initial dicom file (extracted from a database for example). Here is how you can do it:fromdicomanonymizerimport*defmain():# Create a list of tags object that should contains id, type and valuefields=[{# 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 pydicomdata=pydicom.Dataset()# Add each field into the datasetforfieldinfields:data.add_new(field['id'],field['type'],field['value'])anonymize_dataset(data)if__name__=="__main__":main()For more information about the pydicom's Dataset, please referhere.
You can also add a dictionary as previously :dictionary={}defnewMethod(dataset,tag):element=dataset.get(tag)ifelementisnotNone:element.value=element.value+'- generated with new method'dictionary[(0x0008,0x103E)]=newMethodanonymize_dataset(data,dictionary)Actions listActionAction definitionemptyReplace with a zero length value, or a non-zero length value that may be a dummy value and consistent with the VR**deleteCompletely remove the tagkeepDo nothing on the tagcleanDon't use it for now. This is not implementedreplace_UIDReplace all UID's number with a random one in order to keep consistent. Same UID will have the same replaced valueempty_or_replaceReplace with a non-zero length value that may be a dummy value and consistent with the VR**delete_or_emptyReplace with a zero length value, or a non-zero length value that may be a dummy value and consistent with the VR**delete_or_replaceReplace with a non-zero length value that may be a dummy value and consistent with the VR**deleteOrEmptyOrReplaceReplace with a non-zero length value that may be a dummy value and consistent with the VR**delete_or_empty_or_replace_UIDIf 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**regexpThese action is not a common action. It allows to use regexp to modify values** VR: Value RepresentationWork originally done by Edern Haumont