SimpleITK  
DicomSeriesReadModifyWrite/DicomSeriesReadModifySeriesWrite.py
1# =========================================================================
2#
3# Copyright NumFOCUS
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0.txt
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16#
17# =========================================================================
18
19""" A SimpleITK example script demonstrating how to read a DICOM series,
20 modify it, and then write a new DICOM series. """
21
22import sys
23import time
24import os
25import SimpleITK as sitk
26
27if len(sys.argv) < 3:
28 print(
29 "Usage: python "
30 + __file__
31 + " <input_directory_with_DICOM_series> <output_directory>"
32 )
33 sys.exit(1)
34
35# Read the original series. First obtain the series file names using the
36# image series reader.
37data_directory = sys.argv[1]
38series_IDs = sitk.ImageSeriesReader.GetGDCMSeriesIDs(data_directory)
39if not series_IDs:
40 print(
41 'ERROR: given directory "'
42 + data_directory
43 + '" does not contain a DICOM series.'
44 )
45 sys.exit(1)
46series_file_names = sitk.ImageSeriesReader.GetGDCMSeriesFileNames(
47 data_directory, series_IDs[0]
48)
49
50series_reader = sitk.ImageSeriesReader()
51series_reader.SetFileNames(series_file_names)
52
53# Configure the reader to load all of the DICOM tags (public+private):
54# By default tags are not loaded (saves time).
55# By default if tags are loaded, the private tags are not loaded.
56# We explicitly configure the reader to load tags, including the
57# private ones.
58series_reader.MetaDataDictionaryArrayUpdateOn()
59series_reader.LoadPrivateTagsOn()
60image3D = series_reader.Execute()
61
62# Modify the image (blurring)
63filtered_image = sitk.DiscreteGaussian(image3D)
64
65# Write the 3D image as a series
66# IMPORTANT: There are many DICOM tags that need to be updated when you modify
67# an original image. This is a delicate operation and requires
68# knowledge of the DICOM standard. This example only modifies some.
69# For a more complete list of tags that need to be modified see:
70# http://gdcm.sourceforge.net/wiki/index.php/Writing_DICOM
71
72writer = sitk.ImageFileWriter()
73# Use the study/series/frame of reference information given in the meta-data
74# dictionary and not the automatically generated information from the file IO
75writer.KeepOriginalImageUIDOn()
76
77# Copy relevant tags from the original meta-data dictionary (private tags are
78# also accessible).
79tags_to_copy = [
80 "0010|0010", # Patient Name
81 "0010|0020", # Patient ID
82 "0010|0030", # Patient Birth Date
83 "0020|000d", # Study Instance UID, for machine consumption
84 "0020|0010", # Study ID, for human consumption
85 "0008|0020", # Study Date
86 "0008|0030", # Study Time
87 "0008|0050", # Accession Number
88 "0008|0060", # Modality
89]
90
91modification_time = time.strftime("%H%M%S")
92modification_date = time.strftime("%Y%m%d")
93
94# Copy some of the tags and add the relevant tags indicating the change.
95# For the series instance UID (0020|000e), each of the components is a number,
96# cannot start with zero, and separated by a '.' We create a unique series ID
97# using the date and time.
98# NOTE: Always represent DICOM tags using lower case hexadecimals.
99# DICOM tags represent hexadecimal numbers, so 0020|000D and 0020|000d
100# are equivalent. The ITK/SimpleITK dictionary is string based, so these
101# are two different keys, case sensitive. When read from a DICOM file the
102# hexadecimal string representations are in lower case. To ensure consistency,
103# always use lower case for the tags.
104# Tags of interest:
105direction = filtered_image.GetDirection()
106series_tag_values = [
107 (k, series_reader.GetMetaData(0, k))
108 for k in tags_to_copy
109 if series_reader.HasMetaDataKey(0, k)
110] + [
111 ("0008|0031", modification_time), # Series Time
112 ("0008|0021", modification_date), # Series Date
113 ("0008|0008", "DERIVED\\SECONDARY"), # Image Type
114 (
115 "0020|000e",
116 "1.2.826.0.1.3680043.2.1125." + modification_date + ".1" + modification_time,
117 ),
118 # Series Instance UID
119 (
120 "0020|0037",
121 "\\".join(
122 map(
123 str,
124 (
125 direction[0],
126 direction[3],
127 direction[6],
128 direction[1],
129 direction[4],
130 direction[7],
131 ), # Image Orientation (Patient)
132 )
133 ),
134 ),
135 (
136 "0008|103e",
137 (
138 series_reader.GetMetaData(0, "0008|103e")
139 if series_reader.HasMetaDataKey(0, "0008|103e")
140 else "" + " Processed-SimpleITK"
141 ),
142 ), # Series Description is an optional tag, so may not exist
143]
144
145for i in range(filtered_image.GetDepth()):
146 image_slice = filtered_image[:, :, i]
147 # Tags shared by the series.
148 for tag, value in series_tag_values:
149 image_slice.SetMetaData(tag, value)
150 # Slice specific tags.
151 # Instance Creation Date
152 image_slice.SetMetaData("0008|0012", time.strftime("%Y%m%d"))
153 # Instance Creation Time
154 image_slice.SetMetaData("0008|0013", time.strftime("%H%M%S"))
155 # Image Position (Patient)
156 image_slice.SetMetaData(
157 "0020|0032",
158 "\\".join(map(str, filtered_image.TransformIndexToPhysicalPoint((0, 0, i)))),
159 )
160 # Instance Number
161 image_slice.SetMetaData("0020|0013", str(i))
162
163 # Write to the output directory and add the extension dcm, to force writing
164 # in DICOM format.
165 writer.SetFileName(os.path.join(sys.argv[2], str(i) + ".dcm"))
166 writer.Execute(image_slice)
167sys.exit(0)
Write out a SimpleITK image to the specified file location.
Read series of image files into a SimpleITK image.
SITKBasicFilters_EXPORT Image DiscreteGaussian(const Image &image1, double variance, unsigned int maximumKernelWidth=32u, double maximumError=0.01, bool useImageSpacing=true)
Blurs an image by separable convolution with discrete gaussian kernels. This filter performs Gaussian...