Procházet zdrojové kódy

Moving DICOMtools to separate project

Andrej před 4 roky
rodič
revize
c4a7786ed1

+ 0 - 33
DICOMtools/CMakeLists.txt

@@ -1,33 +0,0 @@
-#-----------------------------------------------------------------------------
-set(MODULE_NAME DICOMtools)
-
-#-----------------------------------------------------------------------------
-set(MODULE_PYTHON_SCRIPTS
-	loadDicom.py
-	importDicom.py
-	exportDicom.py
-	vtkInterface.py
-  )
-
-set(MODULE_PYTHON_RESOURCES
-  Resources/Icons/${MODULE_NAME}.png
-  )
-
-#-----------------------------------------------------------------------------
-slicerMacroBuildScriptedModule(
-  NAME ${MODULE_NAME}
-  SCRIPTS ${MODULE_PYTHON_SCRIPTS}
-  RESOURCES ${MODULE_PYTHON_RESOURCES}
-  WITH_GENERIC_TESTS
-  )
-
-#-----------------------------------------------------------------------------
-if(BUILD_TESTING)
-
-  # Register the unittest subclass in the main script as a ctest.
-  # Note that the test will also be available at runtime.
-  #slicer_add_python_unittest(SCRIPT ${MODULE_NAME}.py)
-
-  # Additional build-time testing
-  #add_subdirectory(Testing)
-endif()

+ 0 - 270
DICOMtools/Resources/Icons/DICOMtools.fig

@@ -1,270 +0,0 @@
-#FIG 3.2  Produced by xfig version 3.2.6a
-Landscape
-Center
-Inches
-Letter
-500.00
-Single
--2
-1200 2
-0 32 #c8c8c8
-0 33 #ded7de
-0 34 #c1c1c1
-0 35 #6e6e6e
-0 36 #c1c1c1
-0 37 #444444
-0 38 #8d8e8d
-0 39 #8d8e8d
-0 40 #717171
-0 41 #adadad
-0 42 #333333
-0 43 #939295
-0 44 #747075
-0 45 #555555
-0 46 #b2b2b2
-0 47 #c1c1c1
-0 48 #c2c2c2
-0 49 #6d6d6d
-0 50 #454545
-0 51 #8d8d8d
-0 52 #8d8e8d
-0 53 #dc9d92
-0 54 #f0ebdf
-0 55 #c2c2c2
-0 56 #e1c7a7
-0 57 #e0e0e0
-0 58 #d1d1d1
-0 59 #ececec
-0 60 #d97a1a
-0 61 #f0e31a
-0 62 #877dc1
-0 63 #afa092
-0 64 #827cdc
-0 65 #d5d5d5
-0 66 #8b8ba4
-0 67 #4a4a4a
-0 68 #8b6b6b
-0 69 #5a5a5a
-0 70 #636363
-0 71 #8d8d8d
-0 72 #b69a73
-0 73 #4192fe
-0 74 #be703b
-0 75 #da7700
-0 76 #d9b700
-0 77 #006400
-0 78 #5a6b3b
-0 79 #d2d2d2
-0 80 #a9a9a9
-0 81 #8d8da3
-0 82 #f2b85d
-0 83 #88986b
-0 84 #646464
-0 85 #d5d5d5
-0 86 #8b8ba4
-0 87 #b6e5fe
-0 88 #85bfeb
-0 89 #bcbcbc
-0 90 #d29552
-0 91 #8d8d8d
-0 92 #97d1fd
-0 93 #8d8d8d
-0 94 #616161
-0 95 #adb1ad
-0 96 #fe9900
-0 97 #d5d5d5
-0 98 #8b8ba4
-0 99 #8b6b6b
-0 100 #8b9b6b
-0 101 #f66b00
-0 102 #5a6b39
-0 103 #8b9b6b
-0 104 #d5d5d5
-0 105 #8b8ba4
-0 106 #8b6b6b
-0 107 #8b9b6b
-0 108 #f66b00
-0 109 #8b9b7b
-0 110 #184a18
-0 111 #d5d5d5
-0 112 #8b8ba4
-0 113 #f6bc5a
-0 114 #8b9b6b
-0 115 #636b9b
-0 116 #8b6b6b
-0 117 #f6f6f6
-0 118 #dd0000
-0 119 #8b9b6b
-0 120 #d5d5d5
-0 121 #8b8ba4
-0 122 #f6bc5a
-0 123 #8b9b6b
-0 124 #d5d5d5
-0 125 #8b8ba4
-0 126 #f6bc5a
-0 127 #8b9b6b
-0 128 #636b9b
-0 129 #526b29
-0 130 #939393
-0 131 #006300
-0 132 #8b8ba4
-0 133 #8b8ba4
-0 134 #8b8ba4
-0 135 #00634a
-0 136 #7b834a
-0 137 #e6bc7b
-0 138 #8b9b7b
-0 139 #a4b4c5
-0 140 #6b6b93
-0 141 #836b6b
-0 142 #529b4a
-0 143 #d5e6e6
-0 144 #526363
-0 145 #186b4a
-0 146 #9ba4b4
-0 147 #fe9300
-0 148 #fe9300
-0 149 #8b6b6b
-0 150 #00634a
-0 151 #7b834a
-0 152 #63737b
-0 153 #e6bc7b
-0 154 #184a18
-0 155 #8b8ba4
-0 156 #f6bc5a
-0 157 #8b9b6b
-0 158 #d5d5d5
-0 159 #8b8ba4
-0 160 #8b6b6b
-0 161 #8b9b6b
-0 162 #d2d2d2
-0 163 #a9a9a9
-0 164 #8d8da3
-0 165 #f2b85d
-0 166 #88986b
-0 167 #d5d5d5
-0 168 #8b8ba4
-0 169 #d5d5d5
-0 170 #8b8ba4
-0 171 #8b6b6b
-0 172 #8b9b6b
-0 173 #d5d5d5
-0 174 #8b8ba4
-0 175 #8b6b6b
-0 176 #8b9b7b
-0 177 #000000
-0 178 #f63829
-0 179 #000000
-0 180 #fefe52
-0 181 #52794a
-0 182 #63995a
-0 183 #c56142
-0 184 #e66942
-0 185 #fe7952
-0 186 #dddddd
-0 187 #8b8ba4
-0 188 #f6bc5a
-0 189 #8b9b6b
-0 190 #636b9b
-0 191 #f6f6f6
-0 192 #d5d5d5
-0 193 #8b6b6b
-0 194 #d2d2d2
-0 195 #a9a9a9
-0 196 #8d8da3
-0 197 #f2b85d
-0 198 #88986b
-0 199 #d2d2d2
-0 200 #a9a9a9
-0 201 #8d8da3
-0 202 #f2b85d
-0 203 #88986b
-0 204 #d2d2d2
-0 205 #a9a9a9
-0 206 #8d8da3
-0 207 #f2b85d
-0 208 #88986b
-0 209 #d2d2d2
-0 210 #a9a9a9
-0 211 #8d8da3
-0 212 #f2b85d
-0 213 #88986b
-0 214 #d2d2d2
-0 215 #a9a9a9
-0 216 #8d8da3
-0 217 #f2b85d
-0 218 #88986b
-0 219 #d5d5d5
-0 220 #8b8ba4
-0 221 #d2d2d2
-0 222 #a9a9a9
-0 223 #8d8da3
-0 224 #f2b85d
-0 225 #88986b
-0 226 #d2d2d2
-0 227 #a9a9a9
-0 228 #8d8da3
-0 229 #f2b85d
-0 230 #88986b
-0 231 #d2d2d2
-0 232 #a9a9a9
-0 233 #8d8da3
-0 234 #f2b85d
-0 235 #88986b
-0 236 #d2d2d2
-0 237 #a9a9a9
-0 238 #8d8da3
-0 239 #f2b85d
-0 240 #88986b
-0 241 #d5d5d5
-0 242 #8b8ba4
-0 243 #f2edd2
-0 244 #f4ad5d
-0 245 #95cd98
-0 246 #a9a9a9
-0 247 #b4157d
-0 248 #ededed
-0 249 #838383
-0 250 #d5d5d5
-0 251 #8b8ba4
-0 252 #f6bc5a
-0 253 #8b9b6b
-0 254 #636b9b
-0 255 #7b7b7b
-0 256 #005a00
-0 257 #e67373
-0 258 #f6f6f6
-0 259 #dd0000
-0 260 #feca31
-0 261 #29794a
-0 262 #dd2821
-0 263 #2159c5
-0 264 #f7f7f7
-0 265 #ededed
-0 266 #e5e5e5
-0 267 #7b834a
-0 268 #d5d5d5
-0 269 #e6bc7b
-0 270 #8b9b7b
-0 271 #a4b4c5
-0 272 #6b6b93
-0 273 #836b6b
-0 274 #529b4a
-0 275 #d5e6e6
-0 276 #9ba4b4
-0 277 #21835a
-0 278 #8b8ba4
-0 279 #f6bc5a
-0 280 #8b9b6b
-0 281 #636b9b
-0 282 #d5d5d5
-0 283 #8b8ba4
-0 284 #f6bc5a
-0 285 #8b9b6b
-0 286 #8b6b6b
-2 2 0 0 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
-	 4500 3000 7125 3000 7125 5625 4500 5625 4500 3000
-2 4 0 1 0 7 50 -1 -1 0.000 0 0 7 0 0 5
-	 6600 4800 6600 3600 5100 3600 5100 4800 6600 4800
-4 0 0 50 -1 4 16 0.0000 4 135 450 5400 4125 DICOM\001
-4 0 0 50 -1 4 14 0.0000 4 135 450 5550 4425 tools\001

binární
DICOMtools/Resources/Icons/DICOMtools.png


binární
DICOMtools/Resources/Screenshots/exportDICOM.png


+ 0 - 20
DICOMtools/Resources/Screenshots/importDICOM.fig

@@ -1,20 +0,0 @@
-#FIG 3.2  Produced by xfig version 3.2.6a
-Landscape
-Center
-Inches
-Letter
-100.00
-Single
--2
-1200 2
-2 4 0 4 8 0 50 -1 -1 0.000 0 0 7 0 0 5
-	 13200 11250 6150 11250 6150 10950 13200 10950 13200 11250
-2 4 0 4 15 0 50 -1 -1 0.000 0 0 7 0 0 5
-	 13200 11625 6150 11625 6150 11325 13200 11325 13200 11625
-2 4 0 4 31 0 50 -1 -1 0.000 0 0 7 0 0 5
-	 13200 12000 6150 12000 6150 11700 13200 11700 13200 12000
-2 4 0 4 18 0 50 -1 -1 0.000 0 0 7 0 0 5
-	 13200 12375 6150 12375 6150 12075 13200 12075 13200 12375
-2 5 0 1 0 -1 55 -1 -1 0.000 0 0 -1 0 0 5
-	0 /data0/studen/data/blog/pelican/content/images/importDICOM.png
-	 4650 3825 17970 3825 17970 18870 4650 18870 4650 3825

binární
DICOMtools/Resources/Screenshots/importDICOM.png


+ 0 - 24
DICOMtools/Resources/Screenshots/loadDICOM.fig

@@ -1,24 +0,0 @@
-#FIG 3.2  Produced by xfig version 3.2.6a
-Landscape
-Center
-Inches
-Letter
-100.00
-Single
--2
-1200 2
-2 4 0 4 8 0 50 -1 -1 0.000 0 0 7 0 0 5
-	 13200 11250 6150 11250 6150 10950 13200 10950 13200 11250
-2 4 0 4 15 0 50 -1 -1 0.000 0 0 7 0 0 5
-	 13200 11625 6150 11625 6150 11325 13200 11325 13200 11625
-2 5 0 1 0 -1 55 -1 -1 0.000 0 0 -1 0 0 5
-	0 /data0/studen/data/blog/pelican/content/images/loadDICOM.png
-	 4650 3825 17970 3825 17970 18870 4650 18870 4650 3825
-2 4 0 4 18 0 50 -1 -1 0.000 0 0 7 0 0 5
-	 13200 12675 6150 12675 6150 12375 13200 12375 13200 12675
-2 4 0 4 31 0 50 -1 -1 0.000 0 0 7 0 0 5
-	 13200 12300 6150 12300 6150 12000 13200 12000 13200 12300
-2 4 0 4 12 0 50 -1 -1 0.000 0 0 7 0 0 5
-	 13200 12000 6150 12000 6150 11700 13200 11700 13200 12000
-2 4 0 4 30 0 50 -1 -1 0.000 0 0 7 0 0 5
-	 13200 12975 6150 12975 6150 12675 13200 12675 13200 12975

binární
DICOMtools/Resources/Screenshots/loadDICOM.png


+ 0 - 415
DICOMtools/exportDicom.py

@@ -1,415 +0,0 @@
-import DICOMLib
-from slicer.ScriptedLoadableModule import *
-import slicerNetwork
-import qt,vtk,ctk,slicer
-import datetime
-import re
-import os
-import slicer.cli
-import json
-
-class exportDicom(slicer.ScriptedLoadableModule.ScriptedLoadableModule):
-  def __init__(self,parent):
-        slicer.ScriptedLoadableModule.ScriptedLoadableModule.__init__(self, parent)
-        self.className="exportDicom"
-        self.parent.title="exportDicom"
-        self.parent.categories = ["LabKey"]
-        self.parent.dependencies = []
-        self.parent.contributors = ["Andrej Studen (University of Ljubljana)"] # replace with "Firstname Lastname (Organization)"
-        self.parent.helpText = """
-        This is an example of scripted loadable module bundled in an extension.
-        It adds hierarchy datat for reliable dicom export of a node
-        """
-        self.parent.helpText += self.getDefaultModuleDocumentationLink()
-        self.parent.acknowledgementText = """
-        This extension developed within Medical Physics research programe of ARRS
-        """ # replace with organization, grant and thanks.
-
-#
-# dataExplorerWidget
-
-
-
-class exportDicomWidget(ScriptedLoadableModuleWidget):
-  """Uses ScriptedLoadableModuleWidget base class, available at:
-  https://github.com/Slicer/Slicer/blob/master/Base/Python/slicer/ScriptedLoadableModule.py
-  """
-
-  def setup(self):
-      ScriptedLoadableModuleWidget.setup(self)
-      self.logic=exportDicomLogic(self)
-
-      try:
-           fhome=os.environ["HOME"]
-      except:
-              #in windows, the variable is called HOMEPATH
-           fhome=os.environ['HOMEDRIVE']+os.environ['HOMEPATH']
-
-      cfgPath=os.path.join(fhome,".labkey")
-      cfgNet=os.path.join(cfgPath,"Remote.json")
-
-      self.project='DICOM/Export'
-      
-      baseUUIDFile=os.path.join(cfgPath,"baseUUID.json")
-      baseUUIDCandidate='0.0.0.0.0'
-      try:
-          print("Opening {}".format(baseUUIDFile))
-          f=open(baseUUIDFile,'r')
-          print("Parsing {}".format(baseUUIDFile))
-          baseUUIDCfg=json.load(f)
-          print("Decoding {}".format(baseUUIDCfg))
-          baseUUIDCandidate=baseUUIDCfg['baseUUID']
-          print("baseUUID {}".format(baseUUIDCandidate))
-          self.project=baseUUIDCfg['project']
-          print("project {}".format(self.project))
-          
-      except IOError:
-          pass
-      except JSONDecodeError:
-          pass
-      except KeyError:
-          pass
-          
-      
-      self.Net=slicerNetwork.labkeyURIHandler()
-      self.Net.parseConfig(cfgNet)
-      self.Net.initRemote()
-
-      
-      datasetCollapsibleButton = ctk.ctkCollapsibleButton()
-      datasetCollapsibleButton.text = "Node data"
-      self.layout.addWidget(datasetCollapsibleButton)
-      # Layout within the dummy collapsible button
-      datasetFormLayout = qt.QFormLayout(datasetCollapsibleButton)
-
-      self.volumeNode=qt.QLineEdit("enter name of the volume Node")
-      datasetFormLayout.addRow("volumeNode:",self.volumeNode)
-      self.patientId=qt.QLineEdit("enter PatientID")
-      datasetFormLayout.addRow("PatientId:",self.patientId)
-      self.studyInstanceUid=qt.QLineEdit("enter study id")
-      datasetFormLayout.addRow("StudyInstanceUid:",self.studyInstanceUid)
-      self.studyDescription=qt.QLineEdit("enter study description")
-      datasetFormLayout.addRow("StudyDescription:",self.studyDescription)
-
-      self.addHierarchyButton=qt.QPushButton("Add hierarchy")
-      self.addHierarchyButton.clicked.connect(self.onAddHierarchyButtonClicked)
-      datasetFormLayout.addRow("Volume:",self.addHierarchyButton)
-      
-      self.baseUUIDText=qt.QLineEdit(baseUUIDCandidate)
-      datasetFormLayout.addRow("Base UUID:",self.baseUUIDText)
-      
-       
-
-      self.exportButton=qt.QPushButton("Export")
-      self.exportButton.clicked.connect(self.onExportButtonClicked)
-      datasetFormLayout.addRow("Export:",self.exportButton)
-
-
-
-  def onAddHierarchyButtonClicked(self):
-      metadata={'patientId':self.patientId.text,
-                'studyDescription':self.studyDescription.text,
-                'studyInstanceUid':self.studyInstanceUid.text,
-                'baseUUID':self.baseUUIDText.text}
-      node=slicer.util.getFirstNodeByName(self.volumeNode.text)
-      if node==None:
-          return
-      self.logic.addHierarchy(node,metadata)
-
-  def onExportButtonClicked(self):
-      metadata={'patientId':self.patientId.text,
-                'studyDescription':self.studyDescription.text,
-                'studyInstanceUid':self.studyInstanceUid.text,
-                'seriesInstanceUid':self.logic.generateSeriesUUID('volume',self.baseUUIDText.text),
-                'frameOfReferenceInstanceUid':self.logic.generateFrameOfReferenceUUID('volume',self.baseUUIDText.text)}
-      node=slicer.util.getFirstNodeByName(self.volumeNode.text)
-      if node==None:
-          return
-      self.logic.exportNodeAsDICOM(self.Net,self.project,node,metadata)
-
-
-
-class exportDicomLogic(slicer.ScriptedLoadableModule.ScriptedLoadableModuleLogic):
-  def __init__(self,parent):
-       slicer.ScriptedLoadableModule.ScriptedLoadableModuleLogic.__init__(self, parent)
-       self.labelUUID={'series':'1','study':'2','instance':'3','frameOfReference':4}
-       self.dataUUID={'volume':'1','segmentation':'2','transformation':'3'}
-
-       try:
-           fhome=os.environ["HOME"]
-       except:
-              #in windows, the variable is called HOMEPATH
-           fhome=os.environ['HOMEDRIVE']+os.environ['HOMEPATH']
-
-
-       self.basePath=os.path.join(fhome,'.dicom')
-
-       if not os.path.isdir(self.basePath):
-           os.mkdir(self.basePath)
-
-       self.itemLabel={
-            'patientName': slicer.vtkMRMLSubjectHierarchyConstants.GetDICOMPatientNameAttributeName(),
-            'modality': slicer.vtkMRMLSubjectHierarchyConstants.GetDICOMSeriesModalityAttributeName(),
-            'patientId': slicer.vtkMRMLSubjectHierarchyConstants.GetDICOMPatientIDAttributeName(),
-            'patientSex': slicer.vtkMRMLSubjectHierarchyConstants.GetDICOMPatientSexAttributeName(),
-            'patientBirthDate': slicer.vtkMRMLSubjectHierarchyConstants.GetDICOMPatientBirthDateAttributeName(),
-            'patientComments': slicer.vtkMRMLSubjectHierarchyConstants.GetDICOMPatientCommentsAttributeName(),
-            'studyDescription': slicer.vtkMRMLSubjectHierarchyConstants.GetDICOMStudyDescriptionAttributeName(),
-            'studyInstanceUid': slicer.vtkMRMLSubjectHierarchyConstants.GetDICOMStudyInstanceUIDTagName(),
-            'studyDate': slicer.vtkMRMLSubjectHierarchyConstants.GetDICOMStudyDateAttributeName(),
-            'studyId': slicer.vtkMRMLSubjectHierarchyConstants.GetDICOMStudyIDTagName(),
-            'studyTime': slicer.vtkMRMLSubjectHierarchyConstants.GetDICOMStudyTimeAttributeName()}
-
-
-
-
-
-
-  def generateStudyUUID(self,type,baseUUID):
-
-        x=datetime.datetime.now()
-        date=x.strftime("%Y%m%d")
-        studyFile=os.path.join(self.basePath,'studyCount'+date+'.txt')
-
-        try:
-            f=open(studyFile,"r")
-            id=int(f.readline())
-            id=id+1
-            f.close()
-        except:
-            id=0
-
-        studyId="{}.{}.{}.{}.{}".format(baseUUID,self.labelUUID['study'],
-                        self.dataUUID[type],date,id)
-
-        f=open(studyFile,"w")
-        f.write("{}".format(id))
-        f.close()
-        return studyId
-
-
-
-
-  def generateSOPInstanceUUID(self,type,baseUUID):
-
-        x=datetime.datetime.now()
-        date=x.strftime("%Y%m%d")
-        instanceFile=os.path.join(self.basePath,'instanceCount'+date+'.txt')
-
-        try:
-            f=open(instanceFile,"r")
-            id=int(f.readline())
-            id=id+1
-            f.close()
-        except:
-            id=0
-
-        instanceId="{}.{}.{}.{}.{}".format(baseUUID,self.labelUUID['instance'],
-                        self.dataUUID[type],date,id)
-
-        f=open(instanceFile,"w")
-        f.write("{}".format(id))
-        f.close()
-        return instanceId
-
-
-  def generateFrameOfReferenceUUID(self,type,baseUUID):
-
-        x=datetime.datetime.now()
-        date=x.strftime("%Y%m%d")
-        forFile=os.path.join(self.basePath,'frameCount'+date+'.txt')
-
-        try:
-            f=open(studyFile,"r")
-            id=int(f.readline())
-            id=id+1
-            f.close()
-        except:
-            id=0
-
-        forId="{}.{}.{}.{}.{}".format(baseUUID,self.labelUUID['frameOfReference'],
-                        self.dataUUID[type],date,id)
-
-        f=open(forFile,"w")
-        f.write("{}".format(id))
-        f.close()
-        return forId
-  
-  def generateSeriesUUID(self,type,baseUUID):
-
-        x=datetime.datetime.now()
-        seriesInstanceUid=baseUUID+'.'+self.labelUUID['series']+'.'
-        seriesInstanceUid+=self.dataUUID[type]+'.'+x.strftime("%Y%m%d")+'.'+getTimeCode(x)
-        return seriesInstanceUid
-
-  def setAttribute(self,shn,itemId,label,metadata):
-        try:
-            shn.SetItemAttribute(itemId,self.itemLabel['modality'],metadata['modality'])
-        except KeyError:
-            pass
-
-  def addHierarchy(self,dataNode,metadata):
-        #convert dataNode to fully fledged DICOM object in hierarchy
-
-        #variation of addSeriesInSubjectHierarchy
-        shn=slicer.vtkMRMLSubjectHierarchyNode.GetSubjectHierarchyNode(slicer.mrmlScene)
-        sceneItemId=shn.GetSceneItemID()
-
-        #add the series for the data node
-        seriesItemId=shn.CreateItem(sceneItemId,dataNode)
-
-        x=datetime.datetime.now()
-        hour=x.strftime("%H")
-        hour=re.sub('^0','',hour)
-        ft=hour+x.strftime("%M%S")
-        seriesInstanceUid=metadata['baseUUID']+'.'+self.labelUUID['series']+'.'
-        seriesInstanceUid+=self.dataUUID['volume']+'.'+x.strftime("%Y%m%d")+'.'+ft
-        shn.SetItemUID(seriesItemId,slicer.vtkMRMLSubjectHierarchyConstants.GetDICOMUIDName(),
-            seriesInstanceUid)
-
-        self.setAttribute(shn,seriesItemId,'modality',metadata)
-        self.setAttribute(shn,seriesItemId,'seriesNumber',metadata)
-
-        #add PatientId
-        try:
-            patientId=metadata['patientId']
-        except KeyError:
-            patientId='Unknown'
-
-        try:
-            studyInstanceUid=metadata['studyInstanceUid']
-        except KeyError:
-            studyInstanceUid=self.generateStudyUUID('volume',metadata['baseUUID'])
-
-        slicer.vtkSlicerSubjectHierarchyModuleLogic.InsertDicomSeriesInHierarchy(shn,patientId,
-            studyInstanceUid,seriesInstanceUid)
-
-        patientItemId=shn.GetItemByUID(slicer.vtkMRMLSubjectHierarchyConstants.GetDICOMUIDName(),patientId)
-
-        self.setAttribute(shn,patientItemId,'patientName',metadata)
-        self.setAttribute(shn,patientItemId,'patientId',metadata)
-        self.setAttribute(shn,patientItemId,'patientSex',metadata)
-        self.setAttribute(shn,patientItemId,'patientBirthDate',metadata)
-        self.setAttribute(shn,patientItemId,'patientComments',metadata)
-
-        patientItemName=patientId
-        shn.SetItemName(patientItemId,patientItemName)
-
-        studyItemId=shn.GetItemByUID(slicer.vtkMRMLSubjectHierarchyConstants.GetDICOMUIDName(),studyInstanceUid)
-
-        self.setAttribute(shn,studyItemId,'studyDescription',metadata)
-        self.setAttribute(shn,studyItemId,'studyInstanceUid',metadata)
-        self.setAttribute(shn,studyItemId,'studyId',metadata)
-        self.setAttribute(shn,studyItemId,'studyDate',metadata)
-        self.setAttribute(shn,studyItemId,'studyTime',metadata)
-
-        studyItemName=studyInstanceUid
-        shn.SetItemName(studyItemId,studyItemName)
-
-  def setTagValue(self,cliparameters,metadata,field):
-       try:
-           cliparameters[field]=metadata[field]
-       except KeyError:
-           pass
-
-  def setDirectoryValue(self,cliparameters,cliKey,metadata,key):
-       try:
-           cliparameters[cliKey]=metadata[key]
-       except KeyError:
-           pass
-
-
-
-  def generateDicom(self, volumeNode, metadata, fdir):
-
-       cliparameters={}
-       tagList=['patientName','patientComments','studyDate','studyTime','studyDescription',
-            'modality','manufacturer','model','seriesDescription',
-            'seriesNumber','seriesDate','seriesTime','contentDate','contentTime']
-
-       for tag in tagList:
-           self.setTagValue(cliparameters,metadata,tag)
-
-       valuePairs={'patientID':'patientId',
-                    'studyID':'studyId',
-                    'seriesInstanceUID':'seriesInstanceUid',
-                    'studyInstanceUID':'studyInstanceUid',
-                    'frameOfReferenceInstanceUID':'frameOfReferenceInstanceUid'}
-
-       for key in valuePairs:
-           self.setDirectoryValue(cliparameters,key,metadata,valuePairs[key])
-
-
-       cliparameters['dicomDirectory']=fdir
-       cliparameters['dicomPrefix']='IMG'
-       cliparameters['inputVolume']=volumeNode.GetID()
-
-       print("[CLI]SeriesInstanceUID: {}").format(cliparameters['seriesInstanceUID'])
-       print("[MeD]SeriesInstanceUID: {}").format(metadata['seriesInstanceUid'])
-
-       try:
-           dicomWrite=slicer.modules.createdicomseries
-       except AttributeError:
-           print("Missing dicom exporter")
-           return
-
-       cliNode=slicer.cli.run(dicomWrite,None,cliparameters,wait_for_completion=True)
-       status=cliNode.GetStatusString()
-       print("Status: {}").format(status)
-       if status.find("error")>-1:
-              print("Error: {}").format(cliNode.GetErrorText())
-              return False
-       return True
-
-
-  def exportNodeAsDICOM(self,net, project,volumeNode,metadata):
-
-
-       #buffed up exportable is now ready to be stored
-       fdir=net.GetLocalCacheDirectory()
-       #project=project.replace('/','\\')
-       fdir=os.path.join(fdir,project)
-       fdir=os.path.join(fdir,'%40files')
-       fdir=os.path.join(fdir,metadata['patientId'])
-       #fdirReg=os.path.join(fdir,'Registration')
-
-       if not os.path.isdir(fdir):
-           os.makedirs(fdir)
-       
-       relDir=net.GetRelativePathFromLocalPath(fdir)
-       remoteDir=net.GetLabkeyPathFromRelativePath(relDir)
-
-       if not net.isRemoteDir(remoteDir):
-            net.mkdir(remoteDir)
-
-              
-       dirName=volumeNode.GetName();
-       dirName=dirName.replace(" ","_")
-       fdir=os.path.join(fdir,dirName)
-
-       if not os.path.isdir(fdir):
-           os.mkdir(fdir)
-
-       relDir=net.GetRelativePathFromLocalPath(fdir)
-       remoteDir=net.GetLabkeyPathFromRelativePath(relDir)
-
-       if not net.isRemoteDir(remoteDir):
-            net.mkdir(remoteDir)
-
-       if not self.generateDicom(volumeNode,metadata,fdir):
-           return
-
-       for f in os.listdir(fdir):
-           localPath=os.path.join(fdir,f)
-           print("localPath: {}").format(localPath)
-           relativePath=net.GetRelativePathFromLocalPath(localPath)
-           print("relativePath: {}").format(relativePath)
-           remotePath=net.GetLabkeyPathFromRelativePath(relativePath)
-           print("remotePath: {}").format(relativePath)
-           net.copyLocalFileToRemote(localPath,remotePath)
-
-def getTimeCode(x):
-    hour=x.strftime("%H")
-    hour=re.sub('^0','',hour)
-    return hour+x.strftime("%M%S")
-  

+ 0 - 367
DICOMtools/importDicom.py

@@ -1,367 +0,0 @@
-import pydicom
-import vtkInterface as vi
-import os
-import vtk, qt, ctk, slicer
-from slicer.ScriptedLoadableModule import *
-import slicerNetwork
-import json
-import loadDicom
-import DICOMLib
-
-class importDicom(slicer.ScriptedLoadableModule.ScriptedLoadableModule):
-    def __init__(self,parent):
-        slicer.ScriptedLoadableModule.ScriptedLoadableModule.__init__(self, parent)
-        self.className="importDICOM"
-        self.parent.title="importDICOM"
-        self.parent.categories = ["LabKey"]
-        self.parent.dependencies = []
-        self.parent.contributors = ["Andrej Studen (UL/FMF)"] # replace with "Firstname Lastname (Organization)"
-        self.parent.helpText = """
-                utilities for parsing dicom entries
-                """
-        self.parent.acknowledgementText = """
-                Developed within the medical physics research programme of the Slovenian research agency.
-                """ # replace with organization, grant and thanks.
-
-class importDicomWidget(slicer.ScriptedLoadableModule.ScriptedLoadableModuleWidget):
-  """Uses ScriptedLoadableModuleWidget base class, available at:
-  https://github.com/Slicer/Slicer/blob/master/Base/Python/slicer/ScriptedLoadableModule.py
-  """
-
-  def setup(self):
-      
-    slicer.ScriptedLoadableModule.ScriptedLoadableModuleWidget.setup(self)
-    self.logic=importDicomLogic(self)
-    self.network=slicerNetwork.labkeyURIHandler()
-    
-    connectionCollapsibleButton = ctk.ctkCollapsibleButton()
-    connectionCollapsibleButton.text = "Connection"
-    self.layout.addWidget(connectionCollapsibleButton)
-
-    connectionFormLayout = qt.QFormLayout(connectionCollapsibleButton)
-    
-    self.loadConfigButton=qt.QPushButton("Load configuration")
-    self.loadConfigButton.toolTip="Load configuration"
-    self.loadConfigButton.connect('clicked(bool)',self.onLoadConfigButtonClicked)
-    connectionFormLayout.addRow("Connection:",self.loadConfigButton)
-
-    self.DICOMDirectory=qt.QLineEdit("Test/Temp/%40files/TEST/MLEM")
-    connectionFormLayout.addRow("LabKey directory:",self.DICOMDirectory)
-
-
-    #loadDICOMButton=qt.QPushButton("Load")
-    #loadDICOMButton.toolTip="Load DICOM"
-    #loadDICOMButton.clicked.connect(self.onLoadDICOMButtonClicked)
-    #connectionFormLayout.addRow("DICOM:",loadDICOMButton)
-
-    self.DICOMFilter=qt.QLineEdit('{"seriesNumber":"SeriesLabel"}')
-    connectionFormLayout.addRow("Filter(JSON):",self.DICOMFilter)
-
-    loadDICOMFilterButton=qt.QPushButton("Load with filter")
-    loadDICOMFilterButton.toolTip="Load DICOM with filter"
-    loadDICOMFilterButton.clicked.connect(self.onLoadDICOMFilterButtonClicked)
-    connectionFormLayout.addRow("DICOM:",loadDICOMFilterButton)
-
-  def onLoadConfigButtonClicked(self):
-       filename=qt.QFileDialog.getOpenFileName(None,'Open configuration file (JSON)',
-            os.path.join(os.path.expanduser('~'),'.labkey'), '*.json')
-       self.network.parseConfig(filename)
-       self.network.initRemote()
-       self.loadConfigButton.setText(os.path.basename(filename))
-  
-  def onLoadDICOMFilterButtonClicked(self):
-      filter=json.loads(self.DICOMFilter.text)
-      #print("Filter is {}".format(filter))
-      self.logic.loadVolumes(self.network,self.DICOMDirectory.text,filter)
-    
-  def onLoadDICOMButtonClicked(self):
-      self.logic.load(self.network,self.DICOMDirectory.text)
-       
-
-
-#equivalent of loadable + labkey interface
-class dicomSeries():
-    def __init__(self):
-        self.data = []
-        self.idx = []
-        self.z = []
-        self.pixel_size = [0,0,0]
-        self.lpsOrigin = [0,0,0]
-        self.lpsOrigin[2]=1e30
-        self.lpsOrientation=[0,0,0,0,0,0]
-        self.local=False
-
-
-    def getfile(self,net,relativePath):
-        if self.local:
-                return open(relativePath,'rb')
-        return net.readFileToBuffer(relativePath)
-
-    def addFile(self,f):
-        try:
-            self.files.append(f)
-        except:
-            self.files=[f]
-
-    def setLabel(self,label):
-        self.label=label
-
-    def getLabel(self):
-        try:
-            return self.label
-        except:
-            return None
-
-    def setMetadata(self,key,value):
-        try:
-            self.metadata[key]=value
-        except:
-            self.metadata={key:value}
-
-    def getMetadata(self):
-        try:
-            return self.metadata
-        except:
-            return {}
-
-            
-
-    def load(self,net):
-
-        for f in self.files:
-            print('{}:'.format(f))
-            fileBuffer=self.getfile(net,f)
-            self.loadFile(fileBuffer)
-
-        nz=len(self.idx)
-        sh=self.data[-1].shape
-        sh_list=list(sh)
-        sh_list.append(nz)
-        data_array=np.zeros(sh_list)
-
-        for k in range(0,nz):
-            kp=int(np.round((self.z[k]-self.center[2])/self.pixel_size[2]))
-            data_array[:,:,kp]=np.transpose(self.data[k])
-
-        try:
-            nodeName='Series'+self.label
-        except:
-            print('Could not set series label')
-            nodeName='UnknownSeries'
-
-        newNode=slicer.vtkMRMLScalarVolumeNode()
-        newNode.SetName(nodeName)
-
-        ijkToRAS = vtk.vtkMatrix4x4()
-        #think how to do this with image orientation
-
-        rasOrientation=[-self.lpsOrientation[i] if (i%3 < 2) else self.lpsOrientation[i]
-          for i in range(0,len(self.lpsOrientation))]
-        rasOrigin=[-self.lpsOrigin[i] if (i%3<2) else self.lpsOrigin[i] for i in range(0,len(self.lpsOrigin))]
-
-        for i in range(0,3):
-             for j in range(0,3):
-                 ijkToRAS.SetElement(i,j,self.pixel_size[i]*rasOrientation[3*j+i])
-
-             ijkToRAS.SetElement(i,3,rasOrigin[i])
-
-        newNode.SetIJKToRASMatrix(ijkToRAS)
-
-        v=vtk.vtkImageData()
-        v.GetPointData().SetScalars(
-            vtk.util.numpy_support.numpy_to_vtk(
-                np.ravel(self.data,order='F'),deep=True, array_type=vtk.VTK_FLOAT))
-        v.SetOrigin(0,0,0)
-        v.SetSpacing(1,1,1)
-        v.SetDimensions(self.data.shape)
-
-        newNode.SetAndObserveImageData(v)
-        slicer.mrmlScene.AddNode(newNode)
-        volume={'node':newNode,'metadata':self.metadata}
-        return volume
-
-    def loadFile(self,fileBuffer):
-
-        plan=pydicom.dcmread(fileBuffer)
-
-        self.data.append(plan.pixel_array)
-        self.idx.append(plan.InstanceNumber)
-        self.z.append(plan.ImagePositionPatient[2])
-
-
-        #pixelSize
-        pixel_size=[plan.PixelSpacing[0],plan.PixelSpacing[1],
-                    plan.SliceThickness]
-
-        for i in range(0,3):
-            if self.pixel_size[i] == 0:
-                self.pixel_size[i] = float(pixel_size[i])
-            if abs(self.pixel_size[i]-pixel_size[i]) > 1e-3:
-                print('Pixel size mismatch {.2f}/{.2f}'.\
-                        format(self.pixel_size[i],pixel_size[i]))
-
-        #origin
-        for i in range(0,2):
-            if self.lpsOrigin[i] == 0:
-                self.lpsOrigin[i] = float(plan.ImagePositionPatient[i])
-            if abs(self.lpsOrigin[i]-plan.ImagePositionPatient[i]) > 1e-3:
-                print('Image center mismatch {.2f}/{.2f}'.\
-                        format(self.lpsOrigin[i],\
-                        plan.ImagePositionPatient[i]))
-        #not average, but minimum (!) why??
-
-        if plan.ImagePositionPatient[2]<self.lpsOrigin[2]:
-            self.lpsOrigin[2]=plan.ImagePositionPatient[2]
-
-
-        #orientation
-        for i in range(0,6):
-            if self.lpsOrientation[i] == 0:
-                self.lpsOrientation[i] = float(plan.ImageOrientationPatient[i])
-            if abs(self.lpsOrientation[i]-plan.ImageOrientationPatient[i]) > 1e-3:
-                print('Image orientation mismatch {0:.2f}/{1:.2f}'.\
-                        format(self.lpsOrientation[i],\
-                        plan.ImageOrientationPatient[i]))
-
-        return True
-
-class importDicomLogic(slicer.ScriptedLoadableModule.ScriptedLoadableModuleLogic):
-    def __init__(self,parent):
-        slicer.ScriptedLoadableModule.ScriptedLoadableModuleLogic.__init__(self, parent)
-        self.local=False
-        self.tag={
-        'studyInstanceUid':0x0020000d,
-        'seriesInstanceUid':0x0020000e,
-        'patientId':0x00100020,
-        'patientName':0x00100010,
-        'sequenceName':0x00180024,
-        'seriesNumber':0x00200011,
-        'percentPhaseFieldOfView':0x00180094,
-        'modality': 0x00080060,
-        'patientSex': 0x00100040,
-        'patientBirthDate': 0x00100030,
-        'patientComments': 0x00104000,
-        'studyDescription': 0x00081030,
-        'studyDate': 0x00080020,
-        'studyId': 0x00200010,
-        'studyTime': 0x00080030,
-        'frameOfReferenceInstanceUid':0x00200052}
-    
-
-
-    def setLocal(self, basePath):
-        self.local=True
-        self.basePath=basePath
-
-        
-    def loadVolumes(self,net,directory,filter):
-        #mimic examineForImport
-        seriesList=self.examineForImport(net,directory,filter)
-        print("Got {} series").format(len(seriesList))
-        volumes=[]
-
-        for s in seriesList:
-            try:
-                volumes.append(s.load(net))
-                #often fails, e.g. JPEGLossles
-            except:
-                loadable=DICOMLib.DICOMLoadable()
-                loadable.name='Series'+str(s.getLabel())
-                print("Loading for {} number of files (pre-load) {}").\
-                        format(loadable.name,len(s.files))
-                loadable.files=[net.DownloadFileToCache(f) for f in s.files]
-                print("Loading for {} number of files (pre-sort) {}").\
-                        format(loadable.name,len(loadable.files))
-
-                loadable.files,distances,loadable.warning=\
-                        DICOMLib.DICOMUtils.getSortedImageFiles(\
-                        loadable.files,1e-3)
-
-                print("Loading for {} number of files {}").\
-                        format(loadable.name,len(loadable.files))
-                try:
-                    volumeNode=self.volumePlugin.load(loadable)
-                except:
-                    self.volumePlugin=\
-                            slicer.modules.dicomPlugins['DICOMScalarVolumePlugin']()
-                    volumeNode=self.volumePlugin.load(loadable)
-                volume={'node':volumeNode,'metadata':s.getMetadata()}
-                volumes.append(volume)
-
-
-        return volumes
-
-
-    def listdir(self,net,relativeDirectory):
-        if self.local:
-            dirs=os.listdir(os.path.join(self.basePath,relativeDirectory))
-            return [os.path.join(relativeDirectory,dir) for dir in dirs]
-        return net.listRelativeDir(relativeDirectory)
-
-    def getfile(self,net,relativePath):
-        if self.local:
-            return open(os.path.join(self.basePath,relativePath),'rb')
-        return net.readFileToBuffer(relativePath)
-
-    def examineForImport(self,net,directory,filter):
-        #split by series
-        seriesList=[]
-
-        files=self.listdir(net,directory)
-        if len(files)==0:
-            print("No input found in {}".format(directory))
-            return seriesList
-
-
-        for f in files:
-            fileBuffer=self.getfile(net,f)
-
-            #validate
-            try:
-                plan = pydicom.dcmread(fileBuffer)
-            except:
-                print ("{}: Not a dicom file")
-                continue
-
-            #determine validity first
-            fileValid=True
-            for key in filter:
-                if filter[key]==None:
-                    continue
-                if filter[key]=='SeriesLabel':
-                    seriesTag=self.tag[key]
-                    continue
-
-                v=plan[self.tag[key]].value
-                if not v==filter[key]:
-                    print('Filter mismatch {}{:x}: {}/{}').format(key,self.tag[key],v,filter[key])
-                    fileValid=False
-
-            if not fileValid:
-                continue
-
-            #determine serieslabel second
-            seriesLabel=plan[seriesTag].value
-                
-            try:
-                if series.getLabel()==seriesLabel:
-                    series.addFile(f)
-                    continue
-            except NameError:
-                pass
-
-            #add new series
-            seriesList.append(dicomSeries())
-            series=seriesList[-1]
-            series.local=self.local
-
-            #set series parameters
-            series.addFile(f)
-            series.setLabel(seriesLabel)
-            for key in filter:
-                if not filter[key]==None:
-                    continue
-                v=plan[self.tag[key]].value
-                series.setMetadata(key,v)
-
-        return seriesList

+ 0 - 516
DICOMtools/loadDicom.py

@@ -1,516 +0,0 @@
-import slicer
-import os
-import subprocess
-import re
-import slicerNetwork
-import ctk,qt
-import json
-
-dicomModify=os.getenv("HOME")
-if not dicomModify==None:
-    dicomModify+="/software/install/"
-    dicomModify+="dicomModify/bin/dicomModify"
-
-class loadDicom(slicer.ScriptedLoadableModule.ScriptedLoadableModule):
-    def __init__(self,parent):
-        slicer.ScriptedLoadableModule.ScriptedLoadableModule.__init__(self, parent)
-        self.className="loadDicom"
-        self.parent.title="loadDicom"
-        self.parent.categories = ["LabKey"]
-        self.parent.dependencies = []
-        self.parent.contributors = ["Andrej Studen (UL/FMF)"] # replace with "Firstname Lastname (Organization)"
-        self.parent.helpText = """
-            utilities for parsing dicom entries
-            """
-        self.parent.acknowledgementText = """
-            Developed within the medical physics research programme of the Slovenian research agency.
-            """ # replace with organization, grant and thanks.
-
-class loadDicomWidget(slicer.ScriptedLoadableModule.ScriptedLoadableModuleWidget):
-  """Uses ScriptedLoadableModuleWidget base class, available at:
-  https://github.com/Slicer/Slicer/blob/master/Base/Python/slicer/ScriptedLoadableModule.py
-  """
-
-  def setup(self):
-    slicer.ScriptedLoadableModule.ScriptedLoadableModuleWidget.setup(self)
-    self.logic=loadDicomLogic(self)
-    self.network=slicerNetwork.labkeyURIHandler()
-    
-    connectionCollapsibleButton = ctk.ctkCollapsibleButton()
-    connectionCollapsibleButton.text = "Connection"
-    self.layout.addWidget(connectionCollapsibleButton)
-
-    connectionFormLayout = qt.QFormLayout(connectionCollapsibleButton)
-    
-    self.loadConfigButton=qt.QPushButton("Load configuration")
-    self.loadConfigButton.toolTip="Load configuration"
-    self.loadConfigButton.connect('clicked(bool)',self.onLoadConfigButtonClicked)
-    connectionFormLayout.addRow("Connection:",self.loadConfigButton)
-
-    self.DICOMDirectory=qt.QLineEdit("Test/Temp/%40files/TEST/MLEM")
-    connectionFormLayout.addRow("LabKey directory:",self.DICOMDirectory)
-
-
-    loadDICOMButton=qt.QPushButton("Load")
-    loadDICOMButton.toolTip="Load DICOM"
-    loadDICOMButton.clicked.connect(self.onLoadDICOMButtonClicked)
-    connectionFormLayout.addRow("DICOM:",loadDICOMButton)
-
-    self.DICOMFilter=qt.QLineEdit('{"seriesNumber":"SeriesLabel"}')
-    connectionFormLayout.addRow("Filter(JSON):",self.DICOMFilter)
-
-    loadDICOMFilterButton=qt.QPushButton("Load with filter")
-    loadDICOMFilterButton.toolTip="Load DICOM with filter"
-    loadDICOMFilterButton.clicked.connect(self.onLoadDICOMFilterButtonClicked)
-    connectionFormLayout.addRow("DICOM:",loadDICOMFilterButton)
-
-    loadDICOMSegmentationFilterButton=qt.QPushButton("Load segmentation with filter")
-    loadDICOMSegmentationFilterButton.toolTip="Load DICOM (RT contour) with filter"
-    loadDICOMSegmentationFilterButton.clicked.connect(self.onLoadDICOMSegmentationFilterButtonClicked)
-    connectionFormLayout.addRow("DICOM:",loadDICOMSegmentationFilterButton)
-
-
-  def onLoadConfigButtonClicked(self):
-       filename=qt.QFileDialog.getOpenFileName(None,'Open configuration file (JSON)',
-            os.path.join(os.path.expanduser('~'),'.labkey'), '*.json')
-       self.network.parseConfig(filename)
-       self.network.initRemote()
-       self.loadConfigButton.setText(os.path.basename(filename))
-  
-  def onLoadDICOMFilterButtonClicked(self):
-      filter=json.loads(self.DICOMFilter.text)
-      #print("Filter is {}".format(filter))
-      self.logic.loadVolumes(self.network,self.DICOMDirectory.text,filter)
-    
-  def onLoadDICOMSegmentationFilterButtonClicked(self):
-      filter=json.loads(self.DICOMFilter.text)
-      #print("Filter is {}".format(filter))
-      self.logic.loadSegmentations(self.network,self.DICOMDirectory.text,filter)
-  
-  def onLoadDICOMButtonClicked(self):
-      self.logic.load(self.network,self.DICOMDirectory.text)
-       
-
-class loadDicomLogic(slicer.ScriptedLoadableModule.ScriptedLoadableModuleLogic):
-    def __init__(self,parent):
-        slicer.ScriptedLoadableModule.ScriptedLoadableModuleLogic.__init__(self, parent)
-
-        self.tag={
-              'sopInstanceUid' : {'tag':"0008,0018",'VR':'UI'},
-              'studyDate': {'tag':"0008,0020",'VR':'DA'},
-              'studyTime': {'tag':"0008,0030",'VR':'TM'},
-              'seriesTime': {'tag':"0008,0031",'VR':'TM'},
-              'modality': {'tag':"0008,0060",'VR':'CS'},
-              'presentationIntentType': {'tag':"0008,0068",'VR':'CS'},
-              'manufacturer': {'tag':"0008,0070",'VR':'LO'},
-              'institutionName': {'tag':"0008,0080",'VR':'LO'},
-              'studyDescription': {'tag':"0008,1030",'VR':'LO'},
-              'seriesDescription': {'tag':"0008,103e",'VR':'LO'},
-              'manufacturerModelName': {'tag':"0008,1090",'VR':'LO'},
-              'patientName': {'tag':"0010,0010",'VR':'PN'},
-              'patientId': {'tag':"0010,0020",'VR':'LO'},
-              'patientBirthDate': {'tag':"0010,0030",'VR':'DA'},
-              'patientSex': {'tag':"0010,0040",'VR':'CS'},
-              'patientAge': {'tag':"0010,1010",'VR':'AS'},
-              'patientComments': {'tag':"0010,4000",'VR':'LT'},
-              'sequenceName': {'tag':"0018,0024",'VR':'SH'},
-              'kVP': {'tag':"0018,0060",'VR':'DS'},
-              'percentPhaseFieldOfView': {'tag':"0018,0094",'VR':'DS'},
-              'xRayTubeCurrent': {'tag':"0018,1151",'VR':'IS'},
-              'exposure': {'tag':"0018,1152",'VR':'IS'},
-              'imagerPixelSpacing': {'tag':"0018,1164",'VR':'DS'},
-              'bodyPartThickness': {'tag':"0018,11a0",'VR':'DS'},
-              'compressionForce': {'tag':"0018,11a2",'VR':'DS'},
-              'viewPosition': {'tag':"0018,5101",'VR':'CS'},
-              'fieldOfViewHorizontalFlip': {'tag':"0018,7034",'VR':'CS'},
-              'studyInstanceUid': {'tag':"0020,000d",'VR':'UI'},
-              'seriesInstanceUid': {'tag':"0020,000e",'VR':'UI'},
-              'studyId': {'tag':"0020,0010",'VR':'SH'},
-              'seriesNumber': {'tag':"0020,0011",'VR':'IS'},
-              'instanceNumber': {'tag':"0020,0013",'VR':'IS'},
-              'frameOfReferenceInstanceUid': {'tag':"0020,0052",'seqTag':"3006,0010",'VR':'UI'},
-              'imageLaterality': {'tag':"0020,0062",'VR':'CS'},
-              'imagesInAcquisition': {'tag':"0020,1002",'VR':'IS'},
-              'photometricInterpretation': {'tag':"0028,0004",'VR':'CS'},
-              'reconstructionMethod': {'tag':"0054,1103",'VR':'LO'}
-        }
-        self.tagPyDicom={
-              'studyDate': 0x00080020,
-              'studyTime': 0x00080030,
-              'modality': 0x00080060,
-              'presentationIntentType': 0x00080068,
-              'manufacturer': 0x00080070,
-              'studyDescription': 0x00081030,
-              'seriesDescription': 0x0008103e,
-              'patientName': 0x00100010,
-              'patientId': 0x00100020,
-              'patientBirthDate': 0x00100030,
-              'patientSex': 0x00100040,
-              'patientComments': 0x00104000,
-              'sequenceName': 0x00180024,
-              'kVP': 0x00180060,
-              'percentPhaseFieldOfView': 0x00180094,
-              'xRayTubeCurrent': 0x00181151,
-              'exposure': 0x00181152,
-              'imagerPixelSpacing': 0x00181164,
-              'bodyPartThickness': 0x001811a0,
-              'compressionForce': 0x001811a2,
-              'viewPosition': 0x00185101,
-              'studyInstanceUid': 0x0020000d,
-              'seriesInstanceUid': 0x0020000e,
-              'studyId': 0x00200010,
-              'seriesNumber': 0x00200011,
-              'instanceNumber': 0x00200013,
-              'frameOfReferenceInstanceUid': 0x00200052
-              }
-      #new_dict_items={
-      #        0x001811a0: ('DS','BodyPartThickness','Body Part Thickness')
-      #}
-      #dicom.datadict.add_dict_entries(new_dict_items)
-        self.local=False
-        self.useDicomModify=False
-
-    def enableDicomModify(self):
-        self.useDicomModify=True
-
-    def setLocal(self,basePath):
-        self.local=True
-        self.basePath=basePath
-        
-
-    def getHex(self,key):
-        #convert string to hex key;
-        fv=key.split(",")
-        return int(fv[0],16)*0x10000+int(fv[1],16)
-
-    def load(self,sNet,dir,doRemove=True):
-        #load directory using DICOMLib tools
-
-        print("Loading dir {}").format(dir)
-        dicomFiles=self.listdir(sNet,dir)
-        
-        filelist=[]
-        for f in dicomFiles:
-                localPath=self.getfile(sNet,f)
-                filelist.append(localPath)
-                if not self.useDicomModify:
-                    continue
-                if dicomModify==None:
-                    continue
-                f0=localPath
-                f1=f0+"1"
-                try:
-                   subprocess.call(\
-                           dicomModify+" "+f0+" "+f1+" && mv "+f1+" "+f0+";", 
-                           shell=True)
-                except OSError:
-                   print("dicomModify failed")
-
-        try:
-            loadables=self.volumePlugin.examineForImport([filelist])
-        except AttributeError:
-            self.volumePlugin=slicer.modules.dicomPlugins['DICOMScalarVolumePlugin']()
-            loadables=self.volumePlugin.examineForImport([filelist])
-
-
-        for loadable in loadables:
-            #check if it makes sense to load a particular loadable
-            
-            if loadable.name.find('imageOrientationPatient')>-1:
-                continue
-            filter={}
-            filter['seriesNumber']=None 
-            metadata={}
-            if not self.applyFilter(loadable,filter,metadata):
-                continue
-            volumeNode=self.volumePlugin.load(loadable)
-            if volumeNode != None:
-                vName='Series'+metadata['seriesNumber']
-                volumeNode.SetName(vName)
-
-        try:
-            loadableRTs=self.RTPlugin.examineForImport([filelist])
-        except:
-            self.RTPlugin=plugin=slicer.modules.dicomPlugins['DicomRtImportExportPlugin']()
-            loadableRTs=self.RTPlugin.examineForImport([filelist])
-
-        for loadable in loadableRTs:
-            segmentationNode=self.RTPlugin.load(loadable)
-           
-        if not doRemove:
-            return
-
-        for f in filelist:
-            self.removeLocal(f)
-
-    def applyFilter(self,loadable,filter,nodeMetadata):
-        #apply filter to loadable.file[0]. Return true if file matches prescribed filter and
-        #false otherwise
-
-        #filter is a directory with keys equal to pre-specified values listed above
-        #if value associated to key equals None, that value gets set in nodeMetadata
-        #if value is set, a match is attempted and result reported in return value
-        #all filters should match for true output
-
-        return self.applyFilterFile(loadable.files[0],filter,nodeMetadata)
-    
-    def applyFilterFile(self,file,filter,nodeMetadata,shell=False):
-        #apply filter to file. Return true if file matches prescribed filter and
-        #false otherwise
-
-        #filter is a directory with keys equal to pre-specified values listed above
-        #if value associated to key equals None, that value gets set in nodeMetadata
-        #if value is set, a match is attempted and result reported in return value
-        #all filters should match for true output
-
-        filterOK=True
-        
-        for key in filter:
-            try:
-                fileValue=dicomValue(file,self.tag[key]['tag'],self.tag[key]['seqTag'],shell=shell)
-            except KeyError:
-                fileValue=dicomValue(file,self.tag[key]['tag'],shell=shell)
-
-
-            if filter[key]=="SeriesLabel":
-                nodeMetadata['seriesLabel']=fileValue
-                continue
-
-            if not filter[key]==None:
-                if not fileValue==filter[key]:
-                    #print("File {} failed for tag {}: {}/{}").format(\
-                    #    file,key,fileValue,filter[key])
-                    filterOK=False
-                    break
-
-            nodeMetadata[key]=fileValue
-
-
-        return filterOK
-
-    def listdir(self,sNet,dir):
-        #list remote directory
-        if self.local:
-            dir1=os.path.join(self.basePath,dir)
-            dirs=os.listdir(dir1)
-            return [os.path.join(dir1,f) for f in dirs]
-        return sNet.listRelativeDir(dir)
-
-    def getfile(self,sNet,file):
-        #get remote file
-        if self.local:
-            return file
-        return sNet.DownloadFileToCache(file)
-
-    def removeLocal(self,localFile):
-        if self.local:
-            return
-        os.remove(localFile)
-        
-
-    def loadVolumes(self,sNet,dir,filter,doRemove=True):
-    #returns all series from the directory, each as a separate node in a node list
-    #filter is a dictionary of speciifed dicom values, if filter(key)=None, that values
-    #get set, if it isn't, the file gets checked for a match
-
-        print("Loading dir {}").format(dir)
-        dicomFiles=self.listdir(sNet,dir)
-        #filelist=[os.path.join(dir,f) for f in os.listdir(dir)]
-        filelist=[]
-        for f in dicomFiles:
-            localPath=self.getfile(sNet,f)
-            f0=localPath
-            f1=f0+"1"
-            if not dicomModify==None:
-                try:
-                    subprocess.call(dicomModify+" "+f0+" "+f1+" && mv "+f1+" "+f0+";", shell=False)
-                except OSError:
-                    print("dicomModify failed")
-            filelist.append(localPath)
-
-        try:
-            loadables=self.volumePlugin.examineForImport([filelist])
-        except AttributeError:
-            self.volumePlugin=slicer.modules.dicomPlugins['DICOMScalarVolumePlugin']()
-            loadables=self.volumePlugin.examineForImport([filelist])
-
-
-        volumeNodes=[]
-        print("Number of loadables:{}").format(len(loadables))
-        for loadable in loadables:
-            #TODO check if it makes sense to load a particular loadable
-
-            print("{}: Checking number of files: {}".format(\
-                    loadable.name,len(loadable.files)))
-            
-            #perform checks
-            fileMetadata={}
-            loadable.files[:]=[f for f in loadable.files \
-                    if self.applyFilterFile(f,filter,fileMetadata)]
-            
-            if len(loadable.files)<1:
-                #skip this loadable
-                continue
-
-            print("{}: Final number of files: {}".format(\
-                    loadable.name,len(loadable.files)))
-            
-            nodeMetadata={}
-            self.applyFilterFile(loadable.files[0],filter,nodeMetadata)
-
-
-
-            volumeNode=self.volumePlugin.load(loadable,"DCMTK")
-            if volumeNode != None:
-                vName='Series'+nodeMetadata['seriesLabel']
-                volumeNode.SetName(vName)
-                volume={'node':volumeNode,'metadata':nodeMetadata}
-                volumeNodes.append(volume)
-
-        if self.local:
-            return volumeNodes
-
-        if doRemove:
-            for f in filelist:
-                self.removeLocal(f)
-
-        return volumeNodes
-
-    def loadSegmentations(self,net,dir,filter,doRemove=True):
-
-        print("Loading dir {}").format(dir)
-        dicomFiles=self.listdir(net,dir)
-        filelist=[self.getfile(net,f) for f in dicomFiles]
-        segmentationNodes=[]
-
-        try:
-            loadableRTs=self.RTPlugin.examineForImport([filelist])
-        except:
-            self.RTPlugin=plugin=slicer.modules.dicomPlugins['DicomRtImportExportPlugin']()
-            loadableRTs=self.RTPlugin.examineForImport([filelist])
-
-        for loadable in loadableRTs:
-
-            nodeMetadata={}
-            filterOK=self.applyFilter(loadable,filter,nodeMetadata)
-
-            if not filterOK:
-                continue
-
-            success=self.RTPlugin.load(loadable)
-
-            if not success:
-                print("Could not load RT structure set")
-                return
-
-            segNodes=slicer.util.getNodesByClass("vtkMRMLSegmentationNode")
-            segmentationNode=segNodes[0]
-            #assume we loaded the first node in list
-
-            if segmentationNode != None:
-                sName='Segmentation'+nodeMetadata['seriesLabel']
-                segmentationNode.SetName(sName)
-                segmentation={'node':segmentationNode,'metadata':nodeMetadata}
-                segmentationNodes.append(segmentation)
-
-        if not doRemove:
-            return segmentationNodes
-        
-        for f in filelist:
-            self.removeLocal(f)
-
-        return segmentationNodes
-
-def isDicom(file):
-    #check if file is a dicom file
-    try:
-        f=open(file,'rb')
-    except IOError:
-        return False
-
-    f.read(128)
-    dt=f.read(4)
-    f.close()
-    return dt=='DICM'
-
-
-def dicomValue(fileName,tag,seqTag=None,shell=False):
-    #query dicom value of file using dcmdump (DCMTK routine)
-
-    #shell must be false for *nix
-    if os.name=="posix":
-        shell=False
-
-    debug=False
-    dcmdump=os.path.join(os.environ['SLICER_HOME'],"bin","dcmdump")
-    
-    try:
-        if debug:
-            print("Calling {}".format(dcmdump))
-        out=subprocess.check_output([dcmdump,'+p','+P',tag,fileName],shell=shell)
-        if debug:
-            print("Got {}".format(out))
-    except subprocess.CalledProcessError as e:
-        return None
-    
-    
-    if debug:
-        print("Tag {} Line '{}'").format(tag,out)
-    if len(out)==0:
-        return out
-
-    #parse multi-match outputs which appear as several lines
-    lst=out.split('\n')
-    return getTagValue(lst,tag,seqTag)
-    
-def getTagValue(lst,tag,seqTag=None):
-    #report tag value from a list lst of lines reported by dcmdump        
-    
-    debug=False
-    
-    #parse output
-    longTag="^\({}\)".format(tag)
-    #combine sequence and actual tags to long tags
-    if not seqTag==None:
-        if debug:
-            print("Tag:{} seqTag:{}").format(tag,seqTag)
-        longTag="^\({}\).\({}\)".format(seqTag,tag)
-    
-    #pick the values
-    pattern=r'^.*\[(.*)\].*$'
-    
-    #extract tag values
-    rpl=[re.sub(pattern,r'\1',f) for f in lst]
-    
-    #logical whether the line can be matched to typical dcmdump output
-    mtchPattern=[re.match(pattern,f) for f in lst]
-    #find matching tags
-    mtchTag=[re.match(longTag,f) for f in lst]
-    
-    #weed out non-matching lines and lines not matching longTag
-    mtch=[None if x==None or y==None else x \
-            for x,y in zip(mtchTag,mtchPattern)]
-    #set values 
-    out=[x for y,x in zip(mtch,rpl) if not y==None]
-    if len(out)==0:
-        return ''
-    #return first match
-    out=out[0]
-    
-    if debug:
-        print("Tag {} Parsed value {}").format(tag,out)
-    #split output to lists if values are DICOM lists
-    if out.find('\\')>-1:
-        out=out.split('\\')
-
-    return out
-        
-
-def clearNodes():
-    nodes=[]
-    nodes.extend(slicer.util.getNodesByClass("vtkMRMLScalarVolumeNode"))
-    nodes.extend(slicer.util.getNodesByClass("vtkMRMLScalarVolumeDisplayNode"))
-    nodes.extend(slicer.util.getNodesByClass("vtkMRMLSegmentationNode"))
-    nodes.extend(slicer.util.getNodesByClass("vtkMRMLSegmentationDisplayNode"))
-    for node in nodes:
-        slicer.mrmlScene.RemoveNode(node)

+ 0 - 111
DICOMtools/vtkInterface.py

@@ -1,111 +0,0 @@
-import vtk, qt, ctk, slicer
-import numpy as np
-import SimpleITK as sitk
-
-#set of routines to transform images from one form to another, most notably
-#numpy to vtk to itk and all possible combinations inbetween. Keep track of
-#orientation, origin and spacing between transforms
-
-class vtkInterface:
-  def __init__(self, parent):
-    #parent.title = "vtk Interface"
-    #parent.categories = ["LabKey"]
-    parent.dependencies = []
-    parent.title ="vtkInterface"
-    parent.contributors = ["Andrej Studen (FMF/JSI)"] # replace with "Firstname Lastname (Org)"
-    parent.helpText = """
-    Convert native numpy data structures to vtk
-    """
-    parent.acknowledgementText = """
-    This module was developed within the frame of the ARRS sponsored medical
-    physics research programe to investigate quantitative measurements of cardiac
-    function using sestamibi-like tracers
-    """ # replace with organization, grant and thanks.
-    self.parent = parent
-
-
-def numpyToVTK(numpy_array, shape, data_type=vtk.VTK_FLOAT):
-    v=vtk.vtkImageData()
-    v.GetPointData().SetScalars(
-        vtk.util.numpy_support.numpy_to_vtk(
-            np.ravel(numpy_array,order='F'),deep=True, array_type=data_type))
-    v.SetOrigin(0,0,0)
-    v.SetSpacing(1,1,1)
-    v.SetDimensions(shape)
-    return v
-
-
-def completeOrientation(orientation):
-    o=orientation
-    o.append(o[1]*o[5]-o[2]*o[4])#0,3
-    o.append(o[2]*o[3]-o[0]*o[5])#1,4
-    o.append(o[0]*o[4]-o[1]*o[3])#2,5
-    return o
-
-
-def ITK2VTK(img):
-    #convert itk to vtk format.
-    #get the array
-    data=sitk.GetArrayFromImage(img)
-    #reverse the shape (don't ask, look at vtk manual if really curios)
-    shape=list(reversed(data.shape))
-    return numpyToVTK(data.ravel(),shape)
-
-def VTK2ITK(v):
-    #convert vtk image to sitk image
-    #convert to numpy first and then go to sitk
-    scalars=v.GetPointData().GetScalars()
-    shape=v.GetDimensions()
-    data=vtk.util.numpy_support.vtk_to_numpy(scalars)
-    #now convert to sitk (notice the little reversal of the shape)
-    return sitk.GetImageFromArray(np.reshape(data,list(reversed(shape))))
-
-def ITKfromNode(nodeName):
-    #use node as data source and generate an itk image
-    node=slicer.mrmlScene.GetFirstNodeByName(nodeName)
-    if node==None:
-        print("Node {0} not available".format(nodeName))
-        return
-
-    img=VTK2ITK(node.GetImageData())
-
-    img.SetOrigin(node.GetOrigin())
-    img.SetSpacing(node.GetSpacing())
-    m=vtk.vtkMatrix4x4()
-    node.GetIJKToRASDirectionMatrix(m)
-    orientation=[0]*9
-    for i in range(0,3):
-        for j in range (0,3):
-            orientation[3*j+i]=m.GetElement(i,j)
-    img.SetDirection(orientation)
-    return img
-
-
-
-def ITKtoNode(img,nodeName):
-    #display itk image and assign it a volume node
-    #useful for displaying outcomes of itk calculations
-    node=slicer.mrmlScene.GetFirstNodeByName(nodeName)
-    if node==None:
-        node=slicer.vtkMRMLScalarVolumeNode()
-        node.SetName(nodeName)
-        slicer.mrmlScene.AddNode(node)
-
-    node.SetAndObserveImageData(ITK2VTK(img))
-
-    #hairy - keep orientation, spacing and origin from node and pass it to itk
-    #for future reference
-    spacing=img.GetSpacing()
-    orientation=img.GetDirection()
-    origin=img.GetOrigin()
-
-    #we should get orientation, spacing and origin from somewhere
-    ijkToRAS = vtk.vtkMatrix4x4()
-    
-    for i in range(0,3):
-       for j in range(0,3):
-           ijkToRAS.SetElement(i,j,spacing[i]*orientation[3*j+i])
-
-       ijkToRAS.SetElement(i,3,origin[i])
-
-    node.SetIJKToRASMatrix(ijkToRAS)