cardiacSPECT.py 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. import os
  2. import sys
  3. import unittest
  4. import vtk, qt, ctk, slicer
  5. from slicer.ScriptedLoadableModule import *
  6. import logging
  7. import vtkInterface as vi
  8. #
  9. # cardiacSPECT
  10. #
  11. class cardiacSPECT(ScriptedLoadableModule):
  12. """Uses ScriptedLoadableModule base class, available at:
  13. https://github.com/Slicer/Slicer/blob/master/Base/Python/slicer/ScriptedLoadableModule.py
  14. """
  15. def __init__(self, parent):
  16. ScriptedLoadableModule.__init__(self, parent)
  17. parent.title = "Cardiac SPECT"
  18. parent.categories = ["Examples"]
  19. parent.dependencies = []
  20. parent.contributors = ["Andrej Studen (FMF/JSI)"] # replace with "Firstname Lastname (Org)"
  21. parent.helpText = """
  22. Load dynamic cardiac SPECT data to Slicer
  23. """
  24. parent.acknowledgementText = """
  25. This module was developed within the frame of the ARRS sponsored medical
  26. physics research programe to investigate quantitative measurements of cardiac
  27. function using sestamibi-like tracers
  28. """ # replace with organization, grant and thanks.
  29. self.parent.helpText += self.getDefaultModuleDocumentationLink()
  30. self.parent = parent
  31. #
  32. # cardiacSPECTWidget
  33. #
  34. class cardiacSPECTWidget(ScriptedLoadableModuleWidget):
  35. """Uses ScriptedLoadableModuleWidget base class, available at:
  36. https://github.com/Slicer/Slicer/blob/master/Base/Python/slicer/ScriptedLoadableModule.py
  37. """
  38. def setup(self):
  39. ScriptedLoadableModuleWidget.setup(self)
  40. # Instantiate and connect widgets ...
  41. dataButton = ctk.ctkCollapsibleButton()
  42. dataButton.text = "Data"
  43. self.layout.addWidget(dataButton)
  44. # Layout within the sample collapsible button
  45. dataFormLayout = qt.QFormLayout(dataButton)
  46. dataLoadButton = qt.QPushButton("Load")
  47. dataLoadButton.toolTip="Load data from DICOM"
  48. dataFormLayout.addWidget(dataLoadButton)
  49. dataLoadButton.connect('clicked(bool)',self.onDataLoadButtonClicked)
  50. # Set local var as instance attribute
  51. self.dataLoadButton = dataLoadButton
  52. # Add vertical spacer
  53. self.layout.addStretch(1)
  54. addFrameButton=qt.QPushButton("Add Frame")
  55. addFrameButton.toolTip="Add frame to VTK"
  56. dataFormLayout.addWidget(addFrameButton)
  57. addFrameButton.connect('clicked(bool)',self.onAddFrameButtonClicked)
  58. addCTButton=qt.QPushButton("Add CT")
  59. addCTButton.toolTip="Add CT to VTK"
  60. dataFormLayout.addWidget(addCTButton)
  61. addCTButton.connect('clicked(bool)',self.onAddCTButtonClicked)
  62. #
  63. # Parameters Area
  64. #
  65. parametersCollapsibleButton = ctk.ctkCollapsibleButton()
  66. parametersCollapsibleButton.text = "Parameters"
  67. self.layout.addWidget(parametersCollapsibleButton)
  68. # Layout within the dummy collapsible button
  69. parametersFormLayout = qt.QFormLayout(parametersCollapsibleButton)
  70. #
  71. # check box to trigger taking screen shots for later use in tutorials
  72. #
  73. self.time_frame_select=qt.QLineEdit()
  74. self.time_frame_select.setText("2")
  75. self.time_frame_select.toolTip = "Select the time frame"
  76. parametersFormLayout.addRow(self.time_frame_select)
  77. #
  78. # Apply Button
  79. #
  80. self.applyButton = qt.QPushButton("Apply")
  81. self.applyButton.toolTip = "Run the algorithm."
  82. self.applyButton.enabled = False
  83. parametersFormLayout.addRow(self.applyButton)
  84. # connections
  85. self.applyButton.connect('clicked(bool)', self.onApplyButton)
  86. #self.inputSelector.connect("currentNodeChanged(vtkMRMLNode*)", self.onSelect)
  87. #self.outputSelector.connect("currentNodeChanged(vtkMRMLNode*)", self.onSelect)
  88. # Add vertical spacer
  89. self.layout.addStretch(1)
  90. self.logic=cardiacSPECTLogic()
  91. def cleanup(self):
  92. pass
  93. def onApplyButton(self):
  94. pass
  95. #logic = cardiacSPECTLogic()
  96. #imageThreshold = self.imageThresholdSliderWidget.value
  97. def onDataLoadButtonClicked(self):
  98. self.logic.loadData()
  99. def onAddFrameButtonClicked(self):
  100. it=int(self.time_frame_select.text)
  101. self.logic.addFrame(it)
  102. def onAddCTButtonClicked(self):
  103. self.logic.addCT()
  104. #
  105. #
  106. # cardiacSPECTLogic
  107. #
  108. class cardiacSPECTLogic(ScriptedLoadableModuleLogic):
  109. """This class should implement all the actual
  110. computation done by your module. The interface
  111. should be such that other python code can import
  112. this class and make use of the functionality without
  113. requiring an instance of the Widget.
  114. Uses ScriptedLoadableModuleLogic base class, available at:
  115. https://github.com/Slicer/Slicer/blob/master/Base/Python/slicer/ScriptedLoadableModule.py
  116. """
  117. def loadData(self):
  118. startDir=os.environ['HOME']
  119. inputDir=qt.QFileDialog.getExistingDirectory(None,
  120. 'Select DICOM directory',startDir)
  121. #use another script from the same file
  122. mypath=os.environ['HOME']+'/software/build/dynamicSPECT'
  123. sys.path.append(mypath)
  124. import parseDicom as pd
  125. self.frame_data,self.frame_time=pd.read_dynamic_SPECT(inputDir)
  126. self.ct_data,self.ct_center,self.ct_pixel_size=pd.read_CT(inputDir)
  127. #additional message via qt
  128. qt.QMessageBox.information(
  129. slicer.util.mainWindow(),
  130. 'Slicer Python','Data loaded')
  131. def addNode(self,nodeName,v):
  132. #nodeName='testVolume'+str(it)
  133. newNode=slicer.vtkMRMLScalarVolumeNode()
  134. newNode.SetName(nodeName)
  135. ijkToRAS = vtk.vtkMatrix4x4()
  136. ijkToRAS.Identity()
  137. newNode.SetIJKToRASMatrix(ijkToRAS)
  138. newNode.SetAndObserveImageData(v)
  139. slicer.mrmlScene.AddNode(newNode)
  140. selectionNode = slicer.app.applicationLogic().GetSelectionNode()
  141. selectionNode.SetReferenceActiveVolumeID(newNode.GetID())
  142. slicer.app.applicationLogic().PropagateVolumeSelection(0)
  143. def addFrame(self,it):
  144. #convert data from numpy.array to vtkImageData
  145. #use time point it
  146. frame_data=self.frame_data[:,:,:,it];
  147. nodeName='testVolume'+str(it)
  148. self.addNode(nodeName,
  149. vi.numpyToVTK3D(frame_data,[0,0,0],[1,1,1]))
  150. def addCT(self):
  151. nodeName='testCT'
  152. self.addNode(nodeName,
  153. vi.numpyToVTK3D(self.ct_data,
  154. self.ct_center,self.ct_pixel_size))
  155. class cardiacSPECTTest(ScriptedLoadableModuleTest):
  156. """
  157. This is the test case for your scripted module.
  158. Uses ScriptedLoadableModuleTest base class, available at:
  159. https://github.com/Slicer/Slicer/blob/master/Base/Python/slicer/ScriptedLoadableModule.py
  160. """
  161. def setUp(self):
  162. """ Do whatever is needed to reset the state - typically a scene clear will be enough.
  163. """
  164. slicer.mrmlScene.Clear(0)
  165. def runTest(self):
  166. """Run as few or as many tests as needed here.
  167. """
  168. self.setUp()
  169. self.test_cardiacSPECT1()
  170. def test_cardiacSPECT1(self):
  171. """ Ideally you should have several levels of tests. At the lowest level
  172. tests should exercise the functionality of the logic with different inputs
  173. (both valid and invalid). At higher levels your tests should emulate the
  174. way the user would interact with your code and confirm that it still works
  175. the way you intended.
  176. One of the most important features of the tests is that it should alert other
  177. developers when their changes will have an impact on the behavior of your
  178. module. For example, if a developer removes a feature that you depend on,
  179. your test should break so they know that the feature is needed.
  180. """
  181. self.delayDisplay("Starting the test")
  182. #
  183. # first, get some data
  184. #
  185. self.delayDisplay('Test passed!')