Commit 8e34d14af082b07bcfa681133fac291bb5b89a27
1 parent
6a79ee28
Exists in
master
and in
68 other branches
FIX: DICOM (to be attached) reconstruction is flattened. FIX #167
Showing
2 changed files
with
93 additions
and
75 deletions
Show diff stats
invesalius/data/imagedata_utils.py
... | ... | @@ -159,7 +159,13 @@ def BuildEditedImage(imagedata, points): |
159 | 159 | imagedata.SetScalarComponentFromDouble(x, y, z, 0, colour) |
160 | 160 | imagedata.Update() |
161 | 161 | |
162 | - return imagedata | |
162 | + gauss = vtk.vtkImageGaussianSmooth() | |
163 | + gauss.SetInput(imagedata) | |
164 | + gauss.SetRadiusFactor(0.8) | |
165 | + gauss.Update() | |
166 | + | |
167 | + return gauss.GetOutput() | |
168 | + | |
163 | 169 | |
164 | 170 | def Export(imagedata, filename, bin=False): |
165 | 171 | writer = vtk.vtkXMLImageDataWriter() |
... | ... | @@ -214,9 +220,10 @@ def ExtractVOI(imagedata,xi,xf,yi,yf,zi,zf): |
214 | 220 | voi.Update() |
215 | 221 | return voi.GetOutput() |
216 | 222 | |
217 | -def CreateImageData(filelist, zspacing, size, bits): | |
223 | +def CreateImageData(filelist, zspacing, xyspacing,size, | |
224 | + bits, use_dcmspacing): | |
218 | 225 | message = _("Generating multiplanar visualization...") |
219 | - | |
226 | + | |
220 | 227 | if not const.VTK_WARNING: |
221 | 228 | log_path = os.path.join(const.LOG_FOLDER, 'vtkoutput.txt') |
222 | 229 | fow = vtk.vtkFileOutputWindow() |
... | ... | @@ -250,7 +257,12 @@ def CreateImageData(filelist, zspacing, size, bits): |
250 | 257 | # The zpacing is a DicomGroup property, so we need to set it |
251 | 258 | imagedata = vtk.vtkImageData() |
252 | 259 | imagedata.DeepCopy(reader.GetOutput()) |
253 | - spacing = imagedata.GetSpacing() | |
260 | + if (use_dcmspacing): | |
261 | + spacing = xyspacing | |
262 | + spacing[2] = zspacing | |
263 | + else: | |
264 | + spacing = imagedata.GetSpacing() | |
265 | + | |
254 | 266 | imagedata.SetSpacing(spacing[0], spacing[1], zspacing) |
255 | 267 | else: |
256 | 268 | |
... | ... | @@ -283,7 +295,12 @@ def CreateImageData(filelist, zspacing, size, bits): |
283 | 295 | # The zpacing is a DicomGroup property, so we need to set it |
284 | 296 | imagedata = vtk.vtkImageData() |
285 | 297 | imagedata.DeepCopy(appender.GetOutput()) |
286 | - spacing = imagedata.GetSpacing() | |
298 | + | |
299 | + if (use_dcmspacing): | |
300 | + spacing = xyspacing | |
301 | + spacing[2] = zspacing | |
302 | + else: | |
303 | + spacing = imagedata.GetSpacing() | |
287 | 304 | |
288 | 305 | imagedata.SetSpacing(spacing[0], spacing[1], zspacing) |
289 | 306 | |
... | ... | @@ -305,7 +322,7 @@ class ImageCreator: |
305 | 322 | |
306 | 323 | def CreateImageData(self, filelist, zspacing, size, bits): |
307 | 324 | message = _("Generating multiplanar visualization...") |
308 | - | |
325 | + | |
309 | 326 | if not const.VTK_WARNING: |
310 | 327 | log_path = os.path.join(const.LOG_FOLDER, 'vtkoutput.txt') |
311 | 328 | fow = vtk.vtkFileOutputWindow() | ... | ... |
invesalius/reader/dicom.py
... | ... | @@ -93,7 +93,7 @@ class Parser(): |
93 | 93 | self.filename = "" |
94 | 94 | self.encoding = "" |
95 | 95 | self.vtkgdcm_reader = vtkgdcm.vtkGDCMImageReader() |
96 | - | |
96 | + | |
97 | 97 | def GetAcquisitionDate(self): |
98 | 98 | """ |
99 | 99 | Return string containing the acquisition date using the |
... | ... | @@ -141,7 +141,7 @@ class Parser(): |
141 | 141 | value = 0 |
142 | 142 | return value |
143 | 143 | return "" |
144 | - | |
144 | + | |
145 | 145 | def GetAcquisitionTime(self): |
146 | 146 | """ |
147 | 147 | Return string containing the acquisition time using the |
... | ... | @@ -194,18 +194,18 @@ class Parser(): |
194 | 194 | |
195 | 195 | # used to parse DICOM files - similar to vtkDICOMParser |
196 | 196 | gdcm_reader = gdcm.ImageReader() |
197 | - | |
197 | + | |
198 | 198 | gdcm_reader.SetFileName(filename) |
199 | - | |
199 | + | |
200 | 200 | # if DICOM file is null vtkGDCMImageReader raises vtk |
201 | 201 | # exception |
202 | 202 | if not gdcm_reader.Read(): |
203 | 203 | return False |
204 | - | |
204 | + | |
205 | 205 | vtkgdcm_reader = self.vtkgdcm_reader |
206 | 206 | vtkgdcm_reader.SetFileName(filename) |
207 | 207 | vtkgdcm_reader.Update() |
208 | - | |
208 | + | |
209 | 209 | self.filename = filename |
210 | 210 | self.gdcm_reader = gdcm_reader |
211 | 211 | self.vtkgdcm_reader = vtkgdcm_reader |
... | ... | @@ -278,7 +278,7 @@ class Parser(): |
278 | 278 | # we choose only one. As this should be paired to "Window |
279 | 279 | # Width", it is set based on WL_PRESET |
280 | 280 | value_list = [float(value) for value in data.split('\\')] |
281 | - | |
281 | + | |
282 | 282 | if multiple: |
283 | 283 | return str(value_list) |
284 | 284 | else: |
... | ... | @@ -619,7 +619,7 @@ class Parser(): |
619 | 619 | return data |
620 | 620 | return "" |
621 | 621 | |
622 | - | |
622 | + | |
623 | 623 | def GetPhysicianReferringAddress(self): |
624 | 624 | """ |
625 | 625 | Return string containing physician's address. |
... | ... | @@ -730,7 +730,7 @@ class Parser(): |
730 | 730 | if (data): |
731 | 731 | return data |
732 | 732 | return "" |
733 | - | |
733 | + | |
734 | 734 | def GetStudyInstanceUID(self): |
735 | 735 | """ |
736 | 736 | Return string containing Unique Identifier of the |
... | ... | @@ -931,7 +931,7 @@ class Parser(): |
931 | 931 | data = str(ds.GetDataElement(tag).GetValue()) |
932 | 932 | if (data): |
933 | 933 | return data |
934 | - | |
934 | + | |
935 | 935 | 0x0008, 0x0081 |
936 | 936 | |
937 | 937 | def GetInstitutionAddress(self): |
... | ... | @@ -1399,7 +1399,7 @@ class Parser(): |
1399 | 1399 | except TypeError: |
1400 | 1400 | type = orientation.GetType(direc_cosines) |
1401 | 1401 | label = orientation.GetLabel(type) |
1402 | - | |
1402 | + | |
1403 | 1403 | if (label): |
1404 | 1404 | return label |
1405 | 1405 | else: |
... | ... | @@ -1432,14 +1432,14 @@ class Parser(): |
1432 | 1432 | if (date) and (date != 'None'): |
1433 | 1433 | return self.__format_time(date) |
1434 | 1434 | return "" |
1435 | - | |
1435 | + | |
1436 | 1436 | def __format_time(self,value): |
1437 | 1437 | sp1 = value.split(".") |
1438 | 1438 | sp2 = value.split(":") |
1439 | - | |
1439 | + | |
1440 | 1440 | if (len(sp1) == 2) and (len(sp2) == 3): |
1441 | 1441 | new_value = str(sp2[0]+sp2[1]+ |
1442 | - str(int(float(sp2[2])))) | |
1442 | + str(int(float(sp2[2])))) | |
1443 | 1443 | data = time.strptime(new_value, "%H%M%S") |
1444 | 1444 | elif (len(sp1) == 2): |
1445 | 1445 | data = time.gmtime(float(value)) |
... | ... | @@ -1448,14 +1448,14 @@ class Parser(): |
1448 | 1448 | elif(len(sp2) > 1): |
1449 | 1449 | data = time.strptime(value, "%H:%M:%S") |
1450 | 1450 | else: |
1451 | - data = time.strptime(value, "%H%M%S") | |
1451 | + data = time.strptime(value, "%H%M%S") | |
1452 | 1452 | return time.strftime("%H:%M:%S",data) |
1453 | - | |
1453 | + | |
1454 | 1454 | def __format_date(self, value): |
1455 | - | |
1455 | + | |
1456 | 1456 | sp1 = value.split(".") |
1457 | 1457 | try: |
1458 | - | |
1458 | + | |
1459 | 1459 | if (len(sp1) > 1): |
1460 | 1460 | if (len(sp1[0]) <= 2): |
1461 | 1461 | data = time.strptime(value, "%D.%M.%Y") |
... | ... | @@ -1466,10 +1466,10 @@ class Parser(): |
1466 | 1466 | else: |
1467 | 1467 | data = time.strptime(value, "%Y%M%d") |
1468 | 1468 | return time.strftime("%d/%M/%Y",data) |
1469 | - | |
1469 | + | |
1470 | 1470 | except(ValueError): |
1471 | 1471 | return "" |
1472 | - | |
1472 | + | |
1473 | 1473 | def GetAcquisitionTime(self): |
1474 | 1474 | """ |
1475 | 1475 | Return the acquisition time. |
... | ... | @@ -1482,7 +1482,7 @@ class Parser(): |
1482 | 1482 | if (data): |
1483 | 1483 | return self.__format_time(data) |
1484 | 1484 | return "" |
1485 | - | |
1485 | + | |
1486 | 1486 | def GetSerieNumber(self): |
1487 | 1487 | """ |
1488 | 1488 | Return the serie number |
... | ... | @@ -1508,7 +1508,7 @@ class Parser(): |
1508 | 1508 | if encoding != None: |
1509 | 1509 | #Problem with 0051 anonymized |
1510 | 1510 | if (encoding.split(":"))[0] == "Loaded": |
1511 | - return 'ISO_IR 100' | |
1511 | + return 'ISO_IR 100' | |
1512 | 1512 | else: |
1513 | 1513 | return encoding |
1514 | 1514 | return 'ISO_IR 100' |
... | ... | @@ -1544,7 +1544,7 @@ class DicomWriter: |
1544 | 1544 | """ |
1545 | 1545 | |
1546 | 1546 | def __init__(self): |
1547 | - | |
1547 | + | |
1548 | 1548 | self.reader = "" |
1549 | 1549 | self.anony = gdcm.Anonymizer() |
1550 | 1550 | self.path = "" |
... | ... | @@ -1555,13 +1555,13 @@ class DicomWriter: |
1555 | 1555 | def SetFileName(self, path): |
1556 | 1556 | """ |
1557 | 1557 | Set Dicom File Name |
1558 | - """ | |
1558 | + """ | |
1559 | 1559 | self.path = path |
1560 | 1560 | |
1561 | 1561 | self.reader.SetFileName(path) |
1562 | - | |
1562 | + | |
1563 | 1563 | if (self.reader.Read()): |
1564 | - | |
1564 | + | |
1565 | 1565 | self.anony.SetFile(self.reader.GetFile()) |
1566 | 1566 | |
1567 | 1567 | |
... | ... | @@ -1571,11 +1571,11 @@ class DicomWriter: |
1571 | 1571 | Input vtkImageData |
1572 | 1572 | """ |
1573 | 1573 | self.img_data = img_data |
1574 | - | |
1575 | - | |
1574 | + | |
1575 | + | |
1576 | 1576 | def __CreateNewDicom(self, img_data): |
1577 | 1577 | """ |
1578 | - Create New Dicom File, input is | |
1578 | + Create New Dicom File, input is | |
1579 | 1579 | a vtkImageData |
1580 | 1580 | """ |
1581 | 1581 | new_dicom = self.new_dicom |
... | ... | @@ -1583,13 +1583,13 @@ class DicomWriter: |
1583 | 1583 | new_dicom.SetInput(img_data) |
1584 | 1584 | new_dicom.Write() |
1585 | 1585 | |
1586 | - | |
1586 | + | |
1587 | 1587 | def SaveIsNew(self, img_data): |
1588 | 1588 | """ |
1589 | - Write Changes in Dicom file or Create | |
1589 | + Write Changes in Dicom file or Create | |
1590 | 1590 | New Dicom File |
1591 | 1591 | """ |
1592 | - | |
1592 | + | |
1593 | 1593 | self.__CreateNewDicom(img_data) |
1594 | 1594 | |
1595 | 1595 | #Is necessary to create and add |
... | ... | @@ -1597,19 +1597,19 @@ class DicomWriter: |
1597 | 1597 | self.SetFileName(self.path) |
1598 | 1598 | self.anony.SetFile(self.reader.GetFile()) |
1599 | 1599 | |
1600 | - | |
1600 | + | |
1601 | 1601 | def Save(self): |
1602 | 1602 | |
1603 | 1603 | reader = self.reader |
1604 | - | |
1604 | + | |
1605 | 1605 | writer = gdcm.Writer() |
1606 | 1606 | writer.SetFile(self.reader.GetFile()) |
1607 | 1607 | writer.SetFileName(self.path) |
1608 | - writer.Write() | |
1609 | - | |
1608 | + writer.Write() | |
1609 | + | |
1610 | 1610 | |
1611 | 1611 | def SetPatientName(self, patient): |
1612 | - """ | |
1612 | + """ | |
1613 | 1613 | Set Patient Name requeries string type |
1614 | 1614 | """ |
1615 | 1615 | self.anony.Replace(gdcm.Tag(0x0010,0x0010), \ |
... | ... | @@ -1617,73 +1617,73 @@ class DicomWriter: |
1617 | 1617 | |
1618 | 1618 | |
1619 | 1619 | def SetImageThickness(self, thickness): |
1620 | - """ | |
1620 | + """ | |
1621 | 1621 | Set thickness value requeries float type |
1622 | 1622 | """ |
1623 | 1623 | self.anony.Replace(gdcm.Tag(0x0018,0x0050), \ |
1624 | 1624 | str(thickness)) |
1625 | - | |
1626 | - | |
1625 | + | |
1626 | + | |
1627 | 1627 | def SetImageSeriesNumber(self, number): |
1628 | - """ | |
1628 | + """ | |
1629 | 1629 | Set Serie Number value requeries int type |
1630 | 1630 | """ |
1631 | 1631 | self.anony.Replace(gdcm.Tag(0x0020,0x0011), \ |
1632 | 1632 | str(number)) |
1633 | - | |
1634 | - | |
1633 | + | |
1634 | + | |
1635 | 1635 | def SetImageNumber(self, number): |
1636 | - """ | |
1636 | + """ | |
1637 | 1637 | Set image Number value requeries int type |
1638 | 1638 | """ |
1639 | 1639 | self.anony.Replace(gdcm.Tag(0x0020,0x0013), |
1640 | 1640 | str(number)) |
1641 | - | |
1642 | - | |
1641 | + | |
1642 | + | |
1643 | 1643 | def SetImageLocation(self, location): |
1644 | - """ | |
1644 | + """ | |
1645 | 1645 | Set slice location value requeries float type |
1646 | 1646 | """ |
1647 | 1647 | self.anony.Replace(gdcm.Tag(0x0020,0x1041),\ |
1648 | 1648 | str(number)) |
1649 | - | |
1650 | - | |
1649 | + | |
1650 | + | |
1651 | 1651 | def SetImagePosition(self, position): |
1652 | - """ | |
1653 | - Set slice position value requeries list | |
1652 | + """ | |
1653 | + Set slice position value requeries list | |
1654 | 1654 | with three values x, y and z |
1655 | 1655 | """ |
1656 | 1656 | self.anony.Replace(gdcm.Tag(0x0020,0x0032), \ |
1657 | 1657 | str(position[0]) + \ |
1658 | 1658 | "\\" + str(position[1]) + \ |
1659 | 1659 | "\\" + str(position[2])) |
1660 | - | |
1661 | - | |
1660 | + | |
1661 | + | |
1662 | 1662 | def SetAcquisitionModality(self, modality): |
1663 | - """ | |
1663 | + """ | |
1664 | 1664 | Set modality study CT or RM |
1665 | 1665 | """ |
1666 | 1666 | self.anony.Replace(gdcm.Tag(0x0008,0x0060), \ |
1667 | 1667 | str(modality)) |
1668 | - | |
1669 | - | |
1668 | + | |
1669 | + | |
1670 | 1670 | def SetPixelSpacing(self, spacing): |
1671 | 1671 | """ |
1672 | 1672 | Set pixel spacing x and y |
1673 | 1673 | """ |
1674 | 1674 | self.anony.Replace(gdcm.Tag(0x0028,0x0030), \ |
1675 | 1675 | str(spacing)) |
1676 | - | |
1677 | - | |
1676 | + | |
1677 | + | |
1678 | 1678 | def SetInstitutionName(self, institution): |
1679 | 1679 | """ |
1680 | 1680 | Set institution name |
1681 | 1681 | """ |
1682 | 1682 | self.anony.Replace(gdcm.Tag(0x0008, 0x0080), \ |
1683 | 1683 | str(institution)) |
1684 | - | |
1685 | 1684 | |
1686 | - | |
1685 | + | |
1686 | + | |
1687 | 1687 | |
1688 | 1688 | |
1689 | 1689 | |
... | ... | @@ -1808,11 +1808,11 @@ class Patient(object): |
1808 | 1808 | self.name = parser.GetPatientName() |
1809 | 1809 | self.id = parser.GetPatientID() |
1810 | 1810 | self.age = parser.GetPatientAge() |
1811 | - self.birthdate = parser.GetPatientBirthDate() | |
1811 | + self.birthdate = parser.GetPatientBirthDate() | |
1812 | 1812 | self.gender = parser.GetPatientGender() |
1813 | 1813 | self.physician = parser.GetPhysicianReferringName() |
1814 | - | |
1815 | - | |
1814 | + | |
1815 | + | |
1816 | 1816 | class Acquisition(object): |
1817 | 1817 | |
1818 | 1818 | def __init__(self): |
... | ... | @@ -1832,7 +1832,8 @@ class Acquisition(object): |
1832 | 1832 | self.time = parser.GetAcquisitionTime() |
1833 | 1833 | self.protocol_name = parser.GetProtocolName() |
1834 | 1834 | self.serie_number = parser.GetSerieNumber() |
1835 | - | |
1835 | + self.sop_class_uid = parser.GetSOPClassUID() | |
1836 | + | |
1836 | 1837 | class Image(object): |
1837 | 1838 | |
1838 | 1839 | def __init__(self): |
... | ... | @@ -1841,11 +1842,11 @@ class Image(object): |
1841 | 1842 | def SetParser(self, parser): |
1842 | 1843 | self.level = parser.GetImageWindowLevel() |
1843 | 1844 | self.window = parser.GetImageWindowWidth() |
1844 | - | |
1845 | + | |
1845 | 1846 | self.position = parser.GetImagePosition() |
1846 | 1847 | if not (self.position): |
1847 | 1848 | self.position = [1, 1, 1] |
1848 | - | |
1849 | + | |
1849 | 1850 | self.number = parser.GetImageNumber() |
1850 | 1851 | self.spacing = spacing = parser.GetPixelSpacing() |
1851 | 1852 | self.orientation_label = parser.GetImageOrientationLabel() |
... | ... | @@ -1855,18 +1856,18 @@ class Image(object): |
1855 | 1856 | self.size = (parser.GetDimensionX(), parser.GetDimensionY()) |
1856 | 1857 | self.imagedata = parser.GetImageData() |
1857 | 1858 | self.bits_allocad = parser._GetBitsAllocated() |
1858 | - | |
1859 | + | |
1859 | 1860 | if (parser.GetImageThickness()): |
1860 | 1861 | try: |
1861 | 1862 | spacing.append(parser.GetImageThickness()) |
1862 | 1863 | except(AttributeError): |
1863 | - spacing = [1, 1, 1] | |
1864 | + spacing = [1, 1, 1] | |
1864 | 1865 | else: |
1865 | 1866 | try: |
1866 | 1867 | spacing.append(1.5) |
1867 | 1868 | except(AttributeError): |
1868 | 1869 | spacing = [1, 1, 1] |
1869 | - | |
1870 | + | |
1870 | 1871 | spacing[0] = round(spacing[0],2) |
1871 | 1872 | spacing[1] = round(spacing[1],2) |
1872 | 1873 | spacing[2] = round(spacing[2],2) | ... | ... |