123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227 |
- 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=pd.read_dynamic_SPECT(inputDir)
- self.ct_data,self.ct_center,self.ct_pixel_size=pd.read_CT(inputDir)
- #additional message via qt
- qt.QMessageBox.information(
- slicer.util.mainWindow(),
- 'Slicer Python','Data loaded')
- def addNode(self,nodeName,v):
- #nodeName='testVolume'+str(it)
- newNode=slicer.vtkMRMLScalarVolumeNode()
- newNode.SetName(nodeName)
- ijkToRAS = vtk.vtkMatrix4x4()
- ijkToRAS.Identity()
- 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,[0,0,0],[1,1,1]))
- def addCT(self):
- nodeName='testCT'
- self.addNode(nodeName,
- vi.numpyToVTK3D(self.ct_data,
- self.ct_center,self.ct_pixel_size))
- 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!')
|