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) | ... | ... |