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 | 94 | self.encoding = "" |
95 | 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 | 304 | def GetAcquisitionDate(self): |
98 | 305 | """ |
99 | 306 | Return string containing the acquisition date using the |
... | ... | @@ -177,52 +384,6 @@ class Parser(): |
177 | 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 | 387 | def GetImageWindowLevel(self, preset=WL_PRESET, multiple=WL_MULT): |
227 | 388 | """ |
228 | 389 | Return image window center / level (related to brightness). |
... | ... | @@ -377,33 +538,6 @@ class Parser(): |
377 | 538 | return [eval(value) for value in data.split('\\')] |
378 | 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 | 541 | def GetPatientWeight(self): |
408 | 542 | """ |
409 | 543 | Return patient's weight as a float value (kilograms). |
... | ... | @@ -1022,40 +1156,8 @@ class Parser(): |
1022 | 1156 | if (res[1]): |
1023 | 1157 | return int(res[1]) |
1024 | 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 | 1161 | def GetPatientBirthDate(self): |
1060 | 1162 | """ |
1061 | 1163 | Return string containing the patient's birth date using the |
... | ... | @@ -1186,43 +1288,6 @@ class Parser(): |
1186 | 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 | 1291 | def GetEquipmentXRayTubeCurrent(self): |
1227 | 1292 | """ |
1228 | 1293 | Return float value associated to the X-ray tube current |
... | ... | @@ -1446,26 +1511,7 @@ class Parser(): |
1446 | 1511 | return str(res[1]) |
1447 | 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 | 1515 | def GetSeriesDescription(self): |
1470 | 1516 | """ |
1471 | 1517 | Return a string with a description of the series. |
... | ... | @@ -1494,43 +1540,6 @@ class Parser(): |
1494 | 1540 | return self.__format_time(date) |
1495 | 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 | 1543 | def GetAcquisitionTime(self): |
1535 | 1544 | """ |
1536 | 1545 | Return the acquisition time. | ... | ... |