Commit ef8b84edbfe331b67c8d7fb1c7ca3e1ed0512575
1 parent
96833c49
Exists in
master
and in
6 other branches
ENH: Replaced the way it reads some data, changed of vtkgdcm to gdcm reader DICOM tags.
Showing
1 changed file
with
210 additions
and
201 deletions
Show diff stats
invesalius/reader/dicom.py
@@ -94,6 +94,213 @@ class Parser(): | @@ -94,6 +94,213 @@ class Parser(): | ||
94 | self.encoding = "" | 94 | self.encoding = "" |
95 | self.vtkgdcm_reader = vtkgdcm.vtkGDCMImageReader() | 95 | self.vtkgdcm_reader = vtkgdcm.vtkGDCMImageReader() |
96 | 96 | ||
97 | + def SetFileName(self, filename): | ||
98 | + """ | ||
99 | + Set file name to be parsed given its filename (this should | ||
100 | + include the full path of the file of interest). | ||
101 | + | ||
102 | + Return True/False if file could be read. | ||
103 | + """ | ||
104 | + import os.path as path | ||
105 | + | ||
106 | + | ||
107 | + filename = path.abspath(filename) | ||
108 | + | ||
109 | + if (sys.platform == 'win32'): | ||
110 | + filename = filename.encode('latin-1') | ||
111 | + | ||
112 | + if path.isfile(filename): | ||
113 | + # Several information can be acquired from DICOM using | ||
114 | + # vtkgdcm.vtkGDCMImageReader.GetMedicalImageProperties() | ||
115 | + # but some tags (such as spacing) can only be achieved | ||
116 | + # with gdcm.ImageReader() | ||
117 | + # used to parse DICOM files - similar to vtkDICOMParser | ||
118 | + gdcm_reader = gdcm.ImageReader() | ||
119 | + #filename = filename.encode('utf-8') | ||
120 | + | ||
121 | + gdcm_reader.SetFileName(filename) | ||
122 | + | ||
123 | + # if DICOM file is null vtkGDCMImageReader raises vtk | ||
124 | + # exception | ||
125 | + if not gdcm_reader.Read(): | ||
126 | + return False | ||
127 | + | ||
128 | + vtkgdcm_reader = self.vtkgdcm_reader | ||
129 | + vtkgdcm_reader.SetFileName(filename) | ||
130 | + vtkgdcm_reader.Update() | ||
131 | + | ||
132 | + self.filename = filename | ||
133 | + self.gdcm_reader = gdcm_reader | ||
134 | + self.vtkgdcm_reader = vtkgdcm_reader | ||
135 | + return True | ||
136 | + | ||
137 | + return False | ||
138 | + | ||
139 | + def GetImageData(self): | ||
140 | + return self.vtkgdcm_reader.GetOutput() | ||
141 | + | ||
142 | + def __format_time(self,value): | ||
143 | + sp1 = value.split(".") | ||
144 | + sp2 = value.split(":") | ||
145 | + | ||
146 | + if (len(sp1) == 2) and (len(sp2) == 3): | ||
147 | + new_value = str(sp2[0]+sp2[1]+ | ||
148 | + str(int(float(sp2[2])))) | ||
149 | + data = time.strptime(new_value, "%H%M%S") | ||
150 | + elif (len(sp1) == 2): | ||
151 | + data = time.gmtime(float(value)) | ||
152 | + elif (len(sp1) > 2): | ||
153 | + data = time.strptime(value, "%H.%M.%S") | ||
154 | + elif(len(sp2) > 1): | ||
155 | + data = time.strptime(value, "%H:%M:%S") | ||
156 | + else: | ||
157 | + data = time.strptime(value, "%H%M%S") | ||
158 | + return time.strftime("%H:%M:%S",data) | ||
159 | + | ||
160 | + def __format_date(self, value): | ||
161 | + | ||
162 | + sp1 = value.split(".") | ||
163 | + try: | ||
164 | + | ||
165 | + if (len(sp1) > 1): | ||
166 | + if (len(sp1[0]) <= 2): | ||
167 | + data = time.strptime(value, "%D.%M.%Y") | ||
168 | + else: | ||
169 | + data = time.strptime(value, "%Y.%M.%d") | ||
170 | + elif(len(value.split("//")) > 1): | ||
171 | + data = time.strptime(value, "%D/%M/%Y") | ||
172 | + else: | ||
173 | + data = time.strptime(value, "%Y%M%d") | ||
174 | + return time.strftime("%d/%M/%Y",data) | ||
175 | + | ||
176 | + except(ValueError): | ||
177 | + return "" | ||
178 | + | ||
179 | + def GetImageOrientationLabel(self): | ||
180 | + """ | ||
181 | + Return Label regarding the orientation of | ||
182 | + an image. (AXIAL, SAGITTAL, CORONAL, | ||
183 | + OBLIQUE or UNKNOWN) | ||
184 | + """ | ||
185 | + img = self.gdcm_reader.GetImage() | ||
186 | + direc_cosines = img.GetDirectionCosines() | ||
187 | + orientation = gdcm.Orientation() | ||
188 | + try: | ||
189 | + type = orientation.GetType(tuple(direc_cosines)) | ||
190 | + except TypeError: | ||
191 | + type = orientation.GetType(direc_cosines) | ||
192 | + label = orientation.GetLabel(type) | ||
193 | + | ||
194 | + if (label): | ||
195 | + return label | ||
196 | + else: | ||
197 | + return "" | ||
198 | + | ||
199 | + def GetDimensionX(self): | ||
200 | + """ | ||
201 | + Return integer associated to X dimension. This is related | ||
202 | + to the number of columns on the image. | ||
203 | + Return "" if not defined. | ||
204 | + """ | ||
205 | + tag = gdcm.Tag(0x0028, 0x0011) | ||
206 | + ds = self.gdcm_reader.GetFile().GetDataSet() | ||
207 | + sf = gdcm.StringFilter() | ||
208 | + sf.SetFile(self.gdcm_reader.GetFile()) | ||
209 | + data = sf.ToStringPair(tag)[1] | ||
210 | + | ||
211 | + if (data): | ||
212 | + return int(str(data)) | ||
213 | + return "" | ||
214 | + | ||
215 | + | ||
216 | + def GetDimensionY(self): | ||
217 | + """ | ||
218 | + Return integer associated to Y dimension. This is related | ||
219 | + to the number of rows on the image. | ||
220 | + Return "" if not defined. | ||
221 | + """ | ||
222 | + tag = gdcm.Tag(0x0028, 0x0010) | ||
223 | + ds = self.gdcm_reader.GetFile().GetDataSet() | ||
224 | + sf = gdcm.StringFilter() | ||
225 | + sf.SetFile(self.gdcm_reader.GetFile()) | ||
226 | + data = sf.ToStringPair(tag)[1] | ||
227 | + | ||
228 | + if (data): | ||
229 | + return int(str(data)) | ||
230 | + return "" | ||
231 | + | ||
232 | + | ||
233 | + def GetDimensionZ(self): | ||
234 | + """ | ||
235 | + Return float value associated to Z dimension. | ||
236 | + Return "" if not defined. | ||
237 | + """ | ||
238 | + data = self.vtkgdcm_reader.GetOutput()\ | ||
239 | + .GetDimensions()[2] | ||
240 | + if (data): | ||
241 | + return float(data) | ||
242 | + return "" | ||
243 | + | ||
244 | + def GetImageDataType(self): | ||
245 | + """ | ||
246 | + Return image's pixel representation data type (string). This | ||
247 | + might be: | ||
248 | + - Float64 | ||
249 | + - Int8 | ||
250 | + - Int16 | ||
251 | + - Int32 | ||
252 | + - UInt16 | ||
253 | + Return "" otherwise. | ||
254 | + """ | ||
255 | + repres = self._GetPixelRepresentation() | ||
256 | + | ||
257 | + bits = self._GetBitsAllocated() | ||
258 | + | ||
259 | + if not bits: | ||
260 | + answer = "" | ||
261 | + else: | ||
262 | + answer = "UInt16" | ||
263 | + | ||
264 | + if bits == 8: | ||
265 | + answer = "Int8" | ||
266 | + elif bits == 16: | ||
267 | + if repres: | ||
268 | + answer = "Int16" | ||
269 | + elif bits == 32: | ||
270 | + answer = "Int32" | ||
271 | + elif bits == 64: | ||
272 | + answer = "Float64" | ||
273 | + | ||
274 | + return answer | ||
275 | + | ||
276 | + def GetImagePixelSpacingY(self): | ||
277 | + """ | ||
278 | + Return spacing between adjacent pixels considerating y axis | ||
279 | + (height). Values are usually floating point and represent mm. | ||
280 | + Return "" if field is not defined. | ||
281 | + | ||
282 | + DICOM standard tag (0x0028, 0x0030) was used. | ||
283 | + """ | ||
284 | + spacing = self.GetPixelSpacing() | ||
285 | + if spacing: | ||
286 | + return spacing[1] | ||
287 | + return "" | ||
288 | + | ||
289 | + def GetImagePixelSpacingX(self): | ||
290 | + """ | ||
291 | + Return spacing between adjacent pixels considerating x axis | ||
292 | + (width). Values are usually floating point and represent mm. | ||
293 | + Return "" if field is not defined. | ||
294 | + | ||
295 | + DICOM standard tag (0x0028, 0x0030) was used. | ||
296 | + """ | ||
297 | + | ||
298 | + spacing = self.GetPixelSpacing() | ||
299 | + if spacing: | ||
300 | + return spacing[0] | ||
301 | + return "" | ||
302 | + | ||
303 | + | ||
97 | def GetAcquisitionDate(self): | 304 | def GetAcquisitionDate(self): |
98 | """ | 305 | """ |
99 | Return string containing the acquisition date using the | 306 | Return string containing the acquisition date using the |
@@ -177,52 +384,6 @@ class Parser(): | @@ -177,52 +384,6 @@ class Parser(): | ||
177 | return "" | 384 | return "" |
178 | 385 | ||
179 | 386 | ||
180 | - | ||
181 | - def SetFileName(self, filename): | ||
182 | - """ | ||
183 | - Set file name to be parsed given its filename (this should | ||
184 | - include the full path of the file of interest). | ||
185 | - | ||
186 | - Return True/False if file could be read. | ||
187 | - """ | ||
188 | - import os.path as path | ||
189 | - | ||
190 | - | ||
191 | - filename = path.abspath(filename) | ||
192 | - | ||
193 | - if (sys.platform == 'win32'): | ||
194 | - filename = filename.encode('latin-1') | ||
195 | - | ||
196 | - if path.isfile(filename): | ||
197 | - # Several information can be acquired from DICOM using | ||
198 | - # vtkgdcm.vtkGDCMImageReader.GetMedicalImageProperties() | ||
199 | - # but some tags (such as spacing) can only be achieved | ||
200 | - # with gdcm.ImageReader() | ||
201 | - # used to parse DICOM files - similar to vtkDICOMParser | ||
202 | - gdcm_reader = gdcm.ImageReader() | ||
203 | - #filename = filename.encode('utf-8') | ||
204 | - | ||
205 | - gdcm_reader.SetFileName(filename) | ||
206 | - | ||
207 | - # if DICOM file is null vtkGDCMImageReader raises vtk | ||
208 | - # exception | ||
209 | - if not gdcm_reader.Read(): | ||
210 | - return False | ||
211 | - | ||
212 | - vtkgdcm_reader = self.vtkgdcm_reader | ||
213 | - vtkgdcm_reader.SetFileName(filename) | ||
214 | - vtkgdcm_reader.Update() | ||
215 | - | ||
216 | - self.filename = filename | ||
217 | - self.gdcm_reader = gdcm_reader | ||
218 | - self.vtkgdcm_reader = vtkgdcm_reader | ||
219 | - return True | ||
220 | - | ||
221 | - return False | ||
222 | - | ||
223 | - def GetImageData(self): | ||
224 | - return self.vtkgdcm_reader.GetOutput() | ||
225 | - | ||
226 | def GetImageWindowLevel(self, preset=WL_PRESET, multiple=WL_MULT): | 387 | def GetImageWindowLevel(self, preset=WL_PRESET, multiple=WL_MULT): |
227 | """ | 388 | """ |
228 | Return image window center / level (related to brightness). | 389 | Return image window center / level (related to brightness). |
@@ -377,33 +538,6 @@ class Parser(): | @@ -377,33 +538,6 @@ class Parser(): | ||
377 | return [eval(value) for value in data.split('\\')] | 538 | return [eval(value) for value in data.split('\\')] |
378 | return "" | 539 | return "" |
379 | 540 | ||
380 | - def GetImagePixelSpacingY(self): | ||
381 | - """ | ||
382 | - Return spacing between adjacent pixels considerating y axis | ||
383 | - (height). Values are usually floating point and represent mm. | ||
384 | - Return "" if field is not defined. | ||
385 | - | ||
386 | - DICOM standard tag (0x0028, 0x0030) was used. | ||
387 | - """ | ||
388 | - spacing = self.GetPixelSpacing() | ||
389 | - if spacing: | ||
390 | - return spacing[1] | ||
391 | - return "" | ||
392 | - | ||
393 | - def GetImagePixelSpacingX(self): | ||
394 | - """ | ||
395 | - Return spacing between adjacent pixels considerating x axis | ||
396 | - (width). Values are usually floating point and represent mm. | ||
397 | - Return "" if field is not defined. | ||
398 | - | ||
399 | - DICOM standard tag (0x0028, 0x0030) was used. | ||
400 | - """ | ||
401 | - | ||
402 | - spacing = self.GetPixelSpacing() | ||
403 | - if spacing: | ||
404 | - return spacing[0] | ||
405 | - return "" | ||
406 | - | ||
407 | def GetPatientWeight(self): | 541 | def GetPatientWeight(self): |
408 | """ | 542 | """ |
409 | Return patient's weight as a float value (kilograms). | 543 | Return patient's weight as a float value (kilograms). |
@@ -1022,40 +1156,8 @@ class Parser(): | @@ -1022,40 +1156,8 @@ class Parser(): | ||
1022 | if (res[1]): | 1156 | if (res[1]): |
1023 | return int(res[1]) | 1157 | return int(res[1]) |
1024 | return "" | 1158 | return "" |
1025 | - | ||
1026 | - def GetImageDataType(self): | ||
1027 | - """ | ||
1028 | - Return image's pixel representation data type (string). This | ||
1029 | - might be: | ||
1030 | - - Float64 | ||
1031 | - - Int8 | ||
1032 | - - Int16 | ||
1033 | - - Int32 | ||
1034 | - - UInt16 | ||
1035 | - Return "" otherwise. | ||
1036 | - """ | ||
1037 | - repres = self._GetPixelRepresentation() | ||
1038 | - | ||
1039 | - bits = self._GetBitsAllocated() | ||
1040 | - | ||
1041 | - if not bits: | ||
1042 | - answer = "" | ||
1043 | - else: | ||
1044 | - answer = "UInt16" | ||
1045 | - | ||
1046 | - if bits == 8: | ||
1047 | - answer = "Int8" | ||
1048 | - elif bits == 16: | ||
1049 | - if repres: | ||
1050 | - answer = "Int16" | ||
1051 | - elif bits == 32: | ||
1052 | - answer = "Int32" | ||
1053 | - elif bits == 64: | ||
1054 | - answer = "Float64" | ||
1055 | - | ||
1056 | - return answer | ||
1057 | - | ||
1058 | - | 1159 | + |
1160 | + | ||
1059 | def GetPatientBirthDate(self): | 1161 | def GetPatientBirthDate(self): |
1060 | """ | 1162 | """ |
1061 | Return string containing the patient's birth date using the | 1163 | Return string containing the patient's birth date using the |
@@ -1186,43 +1288,6 @@ class Parser(): | @@ -1186,43 +1288,6 @@ class Parser(): | ||
1186 | return "" | 1288 | return "" |
1187 | 1289 | ||
1188 | 1290 | ||
1189 | - def GetDimensionX(self): | ||
1190 | - """ | ||
1191 | - Return integer associated to X dimension. This is related | ||
1192 | - to the number of columns on the image. | ||
1193 | - Return "" if not defined. | ||
1194 | - """ | ||
1195 | - | ||
1196 | - data = self.vtkgdcm_reader.GetOutput()\ | ||
1197 | - .GetDimensions()[0] | ||
1198 | - if (data): | ||
1199 | - return int(data) | ||
1200 | - return "" | ||
1201 | - | ||
1202 | - def GetDimensionY(self): | ||
1203 | - """ | ||
1204 | - Return integer associated to Y dimension. This is related | ||
1205 | - to the number of rows on the image. | ||
1206 | - Return "" if not defined. | ||
1207 | - """ | ||
1208 | - data = self.vtkgdcm_reader.GetOutput()\ | ||
1209 | - .GetDimensions()[1] | ||
1210 | - if (data): | ||
1211 | - return int(data) | ||
1212 | - return "" | ||
1213 | - | ||
1214 | - def GetDimensionZ(self): | ||
1215 | - """ | ||
1216 | - Return float value associated to Z dimension. | ||
1217 | - Return "" if not defined. | ||
1218 | - """ | ||
1219 | - data = self.vtkgdcm_reader.GetOutput()\ | ||
1220 | - .GetDimensions()[2] | ||
1221 | - if (data): | ||
1222 | - return float(data) | ||
1223 | - return "" | ||
1224 | - | ||
1225 | - | ||
1226 | def GetEquipmentXRayTubeCurrent(self): | 1291 | def GetEquipmentXRayTubeCurrent(self): |
1227 | """ | 1292 | """ |
1228 | Return float value associated to the X-ray tube current | 1293 | Return float value associated to the X-ray tube current |
@@ -1446,26 +1511,7 @@ class Parser(): | @@ -1446,26 +1511,7 @@ class Parser(): | ||
1446 | return str(res[1]) | 1511 | return str(res[1]) |
1447 | return "" | 1512 | return "" |
1448 | 1513 | ||
1449 | - def GetImageOrientationLabel(self): | ||
1450 | - """ | ||
1451 | - Return Label regarding the orientation of | ||
1452 | - an image. (AXIAL, SAGITTAL, CORONAL, | ||
1453 | - OBLIQUE or UNKNOWN) | ||
1454 | - """ | ||
1455 | - img = self.gdcm_reader.GetImage() | ||
1456 | - direc_cosines = img.GetDirectionCosines() | ||
1457 | - orientation = gdcm.Orientation() | ||
1458 | - try: | ||
1459 | - type = orientation.GetType(tuple(direc_cosines)) | ||
1460 | - except TypeError: | ||
1461 | - type = orientation.GetType(direc_cosines) | ||
1462 | - label = orientation.GetLabel(type) | ||
1463 | - | ||
1464 | - if (label): | ||
1465 | - return label | ||
1466 | - else: | ||
1467 | - return "" | ||
1468 | - | 1514 | + |
1469 | def GetSeriesDescription(self): | 1515 | def GetSeriesDescription(self): |
1470 | """ | 1516 | """ |
1471 | Return a string with a description of the series. | 1517 | Return a string with a description of the series. |
@@ -1494,43 +1540,6 @@ class Parser(): | @@ -1494,43 +1540,6 @@ class Parser(): | ||
1494 | return self.__format_time(date) | 1540 | return self.__format_time(date) |
1495 | return "" | 1541 | return "" |
1496 | 1542 | ||
1497 | - def __format_time(self,value): | ||
1498 | - sp1 = value.split(".") | ||
1499 | - sp2 = value.split(":") | ||
1500 | - | ||
1501 | - if (len(sp1) == 2) and (len(sp2) == 3): | ||
1502 | - new_value = str(sp2[0]+sp2[1]+ | ||
1503 | - str(int(float(sp2[2])))) | ||
1504 | - data = time.strptime(new_value, "%H%M%S") | ||
1505 | - elif (len(sp1) == 2): | ||
1506 | - data = time.gmtime(float(value)) | ||
1507 | - elif (len(sp1) > 2): | ||
1508 | - data = time.strptime(value, "%H.%M.%S") | ||
1509 | - elif(len(sp2) > 1): | ||
1510 | - data = time.strptime(value, "%H:%M:%S") | ||
1511 | - else: | ||
1512 | - data = time.strptime(value, "%H%M%S") | ||
1513 | - return time.strftime("%H:%M:%S",data) | ||
1514 | - | ||
1515 | - def __format_date(self, value): | ||
1516 | - | ||
1517 | - sp1 = value.split(".") | ||
1518 | - try: | ||
1519 | - | ||
1520 | - if (len(sp1) > 1): | ||
1521 | - if (len(sp1[0]) <= 2): | ||
1522 | - data = time.strptime(value, "%D.%M.%Y") | ||
1523 | - else: | ||
1524 | - data = time.strptime(value, "%Y.%M.%d") | ||
1525 | - elif(len(value.split("//")) > 1): | ||
1526 | - data = time.strptime(value, "%D/%M/%Y") | ||
1527 | - else: | ||
1528 | - data = time.strptime(value, "%Y%M%d") | ||
1529 | - return time.strftime("%d/%M/%Y",data) | ||
1530 | - | ||
1531 | - except(ValueError): | ||
1532 | - return "" | ||
1533 | - | ||
1534 | def GetAcquisitionTime(self): | 1543 | def GetAcquisitionTime(self): |
1535 | """ | 1544 | """ |
1536 | Return the acquisition time. | 1545 | Return the acquisition time. |