Skip to content

Commit 0a6dbb9

Browse files
committed
Split documentation in several files
Also add financing and state of library in README
1 parent 038cc2a commit 0a6dbb9

3 files changed

Lines changed: 318 additions & 305 deletions

File tree

README.md

Lines changed: 9 additions & 305 deletions
Original file line numberDiff line numberDiff line change
@@ -25,313 +25,17 @@ Dicom fields are separated into different groups. Each groups will be anonymized
2525

2626
`dicom-anonymizer` is designed to retain date information within DICOM files, and will anonymize them rather than removing them entirely. This approach is taken to prevent potential crashes in certain applications that rely on these dates to work. This behavior complies with the DICOM standard, as mentioned in section [E.3.6](https://dicom.nema.org/medical/dicom/current/output/html/part15.html#sect_E.3.6).
2727

28-
# How to install it?
28+
## Documentation
2929

30-
Installation can be done via pip `pip install dicom-anonymizer` or conda `conda install -c conda-forge dicom-anonymizer`.
30+
- [Installation](./doc/Setup_build_test.md)
31+
- [Usage](./doc/Usage)
3132

33+
## State of the library
3234

33-
# Local Development Setup
35+
At this present time, Kitware has no plan to implement new features in dicom-anonymizer.
36+
If you have funding to further develop this tool, feel free to reach out to Kitware.
37+
Whenever possible, Kitware will try to fix bugs that affect the use of the project and merge requests from the community will be considered, feel free to [open an issue](https://github.com/KitwareMedical/dicom-anonymizer/issues?q=is%3Aissue%20state%3Aopen%20label%3Aenhancement) to suggest new features.
3438

35-
To get started with local development, follow these steps:
39+
## Financing
3640

37-
1. Create a Virtual Environment:
38-
- On Windows:
39-
```sh
40-
virtualenv env
41-
.\env\Scripts\activate.bat
42-
```
43-
- On MacOS/Linux:
44-
```sh
45-
python -m venv env
46-
source env/bin/activate
47-
```
48-
49-
2. Install Dependencies:
50-
- Install an editable version of the package and the development requirements:
51-
```sh
52-
pip install -e .[dev]
53-
```
54-
55-
3. Set Up Pre-Commit Hooks:
56-
- Install the pre-commit hooks to ensure code quality:
57-
```sh
58-
pre-commit install
59-
```
60-
61-
62-
## How to test it?
63-
64-
To run the unit tests, use the following command:
65-
66-
```sh
67-
pytest
68-
```
69-
70-
71-
# How to build it?
72-
These instructions rely on wheel build-package format. Install it if you have not done it already using:
73-
`pip install wheel`
74-
75-
The sources files can be packaged by using:
76-
`python ./setup.py bdist_wheel`
77-
78-
This command will generate a wheel package in `dist` folder which can be then installed as a python package using
79-
`pip install ./dist/dicom_anonymizer-1.0.13-1-py2.py3-none-any.whl`
80-
81-
On Windows, if you see a warning message
82-
`'./dist/dicom_anonymizer-1.0.13-1-py2.py3-none-any.whl' looks like a filename, but the file does not exist`,
83-
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
84-
`pip install dicom_anonymizer-1.0.13-1-py2.py3-none-any.whl`
85-
86-
87-
Installing this package will also install an executable named `dicom-anonymizer`. In order to use it, please refer to the next section.
88-
89-
90-
91-
# How to use it?
92-
93-
This package allows to anonymize a selection of DICOM field (defined or overridden).
94-
The way on how the DICOM fields are anonymized can also be overridden.
95-
96-
- **[required]** InputPath = Full path to a single DICOM image or to a folder which contains dicom files
97-
- **[required]** OutputPath = Full path to the anonymized DICOM image or to a folder. This folder has to exist.
98-
- [optional] ActionName = Defined an action name that will be applied to the DICOM tag.
99-
- [optional] Dictionary = Path to a JSON file which defines actions that will be applied on specific dicom tags (see below)
100-
101-
102-
103-
## Default behaviour
104-
105-
You can use the default anonymization behaviour describe above.
106-
107-
```python
108-
dicom-anonymizer Input Output
109-
```
110-
111-
112-
## Private tags
113-
114-
Default behavior of the dicom anonymizer is to delete private tags.
115-
But you can bypass it:
116-
- Solution 1: Use regexp to define which private tag you want to keep/update (cf [custom rules](#custom-rules))
117-
- Solution 2: Use dicom-anonymizer.exe option to keep all private tags : `--keepPrivateTags`
118-
119-
120-
121-
## Custom rules
122-
You can manually add new rules in order to have different behaviors with certain tags.
123-
This will allow you to override default rules:
124-
125-
**Executable**:
126-
```python
127-
dicom-anonymizer InputFilePath OutputFilePath -t '(0x0001, 0x0001)' ActionName -t '(0x0001, 0x0005)' ActionName2
128-
```
129-
This will apply the `ActionName` to the tag `'(0x0001, 0x0001)'` and `ActionName2` to `'(0x0001, 0x0005)'`
130-
131-
**Note**: ActionName has to be defined in [actions list](#actions-list)
132-
133-
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 :
134-
```python
135-
python anonymizer.py InputFilePath OutputFilePath -t '(0x0010, 0x0020)' keep
136-
```
137-
This command will override the default behavior executed on this tag and the patient's ID will be kept.
138-
139-
Example 2: We just want to change the study date from 20080701 to 20080000, then we'll use the regexp
140-
```python
141-
python anonymizer.py InputFilePath OutputFilePath -t '(0x0008, 0x0020)' 'regexp' '0701$' '0000'
142-
```
143-
144-
Example 3: Change the tag value with an arbitrary value
145-
```python
146-
python anonymizer.py InputFilePath OutputFilePath -t '(0x0010, 0x0010)' 'replace_with_value' 'new_value'
147-
```
148-
149-
### DICOMDIR
150-
151-
> DICOMDIR anonymization is not specified. It is therefore discouraged and it is recommended to regenerate new DICOMDIR files after anonymizing the original DICOM files.
152-
153-
DICOMDIR files can have a `(0x0004, 0x1220) Directory Record Sequence` tag that can contain patient information.
154-
However, 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:
155-
156-
```python
157-
python anonymizer.py InputFilePath OutputFilePath -t '(0x0004, 0x1220)' replace
158-
```
159-
160-
## Custom rules with dictionary file
161-
162-
Instead of having a big command line with several new actions, you can create your own dictionary by creating a json file `dictionary.json` :
163-
```json
164-
{
165-
"(0x0002, 0x0002)": "ActionName",
166-
"(0x0003, 0x0003)": "ActionName",
167-
"(0x0004, 0x0004)": "ActionName",
168-
"(0x0005, 0x0005)": "ActionName"
169-
}
170-
```
171-
Same as before, the `ActionName` has to be defined in the [actions list](#actions-list).
172-
173-
```python
174-
dicom-anonymizer InputFilePath OutputFilePath --dictionary dictionary.json
175-
```
176-
177-
If you want to use the **regexp** action in a dictionary:
178-
```json
179-
{
180-
"(0x0002, 0x0002)": "ActionName",
181-
"(0x0008, 0x0020)": {
182-
"action": "regexp",
183-
"find": "0701$",
184-
"replace": "0000"
185-
}
186-
}
187-
```
188-
189-
## Custom/overrides actions
190-
191-
Here is a small example which keeps all metadata but updates the series description
192-
by adding a suffix passed as a parameter.
193-
194-
```python
195-
import argparse
196-
from dicomanonymizer import ALL_TAGS, anonymize, keep
197-
198-
199-
def main():
200-
parser = argparse.ArgumentParser(add_help=True)
201-
parser.add_argument(
202-
"input",
203-
help="Path to the input dicom file or input directory which contains dicom files",
204-
)
205-
parser.add_argument(
206-
"output",
207-
help="Path to the output dicom file or output directory which will contains dicom files",
208-
)
209-
args = parser.parse_args()
210-
211-
deletePrivateTags = False
212-
213-
input_dicom_path = args.input
214-
output_dicom_path = args.output
215-
216-
extra_anonymization_rules = {}
217-
218-
# Per https://www.hhs.gov/hipaa/for-professionals/privacy/special-topics/de-identification/index.html
219-
# it is all right to retain only the year part of the birth date for
220-
# de-identification purposes.
221-
def set_date_to_year(dataset, tag):
222-
element = dataset.get(tag)
223-
if element is not None:
224-
element.value = f"{element.value[:4]}0101" # YYYYMMDD format
225-
226-
# ALL_TAGS variable is defined on file dicomfields.py
227-
# the 'keep' method is already defined into the dicom-anonymizer
228-
# It will overrides the default behaviour
229-
for i in ALL_TAGS:
230-
extra_anonymization_rules[i] = keep
231-
232-
extra_anonymization_rules[(0x0010, 0x0030)] = set_date_to_year # Patient's Birth Date
233-
234-
# Launch the anonymization
235-
anonymize(
236-
input_dicom_path,
237-
output_dicom_path,
238-
extra_anonymization_rules,
239-
delete_private_tags=False,
240-
)
241-
242-
243-
if __name__ == "__main__":
244-
main()
245-
```
246-
247-
See the full application in the `examples` folder.
248-
249-
In your own file, you'll have to define:
250-
- Your custom functions. Be careful, your functions always have in inputs a dataset and a tag
251-
- A dictionary which map your functions to a tag
252-
253-
## Anonymize dicom tags for a dataset
254-
255-
You can also anonymize dicom fields in-place for pydicom's DataSet using `anonymize_dataset`. See this example:
256-
```python
257-
import pydicom
258-
259-
from dicomanonymizer import anonymize_dataset
260-
261-
def main():
262-
263-
# Create a list of tags object that should contains id, type and value
264-
fields = [
265-
{ # Replaced by Anonymized
266-
'id': (0x0040, 0xA123),
267-
'type': 'LO',
268-
'value': 'Annie de la Fontaine',
269-
},
270-
{ # Replaced with empty value
271-
'id': (0x0008, 0x0050),
272-
'type': 'TM',
273-
'value': 'bar',
274-
},
275-
{ # Deleted
276-
'id': (0x0018, 0x4000),
277-
'type': 'VR',
278-
'value': 'foo',
279-
}
280-
]
281-
282-
# Create a readable dataset for pydicom
283-
data = pydicom.Dataset()
284-
285-
# Add each field into the dataset
286-
for field in fields:
287-
data.add_new(field['id'], field['type'], field['value'])
288-
289-
anonymize_dataset(data)
290-
291-
if __name__ == "__main__":
292-
main()
293-
```
294-
295-
See the full application in the `examples` folder.
296-
297-
For more information about the pydicom's Dataset, please refer [here](https://pydicom.github.io/pydicom/stable/reference/generated/pydicom.dataset.Dataset.html).
298-
299-
You can also add `extra_anonymization_rules` as above:
300-
```python
301-
anonymize_dataset(data_ds, extra_anonymization_rules, delete_private_tags=True)
302-
```
303-
304-
# Actions list
305-
306-
| Action | Action definition |
307-
| --- | --- |
308-
| empty | Replace with a zero length value, or a non-zero length value that may be a dummy value and consistent with the VR** |
309-
| delete | Completely remove the tag |
310-
| keep | Do nothing on the tag |
311-
| replace_UID | Replace all UID's number with a random one in order to keep consistent. Same UID will have the same replaced value |
312-
| empty_or_replace | Replace with a non-zero length value that may be a dummy value and consistent with the VR** |
313-
| 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** |
314-
| delete_or_replace | Replace with a non-zero length value that may be a dummy value and consistent with the VR** |
315-
| deleteOrEmptyOrReplace | Replace with a non-zero length value that may be a dummy value and consistent with the VR** |
316-
| 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** |
317-
|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.|
318-
|replace_with_value| Replace the tag value with an arbitrary value. See the examples in this file to learn how to use.
319-
320-
321-
** VR: Value Representation
322-
323-
Work originally done by Edern Haumont
324-
325-
# Change the DICOM anonymization standard
326-
327-
You 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`.
328-
The 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`.
329-
330-
Example:
331-
```python
332-
from dicomanonymizer.simpledicomanonymizer import anonymize_dataset, initialize_actions
333-
334-
anonymize_dataset(
335-
dataset, base_rules_gen=lambda: initialize_actions("dicomfields_2024b")
336-
)
337-
```
41+
If you want a new feature in dicom-anonymizer or help manipulating DICOM files, feel free to reach out to us at contact@kitware.fr.

doc/Setup_build_test.md

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# Installation
2+
3+
### Binary installation
4+
5+
Installation can be done via pip `pip install dicom-anonymizer` or conda `conda install -c conda-forge dicom-anonymizer`.
6+
7+
8+
### Local Development Setup
9+
10+
To get started with local development, follow these steps:
11+
12+
1. Create a Virtual Environment:
13+
- On Windows:
14+
```sh
15+
virtualenv env
16+
.\env\Scripts\activate.bat
17+
```
18+
- On MacOS/Linux:
19+
```sh
20+
python -m venv env
21+
source env/bin/activate
22+
```
23+
24+
2. Install Dependencies:
25+
- Install an editable version of the package and the development requirements:
26+
```sh
27+
pip install -e .[dev]
28+
```
29+
30+
3. Set Up Pre-Commit Hooks:
31+
- Install the pre-commit hooks to ensure code quality:
32+
```sh
33+
pre-commit install
34+
```
35+
36+
37+
## Testing
38+
39+
To run the unit tests, use the following command:
40+
41+
```sh
42+
pytest
43+
```
44+
45+
46+
## Building
47+
48+
These instructions rely on wheel build-package format. Install it if you have not done it already using:
49+
`pip install wheel`
50+
51+
The sources files can be packaged by using:
52+
`python ./setup.py bdist_wheel`
53+
54+
This command will generate a wheel package in `dist` folder which can be then installed as a python package using
55+
`pip install ./dist/dicom_anonymizer-1.0.13-1-py2.py3-none-any.whl`
56+
57+
On Windows, if you see a warning message
58+
`'./dist/dicom_anonymizer-1.0.13-1-py2.py3-none-any.whl' looks like a filename, but the file does not exist`,
59+
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
60+
`pip install dicom_anonymizer-1.0.13-1-py2.py3-none-any.whl`
61+
62+
63+
Installing this package will also install an executable named `dicom-anonymizer`. In order to use it, please refer to the next section.

0 commit comments

Comments
 (0)