import os import sys import unittest import vtk, qt, ctk, slicer from slicer.ScriptedLoadableModule import * import logging import vtkInterface as vi # # cardiacSPECT # class cardiacSPECT(ScriptedLoadableModule): """Uses ScriptedLoadableModule base class, available at: https://github.com/Slicer/Slicer/blob/master/Base/Python/slicer/ScriptedLoadableModule.py """ def __init__(self, parent): ScriptedLoadableModule.__init__(self, parent) parent.title = "Cardiac SPECT" parent.categories = ["Examples"] parent.dependencies = [] parent.contributors = ["Andrej Studen (FMF/JSI)"] # replace with "Firstname Lastname (Org)" parent.helpText = """ Load dynamic cardiac SPECT data to Slicer """ 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.helpText += self.getDefaultModuleDocumentationLink() self.parent = parent # # cardiacSPECTWidget # class cardiacSPECTWidget(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) # Instantiate and connect widgets ... dataButton = ctk.ctkCollapsibleButton() dataButton.text = "Data" self.layout.addWidget(dataButton) # Layout within the sample collapsible button dataFormLayout = qt.QFormLayout(dataButton) dataLoadButton = qt.QPushButton("Load") dataLoadButton.toolTip="Load data from DICOM" dataFormLayout.addWidget(dataLoadButton) dataLoadButton.connect('clicked(bool)',self.onDataLoadButtonClicked) # Set local var as instance attribute self.dataLoadButton = dataLoadButton # Add vertical spacer self.layout.addStretch(1) addFrameButton=qt.QPushButton("Add Frame") addFrameButton.toolTip="Add frame to VTK" dataFormLayout.addWidget(addFrameButton) addFrameButton.connect('clicked(bool)',self.onAddFrameButtonClicked) addCTButton=qt.QPushButton("Add CT") addCTButton.toolTip="Add CT to VTK" dataFormLayout.addWidget(addCTButton) addCTButton.connect('clicked(bool)',self.onAddCTButtonClicked) # # Parameters Area # parametersCollapsibleButton = ctk.ctkCollapsibleButton() parametersCollapsibleButton.text = "Parameters" self.layout.addWidget(parametersCollapsibleButton) # Layout within the dummy collapsible button parametersFormLayout = qt.QFormLayout(parametersCollapsibleButton) # # check box to trigger taking screen shots for later use in tutorials # self.time_frame_select=qt.QLineEdit() self.time_frame_select.setText("2") self.time_frame_select.toolTip = "Select the time frame" parametersFormLayout.addRow(self.time_frame_select) # # Apply Button # self.applyButton = qt.QPushButton("Apply") self.applyButton.toolTip = "Run the algorithm." self.applyButton.enabled = False parametersFormLayout.addRow(self.applyButton) # connections self.applyButton.connect('clicked(bool)', self.onApplyButton) #self.inputSelector.connect("currentNodeChanged(vtkMRMLNode*)", self.onSelect) #self.outputSelector.connect("currentNodeChanged(vtkMRMLNode*)", self.onSelect) # Add vertical spacer self.layout.addStretch(1) self.logic=cardiacSPECTLogic() def cleanup(self): pass def onApplyButton(self): pass #logic = cardiacSPECTLogic() #imageThreshold = self.imageThresholdSliderWidget.value def onDataLoadButtonClicked(self): self.logic.loadData() def onAddFrameButtonClicked(self): it=int(self.time_frame_select.text) self.logic.addFrame(it) def onAddCTButtonClicked(self): self.logic.addCT() # # # cardiacSPECTLogic # class cardiacSPECTLogic(ScriptedLoadableModuleLogic): """This class should implement all the actual computation done by your module. The interface should be such that other python code can import this class and make use of the functionality without requiring an instance of the Widget. Uses ScriptedLoadableModuleLogic base class, available at: https://github.com/Slicer/Slicer/blob/master/Base/Python/slicer/ScriptedLoadableModule.py """ def loadData(self): startDir=os.environ['HOME'] inputDir=qt.QFileDialog.getExistingDirectory(None, 'Select DICOM directory',startDir) #use another script from the same file mypath=os.environ['HOME']+'/software/build/dynamicSPECT' sys.path.append(mypath) import parseDicom as pd self.frame_data, self.frame_time, self.frame_center, \ self.frame_pixel_size, self.frame_orientation=pd.read_dynamic_SPECT(inputDir) self.ct_data,self.ct_center,self.ct_pixel_size, \ self.ct_orientation=pd.read_CT(inputDir) self.ct_orientation=vi.completeOrientation(self.ct_orientation) self.frame_orientation=vi.completeOrientation(self.frame_orientation) #additional message via qt qt.QMessageBox.information( slicer.util.mainWindow(), 'Slicer Python','Data loaded') def addNode(self,nodeName,v, orientation): #nodeName='testVolume'+str(it) newNode=slicer.vtkMRMLScalarVolumeNode() newNode.SetName(nodeName) #pixel_size=[0,0,0] pixel_size=v.GetSpacing() print(pixel_size) #origin=[0,0,0] origin=v.GetOrigin() ijkToRAS = vtk.vtkMatrix4x4() #think how to do this with image orientation for i in range(0,3): for j in range(0,3): ijkToRAS.SetElement(i,j,pixel_size[i]*orientation[3*j+i]) ijkToRAS.SetElement(i,3,origin[i]) newNode.SetIJKToRASMatrix(ijkToRAS) newNode.SetAndObserveImageData(v) slicer.mrmlScene.AddNode(newNode) selectionNode = slicer.app.applicationLogic().GetSelectionNode() selectionNode.SetReferenceActiveVolumeID(newNode.GetID()) slicer.app.applicationLogic().PropagateVolumeSelection(0) def addFrame(self,it): #convert data from numpy.array to vtkImageData #use time point it frame_data=self.frame_data[:,:,:,it]; nodeName='testVolume'+str(it) self.addNode(nodeName, vi.numpyToVTK3D(frame_data,self.frame_center, self.frame_pixel_size),self.frame_orientation) def addCT(self): nodeName='testCT' self.addNode(nodeName, vi.numpyToVTK3D(self.ct_data, self.ct_center,self.ct_pixel_size), self.ct_orientation) class cardiacSPECTTest(ScriptedLoadableModuleTest): """ This is the test case for your scripted module. Uses ScriptedLoadableModuleTest base class, available at: https://github.com/Slicer/Slicer/blob/master/Base/Python/slicer/ScriptedLoadableModule.py """ def setUp(self): """ Do whatever is needed to reset the state - typically a scene clear will be enough. """ slicer.mrmlScene.Clear(0) def runTest(self): """Run as few or as many tests as needed here. """ self.setUp() self.test_cardiacSPECT1() def test_cardiacSPECT1(self): """ Ideally you should have several levels of tests. At the lowest level tests should exercise the functionality of the logic with different inputs (both valid and invalid). At higher levels your tests should emulate the way the user would interact with your code and confirm that it still works the way you intended. One of the most important features of the tests is that it should alert other developers when their changes will have an impact on the behavior of your module. For example, if a developer removes a feature that you depend on, your test should break so they know that the feature is needed. """ self.delayDisplay("Starting the test") # # first, get some data # self.delayDisplay('Test passed!')