def setDefaultParams(self): """Configure here all the required params for any LabelEffect (Paint, Draw, ect.)""" # self.editUtil = EditUtil() self.parameterNode = EditUtil.getParameterNode() self.parameterNode.SetParameter("LabelEffect,paintOver", "1") # Enable paintOver self.parameterNode.SetParameter("LabelEffect,paintThreshold", "1") # Enable Threshold checkbox self.parameterNode.SetParameter("PaintEffect,radius", "5")
def create(self): self.findEffects() self.mainFrame = qt.QFrame(self.parent) self.mainFrame.objectName = 'MainFrame' vbox = qt.QVBoxLayout() self.mainFrame.setLayout(vbox) self.parent.layout().addWidget(self.mainFrame) # # the buttons # self.rowFrames = [] self.actions = {} self.buttons = {} self.icons = {} self.callbacks = {} # create all of the buttons (restricted version from the original) self.createButtonRow(self.activeTools) # # createButtonRow() ensures that only effects in self.effects are exposed, # self.createButtonRow( ("DefaultTool", "EraseLabel", "PaintEffect", "DrawEffect", "WandEffect", "LevelTracingEffect", "RectangleEffect", "IdentifyIslandsEffect", "ChangeIslandEffect", "RemoveIslandsEffect", "SaveIslandEffect") ) # self.createButtonRow( ("ErodeEffect", "DilateEffect", "GrowCutEffect", "WatershedFromMarkerEffect", "ThresholdEffect", "ChangeLabelEffect", "MakeModelEffect", "FastMarchingEffect") ) extensions = [] for k in slicer.modules.editorExtensions: extensions.append(k) self.createButtonRow(extensions) # self.createButtonRow( ("PreviousCheckPoint", "NextCheckPoint"), rowLabel="Undo/Redo: " ) # # the labels # self.toolsActiveToolFrame = qt.QFrame(self.parent) self.toolsActiveToolFrame.setLayout(qt.QHBoxLayout()) self.parent.layout().addWidget(self.toolsActiveToolFrame) self.toolsActiveTool = qt.QLabel(self.toolsActiveToolFrame) self.toolsActiveTool.setText('Active Tool:') self.toolsActiveTool.setStyleSheet( "background-color: rgb(232,230,235)") self.toolsActiveToolFrame.layout().addWidget(self.toolsActiveTool) self.toolsActiveToolName = qt.QLabel(self.toolsActiveToolFrame) self.toolsActiveToolName.setText('') self.toolsActiveToolName.setStyleSheet( "background-color: rgb(232,230,235)") self.toolsActiveToolFrame.layout().addWidget(self.toolsActiveToolName) vbox.addStretch(1) self.setDefaultParams() self.updateUndoRedoButtons() self._onParameterNodeModified(EditUtil.getParameterNode())
def enter(self): """ When entering the module, check that the lightbox modes are off and that we have the volumes loaded """ self.turnOffLightboxes() self.installShortcutKeys() # get the master and merge nodes from the composite node associated # with the red slice, but only if showing volumes and we don't already # have an active set of volumes that we are using if self.showVolumesFrame: if not self.helper.master or not self.helper.merge: # get the slice composite node for the Red slice view (we'll assume it exists # since we are in the editor) to get the current background and label # - set the foreground layer as the active ID # in the selection node for later calls to PropagateVolumeSelection compositeNode = EditUtil.getCompositeNode() selectionNode = slicer.app.applicationLogic().GetSelectionNode( ) selectionNode.SetSecondaryVolumeID( compositeNode.GetForegroundVolumeID()) bgID = lbID = "" if compositeNode.GetBackgroundVolumeID(): bgID = compositeNode.GetBackgroundVolumeID() if compositeNode.GetLabelVolumeID(): lbID = compositeNode.GetLabelVolumeID() masterNode = slicer.mrmlScene.GetNodeByID(bgID) mergeNode = slicer.mrmlScene.GetNodeByID(lbID) self.setMasterNode(masterNode) self.setMergeNode(mergeNode) # if not showing volumes, the caller is responsible for setting the master and # merge nodes, most likely according to a widget within the caller # Observe the parameter node in order to make changes to # button states as needed self.parameterNode = EditUtil.getParameterNode() self.addObserver(self.parameterNode, vtk.vtkCommand.ModifiedEvent, self.updateGUIFromMRML) self.addObserver(slicer.mrmlScene, slicer.mrmlScene.StartCloseEvent, self.resetInterface) if self.helper: self.helper.onEnter() if self.toolsColor: self.toolsColor.updateGUIFromMRML(self.parameterNode, vtk.vtkCommand.ModifiedEvent)
def enter(self): """ When entering the module, check that the lightbox modes are off and that we have the volumes loaded """ self.turnOffLightboxes() self.installShortcutKeys() # get the master and merge nodes from the composite node associated # with the red slice, but only if showing volumes and we don't already # have an active set of volumes that we are using if self.showVolumesFrame: if not self.helper.master or not self.helper.merge: # get the slice composite node for the Red slice view (we'll assume it exists # since we are in the editor) to get the current background and label # - set the foreground layer as the active ID # in the selection node for later calls to PropagateVolumeSelection compositeNode = EditUtil.getCompositeNode() selectionNode = slicer.app.applicationLogic().GetSelectionNode() selectionNode.SetReferenceSecondaryVolumeID( compositeNode.GetForegroundVolumeID() ) bgID = lbID = "" if compositeNode.GetBackgroundVolumeID(): bgID = compositeNode.GetBackgroundVolumeID() if compositeNode.GetLabelVolumeID(): lbID = compositeNode.GetLabelVolumeID() masterNode = slicer.mrmlScene.GetNodeByID( bgID ) mergeNode = slicer.mrmlScene.GetNodeByID( lbID ) self.setMasterNode(masterNode) self.setMergeNode(mergeNode) # if not showing volumes, the caller is responsible for setting the master and # merge nodes, most likely according to a widget within the caller # Observe the parameter node in order to make changes to # button states as needed self.parameterNode = EditUtil.getParameterNode() self.parameterNodeTag = self.parameterNode.AddObserver(vtk.vtkCommand.ModifiedEvent, self.updateGUIFromMRML) self.mrmlSceneTag = slicer.mrmlScene.AddObserver(slicer.mrmlScene.StartCloseEvent, self.resetInterface) if self.helper: self.helper.onEnter() if self.toolsColor: self.toolsColor.updateGUIFromMRML(self.parameterNode, vtk.vtkCommand.ModifiedEvent)
def run(self, enableScreenshots=0, screenshotScaleFactor=1): """ Run the actual algorithm """ self.delayDisplay( 'Running test of the Neurosurgical Planning tutorial') self.enableScreenshots = enableScreenshots self.screenshotScaleFactor = screenshotScaleFactor # conventional layout lm = slicer.app.layoutManager() lm.setLayout(2) moduleSelector = slicer.util.mainWindow().moduleSelector() # # first load the data # if self.enableScreenshots == 1: # for the tutorial, do it through the welcome module moduleSelector.selectModule('Welcome') self.delayDisplay("Screenshot") self.takeScreenshot('NeurosurgicalPlanning-Welcome', 'Welcome module', -1) else: # otherwise show the sample data module moduleSelector.selectModule('SampleData') # use the sample data module logic to load data for the self test import SampleData sampleDataLogic = SampleData.SampleDataLogic() self.delayDisplay("Getting Baseline volume") baselineVolume = sampleDataLogic.downloadWhiteMatterExplorationBaselineVolume( ) self.takeScreenshot('NeurosurgicalPlanning-Loaded', 'Data loaded', -1) # # link the viewers # if self.enableScreenshots == 1: # for the tutorial, pop up the linking control sliceController = slicer.app.layoutManager().sliceWidget( "Red").sliceController() popupWidget = sliceController.findChild("ctkPopupWidget") if popupWidget is not None: popupWidget.pinPopup(1) self.takeScreenshot('NeurosurgicalPlanning-Link', 'Link slice viewers', -1) popupWidget.pinPopup(0) sliceLogic = slicer.app.layoutManager().sliceWidget('Red').sliceLogic() compositeNode = sliceLogic.GetSliceCompositeNode() compositeNode.SetLinkedControl(1) # # baseline in the background # sliceLogic.StartSliceCompositeNodeInteraction(1) compositeNode.SetBackgroundVolumeID(baselineVolume.GetID()) sliceLogic.EndSliceCompositeNodeInteraction() self.takeScreenshot('NeurosurgicalPlanning-Baseline', 'Baseline in background', -1) # # adjust window level on baseline # moduleSelector.selectModule('Volumes') baselineDisplay = baselineVolume.GetDisplayNode() baselineDisplay.SetAutoWindowLevel(0) baselineDisplay.SetWindow(2600) baselineDisplay.SetLevel(1206) self.takeScreenshot('NeurosurgicalPlanning-WindowLevel', 'Set W/L on baseline', -1) # # switch to red slice only # lm.setLayout(6) self.takeScreenshot('NeurosurgicalPlanning-RedSliceOnly', 'Set layout to Red Slice only', -1) # # segmentation of tumour # # # create a label map and set it for editing # volumesLogic = slicer.modules.volumes.logic() baselineVolumeLabel = volumesLogic.CreateAndAddLabelVolume( slicer.mrmlScene, baselineVolume, baselineVolume.GetName() + '-label') baselineDisplayNode = baselineVolumeLabel.GetDisplayNode() baselineDisplayNode.SetAndObserveColorNodeID( 'vtkMRMLColorTableNodeFileGenericAnatomyColors.txt') selectionNode = slicer.app.applicationLogic().GetSelectionNode() selectionNode.SetReferenceActiveVolumeID(baselineVolume.GetID()) selectionNode.SetReferenceActiveLabelVolumeID( baselineVolumeLabel.GetID()) slicer.app.applicationLogic().PropagateVolumeSelection(0) # # editor module # moduleSelector.selectModule('Editor') self.takeScreenshot('NeurosurgicalPlanning-Editor', 'Showing Editor Module', -1) # set the slice offset so drawing is right sliceNode = sliceLogic.GetSliceNode() sliceOffset = 58.7 sliceNode.SetSliceOffset(sliceOffset) # # paint # parameterNode = EditUtil.getParameterNode() paintEffect = EditorLib.PaintEffectOptions() paintEffect.setMRMLDefaults() paintEffect.__del__() sliceWidget = lm.sliceWidget('Red') paintTool = EditorLib.PaintEffectTool(sliceWidget) self.takeScreenshot('NeurosurgicalPlanning-Paint', 'Paint tool in Editor Module', -1) # # paint in cystic part of tumor, using converstion from RAS coords to # avoid slice widget size differences # EditUtil.setLabel(293) displayCoords = self.rasToDisplay(-7.4, 71, sliceOffset) paintTool.paintAddPoint(displayCoords[0], displayCoords[1]) displayCoords = self.rasToDisplay(-11, 73, sliceOffset) paintTool.paintAddPoint(displayCoords[0], displayCoords[1]) displayCoords = self.rasToDisplay(-12, 85, sliceOffset) paintTool.paintAddPoint(displayCoords[0], displayCoords[1]) displayCoords = self.rasToDisplay(-13, 91, sliceOffset) paintTool.paintAddPoint(displayCoords[0], displayCoords[1]) displayCoords = self.rasToDisplay(-15, 78, sliceOffset) paintTool.paintAddPoint(displayCoords[0], displayCoords[1]) paintTool.paintApply() self.takeScreenshot('NeurosurgicalPlanning-PaintCystic', 'Paint cystic part of tumor', -1) # # paint in solid part of tumor # EditUtil.setLabel(7) displayCoords = self.rasToDisplay(-0.5, 118.5, sliceOffset) paintTool.paintAddPoint(displayCoords[0], displayCoords[1]) displayCoords = self.rasToDisplay(-7.4, 116, sliceOffset) paintTool.paintAddPoint(displayCoords[0], displayCoords[1]) paintTool.paintApply() self.takeScreenshot('NeurosurgicalPlanning-PaintSolid', 'Paint solid part of tumor', -1) # # paint around the tumor # EditUtil.setLabel(295) rMax = 25 rMin = -50 aMax = 145 aMin = 50 rasStep = 5 # draw the top and bottom for r in range(rMin, rMax, rasStep): displayCoords = self.rasToDisplay(r, aMin, sliceOffset) paintTool.paintAddPoint(displayCoords[0], displayCoords[1]) displayCoords = self.rasToDisplay(r, aMax, sliceOffset) paintTool.paintAddPoint(displayCoords[0], displayCoords[1]) # draw the left and right for a in range(aMin, aMax, rasStep): displayCoords = self.rasToDisplay(rMin, a, sliceOffset) paintTool.paintAddPoint(displayCoords[0], displayCoords[1]) displayCoords = self.rasToDisplay(rMax, a, sliceOffset) paintTool.paintAddPoint(displayCoords[0], displayCoords[1]) paintTool.paintApply() self.takeScreenshot('NeurosurgicalPlanning-PaintAround', 'Paint around tumor', -1) # # clean up after painting # paintTool.cleanup() paintTool = None # # Grow cut # growCutLogic = EditorLib.GrowCutEffectLogic(sliceWidget.sliceLogic()) growCutLogic.growCut() self.takeScreenshot('NeurosurgicalPlanning-Growcut', 'Growcut', -1) # # Merge split volume # slicer.util.selectModule('Editor') slicer.util.findChildren(text='Split Merge Volume')[0].clicked() self.takeScreenshot('NeurosurgicalPlanning-SplitMerge', 'SplitMerge', -1) # # go to the data module # moduleSelector.selectModule('Data') self.takeScreenshot('NeurosurgicalPlanning-SplitMergeData', 'SplitMerge results in Data', -1) # # Ventricles Segmentation # moduleSelector.selectModule('Editor') # # select the label volume with the area around the tumor slicer.util.findChildren( name='PerStructureVolumesFrame')[0].collapsed = False treeView = slicer.util.findChildren(name='StructuresView')[0] selection = qt.QItemSelection() # selecting the last split volume in the third row row = 2 rowStart = treeView.model().index(row, 0) rowEnd = treeView.model().index(row, treeView.model().columnCount() - 1) # rowSel = qt.QItemSelection(rowStart, rowEnd) selection.select(rowStart, rowEnd) # backup: select the label map in the slice logic too baselinelabel295 = slicer.mrmlScene.GetFirstNodeByName( "BaselineVolume-region 3-label") sliceLogic.StartSliceCompositeNodeInteraction(1) compositeNode.SetLabelVolumeID(baselinelabel295.GetID()) sliceLogic.EndSliceCompositeNodeInteraction() self.takeScreenshot('NeurosurgicalPlanning-SelOutside', 'Select outside region', -1) # # Threshold tool # slicer.modules.EditorWidget.toolsBox.selectEffect('ThresholdEffect') parameterNode = EditUtil.getParameterNode() parameterNode.SetParameter('ThresholdEffect,min', str(1700)) slicer.modules.EditorWidget.toolsBox.currentTools[0].apply() self.takeScreenshot('NeurosurgicalPlanning-Ventricles', 'Ventricles segmentation', -1) # # Save Islands # slicer.modules.EditorWidget.toolsBox.selectEffect('SaveIslandEffect') saveIslandLogic = EditorLib.SaveIslandEffectLogic( sliceWidget.sliceLogic()) displayCoords = self.rasToDisplay(25.3, 5.8, sliceOffset) xy = (displayCoords[0], displayCoords[1]) saveIslandLogic.saveIsland(xy) self.takeScreenshot('NeurosurgicalPlanning-SaveIsland', 'Ventricles save island', -1) # # Merge and build # slicer.util.findChildren(text='Merge And Build')[0].clicked() # # switch to conventional layout # lm.setLayout(2) self.takeScreenshot('NeurosurgicalPlanning-MergeAndBuild', 'Merged and built models', -1) # # select label volume with label 293, in the second row # row = 1 rowStart = treeView.model().index(row, 0) rowEnd = treeView.model().index(row, treeView.model().columnCount() - 1) # rowSel = qt.QItemSelection(rowStart, rowEnd) selection.select(rowStart, rowEnd) # backup: select the label map in the slice logic too baselinelabel293 = slicer.mrmlScene.GetFirstNodeByName( "BaselineVolume-region 1-label") sliceLogic.StartSliceCompositeNodeInteraction(1) compositeNode.SetLabelVolumeID(baselinelabel293.GetID()) sliceLogic.EndSliceCompositeNodeInteraction() self.takeScreenshot('NeurosurgicalPlanning-SelCystic', 'Select cystic region', -1) # # Dilate # slicer.modules.EditorWidget.toolsBox.selectEffect('DilateEffect') EditUtil.setLabel(293) self.takeScreenshot('NeurosurgicalPlanning-Dilate', 'Dilate tool', -1) # tutorial says to click apply three times for d in range(1, 3): print d # slicer.util.findChildren(name='DilateEffectOptionsApply')[0].clicked() # slicer.modules.EditorWidget.toolsBox.currentTools[0].apply() slicer.modules.EditorWidget.toolsBox.currentOption.onApply() self.takeScreenshot('NeurosurgicalPlanning-Dilated', 'Dilated tumor', -1) return True
def run(self,enableScreenshots=0,screenshotScaleFactor=1): """ Run the actual algorithm """ self.delayDisplay('Running test of the Neurosurgical Planning tutorial') self.enableScreenshots = enableScreenshots self.screenshotScaleFactor = screenshotScaleFactor # conventional layout lm = slicer.app.layoutManager() lm.setLayout(2) moduleSelector = slicer.util.mainWindow().moduleSelector() # # first load the data # if self.enableScreenshots == 1: # for the tutorial, do it through the welcome module moduleSelector.selectModule('Welcome') self.delayDisplay("Screenshot") self.takeScreenshot('NeurosurgicalPlanning-Welcome','Welcome module',-1) else: # otherwise show the sample data module moduleSelector.selectModule('SampleData') # use the sample data module logic to load data for the self test import SampleData sampleDataLogic = SampleData.SampleDataLogic() self.delayDisplay("Getting Baseline volume") baselineVolume = sampleDataLogic.downloadWhiteMatterExplorationBaselineVolume() self.delayDisplay("Getting DTI volume") dtiVolume = sampleDataLogic.downloadWhiteMatterExplorationDTIVolume() self.takeScreenshot('NeurosurgicalPlanning-Loaded','Data loaded',-1) # # link the viewers # if self.enableScreenshots == 1: # for the tutorial, pop up the linking control sliceController = slicer.app.layoutManager().sliceWidget("Red").sliceController() popupWidget = sliceController.findChild("ctkPopupWidget") if popupWidget != None: popupWidget.pinPopup(1) self.takeScreenshot('NeurosurgicalPlanning-Link','Link slice viewers',-1) popupWidget.pinPopup(0) sliceLogic = slicer.app.layoutManager().sliceWidget('Red').sliceLogic() compositeNode = sliceLogic.GetSliceCompositeNode() compositeNode.SetLinkedControl(1) # # baseline in the background # sliceLogic.StartSliceCompositeNodeInteraction(1) compositeNode.SetBackgroundVolumeID(baselineVolume.GetID()) sliceLogic.EndSliceCompositeNodeInteraction() self.takeScreenshot('NeurosurgicalPlanning-Baseline','Baseline in background',-1) # # adjust window level on baseline # moduleSelector.selectModule('Volumes') baselineDisplay = baselineVolume.GetDisplayNode() baselineDisplay.SetAutoWindowLevel(0) baselineDisplay.SetWindow(2600) baselineDisplay.SetLevel(1206) self.takeScreenshot('NeurosurgicalPlanning-WindowLevel','Set W/L on baseline',-1) # # switch to red slice only # lm.setLayout(6) self.takeScreenshot('NeurosurgicalPlanning-RedSliceOnly','Set layout to Red Slice only',-1) # # segmentation of tumour # # # create a label map and set it for editing # volumesLogic = slicer.modules.volumes.logic() baselineVolumeLabel = volumesLogic.CreateAndAddLabelVolume( slicer.mrmlScene, baselineVolume, baselineVolume.GetName() + '-label' ) baselineDisplayNode = baselineVolumeLabel.GetDisplayNode() baselineDisplayNode.SetAndObserveColorNodeID('vtkMRMLColorTableNodeFileGenericAnatomyColors.txt') selectionNode = slicer.app.applicationLogic().GetSelectionNode() selectionNode.SetReferenceActiveVolumeID(baselineVolume.GetID()) selectionNode.SetReferenceActiveLabelVolumeID(baselineVolumeLabel.GetID()) slicer.app.applicationLogic().PropagateVolumeSelection(0) # # editor module # moduleSelector.selectModule('Editor') self.takeScreenshot('NeurosurgicalPlanning-Editor','Showing Editor Module',-1) # set the slice offset so drawing is right sliceNode = sliceLogic.GetSliceNode() sliceOffset = 58.7 sliceNode.SetSliceOffset(sliceOffset) # # paint # parameterNode = EditUtil.getParameterNode() paintEffect = EditorLib.PaintEffectOptions() paintEffect.setMRMLDefaults() paintEffect.__del__() sliceWidget = lm.sliceWidget('Red') paintTool = EditorLib.PaintEffectTool(sliceWidget) self.takeScreenshot('NeurosurgicalPlanning-Paint','Paint tool in Editor Module',-1) # # paint in cystic part of tumor, using converstion from RAS coords to # avoid slice widget size differences # EditUtil.setLabel(293) displayCoords = self.rasToDisplay(-7.4, 71, sliceOffset) paintTool.paintAddPoint(displayCoords[0], displayCoords[1]) displayCoords = self.rasToDisplay(-11, 73, sliceOffset) paintTool.paintAddPoint(displayCoords[0], displayCoords[1]) displayCoords = self.rasToDisplay(-12, 85, sliceOffset) paintTool.paintAddPoint(displayCoords[0], displayCoords[1]) displayCoords = self.rasToDisplay(-13, 91, sliceOffset) paintTool.paintAddPoint(displayCoords[0], displayCoords[1]) displayCoords = self.rasToDisplay(-15, 78, sliceOffset) paintTool.paintAddPoint(displayCoords[0], displayCoords[1]) paintTool.paintApply() self.takeScreenshot('NeurosurgicalPlanning-PaintCystic','Paint cystic part of tumor',-1) # # paint in solid part of tumor # EditUtil.setLabel(7) displayCoords = self.rasToDisplay(-0.5 , 118.5, sliceOffset) paintTool.paintAddPoint(displayCoords[0], displayCoords[1]) displayCoords = self.rasToDisplay(-7.4 , 116, sliceOffset) paintTool.paintAddPoint(displayCoords[0], displayCoords[1]) paintTool.paintApply() self.takeScreenshot('NeurosurgicalPlanning-PaintSolid','Paint solid part of tumor',-1) # # paint around the tumor # EditUtil.setLabel(295) rMax = 25 rMin = -50 aMax = 145 aMin = 50 rasStep = 5 # draw the top and bottom for r in range(rMin, rMax, rasStep): displayCoords = self.rasToDisplay(r, aMin, sliceOffset) paintTool.paintAddPoint(displayCoords[0], displayCoords[1]) displayCoords = self.rasToDisplay(r, aMax, sliceOffset) paintTool.paintAddPoint(displayCoords[0], displayCoords[1]) # draw the left and right for a in range(aMin, aMax, rasStep): displayCoords = self.rasToDisplay(rMin, a, sliceOffset) paintTool.paintAddPoint(displayCoords[0], displayCoords[1]) displayCoords = self.rasToDisplay(rMax, a, sliceOffset) paintTool.paintAddPoint(displayCoords[0], displayCoords[1]) paintTool.paintApply() self.takeScreenshot('NeurosurgicalPlanning-PaintAround','Paint around tumor',-1) # # clean up after painting # paintTool.cleanup() paintTool = None # # Grow cut # growCutLogic = EditorLib.GrowCutEffectLogic(sliceWidget.sliceLogic()) growCutLogic.growCut() self.takeScreenshot('NeurosurgicalPlanning-Growcut','Growcut',-1) # # Merge split volume # slicer.util.selectModule('Editor') slicer.util.findChildren(text='Split Merge Volume')[0].clicked() self.takeScreenshot('NeurosurgicalPlanning-SplitMerge','SplitMerge',-1) # # go to the data module # moduleSelector.selectModule('Data') self.takeScreenshot('NeurosurgicalPlanning-SplitMergeData','SplitMerge results in Data',-1) # # Ventricles Segmentation # moduleSelector.selectModule('Editor') # # select the label volume with the area around the tumor slicer.util.findChildren(name='PerStructureVolumesFrame')[0].collapsed = False treeView = slicer.util.findChildren(name='StructuresView')[0] selection = qt.QItemSelection() # selecting the last split volume in the third row row = 2 rowStart = treeView.model().index(row,0) rowEnd = treeView.model().index(row,treeView.model().columnCount() - 1) # rowSel = qt.QItemSelection(rowStart, rowEnd) selection.select(rowStart, rowEnd) # backup: select the label map in the slice logic too baselinelabel295 = slicer.mrmlScene.GetFirstNodeByName("BaselineVolume-region 3-label") sliceLogic.StartSliceCompositeNodeInteraction(1) compositeNode.SetLabelVolumeID(baselinelabel295.GetID()) sliceLogic.EndSliceCompositeNodeInteraction() self.takeScreenshot('NeurosurgicalPlanning-SelOutside','Select outside region',-1) # # Threshold tool # slicer.modules.EditorWidget.toolsBox.selectEffect('ThresholdEffect') parameterNode = EditUtil.getParameterNode() parameterNode.SetParameter('ThresholdEffect,min', str(1700)) slicer.modules.EditorWidget.toolsBox.currentTools[0].apply() self.takeScreenshot('NeurosurgicalPlanning-Ventricles','Ventricles segmentation',-1) # # Save Islands # slicer.modules.EditorWidget.toolsBox.selectEffect('SaveIslandEffect') saveIslandLogic = EditorLib.SaveIslandEffectLogic(sliceWidget.sliceLogic()) displayCoords = self.rasToDisplay(25.3, 5.8, sliceOffset) xy = (displayCoords[0], displayCoords[1]) saveIslandLogic.saveIsland(xy) self.takeScreenshot('NeurosurgicalPlanning-SaveIsland','Ventricles save island',-1) # # Merge and build # slicer.util.findChildren(text='Merge And Build')[0].clicked() # # switch to conventional layout # lm.setLayout(2) self.takeScreenshot('NeurosurgicalPlanning-MergeAndBuild','Merged and built models',-1) # # Tractography label map seeding # # # select label volume with label 293, in the second row # row = 1 rowStart = treeView.model().index(row,0) rowEnd = treeView.model().index(row,treeView.model().columnCount() - 1) # rowSel = qt.QItemSelection(rowStart, rowEnd) selection.select(rowStart, rowEnd) # backup: select the label map in the slice logic too baselinelabel293 = slicer.mrmlScene.GetFirstNodeByName("BaselineVolume-region 1-label") sliceLogic.StartSliceCompositeNodeInteraction(1) compositeNode.SetLabelVolumeID(baselinelabel293.GetID()) sliceLogic.EndSliceCompositeNodeInteraction() self.takeScreenshot('NeurosurgicalPlanning-SelCystic','Select cystic region',-1) # # Dilate # slicer.modules.EditorWidget.toolsBox.selectEffect('DilateEffect') EditUtil.setLabel(293) self.takeScreenshot('NeurosurgicalPlanning-Dilate','Dilate tool',-1) # tutorial says to click apply three times for d in range (1,3): print d # slicer.util.findChildren(name='DilateEffectOptionsApply')[0].clicked() # slicer.modules.EditorWidget.toolsBox.currentTools[0].apply() slicer.modules.EditorWidget.toolsBox.currentOption.onApply() self.takeScreenshot('NeurosurgicalPlanning-Dilated','Dilated tumor',-1) # # Tractography Label Map Seeding module # moduleSelector.selectModule('TractographyLabelMapSeeding') self.takeScreenshot('NeurosurgicalPlanning-LabelMapSeedingModule','Showing Tractography Label Seeding Module',-1) tractographyLabelSeeding = slicer.modules.tractographylabelmapseeding parameters = {} parameters['InputVolume'] = dtiVolume.GetID() baselinelabel293 = slicer.mrmlScene.GetFirstNodeByName("BaselineVolume-region 1-label") # VTK6 TODO - set 'InputROIPipelineInfo' parameters['InputROI'] = baselinelabel293.GetID() fibers = slicer.vtkMRMLFiberBundleNode() slicer.mrmlScene.AddNode(fibers) parameters['OutputFibers'] = fibers.GetID() parameters['UseIndexSpace'] = 1 parameters['StoppingValue'] = 0.15 parameters['ROIlabel'] = 293 parameters['StoppingMode'] = 'FractionalAnisotropy' # defaults # parameters['ClTh'] = 0.3 # parameters['MinimumLength'] = 20 # parameters['MaximumLength'] = 800 # parameters['StoppingCurvature'] = 0.7 # parameters['IntegrationStepLength'] = 0.5 # parameters['SeedSpacing'] = 2 # and run it slicer.cli.run(tractographyLabelSeeding, None, parameters) self.takeScreenshot('NeurosurgicalPlanning-LabelMapSeeding','Showing Tractography Label Seeding Results',-1) # # tractography fiducial seeding # moduleSelector.selectModule('TractographyInteractiveSeeding') self.takeScreenshot('NeurosurgicalPlanning-TIS','Showing Tractography Interactive Seeding Module',-1) # DTI in background sliceLogic.StartSliceCompositeNodeInteraction(1) compositeNode.SetBackgroundVolumeID(dtiVolume.GetID()) sliceLogic.EndSliceCompositeNodeInteraction() # DTI visible in 3D sliceNode = sliceLogic.GetSliceNode() sliceLogic.StartSliceNodeInteraction(128) sliceNode.SetSliceVisible(1) sliceLogic.EndSliceNodeInteraction() self.takeScreenshot('NeurosurgicalPlanning-TIS-DTI','DTI volume with Tractography Interactive Seeding Module',-1) # place a fiducial displayNode = slicer.vtkMRMLMarkupsDisplayNode() slicer.mrmlScene.AddNode(displayNode) fidNode = slicer.vtkMRMLMarkupsFiducialNode() fidNode.SetName('F') slicer.mrmlScene.AddNode(fidNode) fidNode.SetAndObserveDisplayNodeID(displayNode.GetID()) r = 28.338526 a = 34.064367 s = sliceOffset fidNode.AddFiducial(r,a,s) # make it active selectionNode = slicer.mrmlScene.GetNodeByID("vtkMRMLSelectionNodeSingleton") if (selectionNode != None): selectionNode.SetReferenceActivePlaceNodeID(fidNode.GetID()) self.takeScreenshot('NeurosurgicalPlanning-TIS-Fid1','Fiducial in Tractography Interactive Seeding Module',-1) # set up the arguments wr = slicer.modules.tractographyinteractiveseeding.widgetRepresentation() wr.setDiffusionTensorVolumeNode(dtiVolume) # create a fiber bundle fiducialFibers = slicer.vtkMRMLFiberBundleNode() slicer.mrmlScene.AddNode(fiducialFibers) wr.setFiberBundleNode(fiducialFibers) wr.setSeedingNode(fidNode) wr.setMinimumPath(10) wr.setStoppingValue(0.15) self.takeScreenshot('NeurosurgicalPlanning-TIS-Args','Tractography Interactive Seeding arguments',-1) self.delayDisplay("Moving the fiducial") for y in range(-20, 100, 5): msg = "Moving the fiducial to y = " + str(y) self.delayDisplay(msg,250) fidNode.SetNthFiducialPosition(0, r, y, s) self.takeScreenshot('NeurosurgicalPlanning-TIS-Moved','Moved fiducial and did Tractography Interactive Seeding',-1) return True
def test_SEGExporterSelfTest1(self): """ Test DICOM import, segmentation, export """ self.messageDelay = 50 import os self.delayDisplay("Starting the DICOM SEG Export test") # # first, get the data - a zip file of dicom data # filePath = self.logic.downloadSampleData() self.delayDisplay('Finished with download\n') self.delayDisplay("Unzipping") dicomFilesDirectory = self.logic.unzipSampleData(filePath) try: self.delayDisplay("Switching to temp database directory") tempDatabaseDirectory = slicer.app.temporaryPath + '/tempDICOMDatabase' import shutil try: shutil.rmtree(tempDatabaseDirectory) except OSError: pass qt.QDir().mkpath(tempDatabaseDirectory) if slicer.dicomDatabase: originalDatabaseDirectory = os.path.split(slicer.dicomDatabase.databaseFilename)[0] else: originalDatabaseDirectory = None settings = qt.QSettings() settings.setValue('DatabaseDirectory', tempDatabaseDirectory) dicomWidget = slicer.modules.dicom.widgetRepresentation().self() dicomWidget.onDatabaseDirectoryChanged(tempDatabaseDirectory) self.delayDisplay('Importing DICOM') mainWindow = slicer.util.mainWindow() mainWindow.moduleSelector().selectModule('DICOM') self.logic.importIntoDICOMDatabase(dicomFilesDirectory) dicomWidget.detailsPopup.open() # load the data by series UID mrHeadSeriesUID = "2.16.840.1.113662.4.4168496325.1025306170.548651188813145058" dicomWidget.detailsPopup.offerLoadables(mrHeadSeriesUID, 'Series') dicomWidget.detailsPopup.examineForLoading() self.delayDisplay('Loading Selection') dicomWidget.detailsPopup.loadCheckedLoadables() # # create a label map and set it for editing # masterNode = slicer.util.getNode('2: SAG*') volumesLogic = slicer.modules.volumes.logic() mergeNode = volumesLogic.CreateAndAddLabelVolume( slicer.mrmlScene, masterNode, masterNode.GetName() + '-label' ) mergeNode.GetDisplayNode().SetAndObserveColorNodeID('vtkMRMLColorTableNodeFileGenericAnatomyColors.txt') selectionNode = slicer.app.applicationLogic().GetSelectionNode() selectionNode.SetReferenceActiveVolumeID( masterNode.GetID() ) selectionNode.SetReferenceActiveLabelVolumeID( mergeNode.GetID() ) slicer.app.applicationLogic().PropagateVolumeSelection(0) # # go to the editor and do some drawing # slicer.util.selectModule('Editor') import EditorLib from EditorLib.EditUtil import EditUtil parameterNode = EditUtil.getParameterNode() parameterNode.SetParameter("LabelEffect,paintThreshold", "1") parameterNode.SetParameter("LabelEffect,paintThresholdMin", "70.0") parameterNode.SetParameter("LabelEffect,paintThresholdMax", "279.75") parameterNode.SetParameter("PaintEffect,radius", "40") parameterNode.SetParameter("PaintEffect,sphere", "1") self.delayDisplay("Paint some things") parameterNode = EditUtil.getParameterNode() lm = slicer.app.layoutManager() paintEffect = EditorLib.PaintEffectOptions() paintEffect.setMRMLDefaults() paintEffect.__del__() sliceWidget = lm.sliceWidget('Red') paintTool = EditorLib.PaintEffectTool(sliceWidget) EditUtil.setLabel(1) paintTool.paintAddPoint(100,100) paintTool.paintApply() EditUtil.setLabel(2) paintTool.paintAddPoint(200,200) paintTool.paintApply() paintTool.cleanup() paintTool = None # save these to compare with the one we read back originalSegmentationArray = slicer.util.array(mergeNode.GetID()) originalSegmentationNodeCopy = slicer.vtkMRMLLabelMapVolumeNode() originalSegmentationNodeCopy.CopyOrientation(mergeNode) # export the volumes into a SEG tempSEGDirectory = slicer.app.temporaryPath + '/tempDICOMSEG' qt.QDir().mkpath(tempSEGDirectory) segFilePath = os.path.join(tempSEGDirectory, "test.SEG.dcm") self.delayDisplay('spliting...', 200) EditUtil.splitPerStructureVolumes(masterNode, mergeNode) self.delayDisplay('exporting...', 200) EditUtil.exportAsDICOMSEG(masterNode) # close scene re-load the input data and SEG slicer.mrmlScene.Clear(0) indexer = ctk.ctkDICOMIndexer() indexer.addDirectory(slicer.dicomDatabase, tempSEGDirectory, None) indexer.waitForImportFinished() mrHeadStudyUID = "2.16.840.1.113662.4.4168496325.1025305873.7118351817185979330" dicomWidget.detailsPopup.offerLoadables(mrHeadStudyUID, 'Study') dicomWidget.detailsPopup.examineForLoading() self.delayDisplay('Loading Selection') dicomWidget.detailsPopup.loadCheckedLoadables() # confirm that segmentations are correctly reloaded headLabelName = '2: SAG/RF-FAST/VOL/FLIP 30-label' reloadedLabel = slicer.util.getNode(headLabelName) reloadedSegmentationArray = slicer.util.array(reloadedLabel.GetID()) import numpy self.assertTrue(numpy.alltrue(originalSegmentationArray == reloadedSegmentationArray)) geometryWarnings = volumesLogic.CompareVolumeGeometry(mergeNode, reloadedLabel) print(geometryWarnings) self.assertTrue(geometryWarnings == '') # re-export # close scene re-load the input data and SEG # confirm that segmentations are available again as per-structure volumes self.delayDisplay('Test passed!') except Exception, e: import traceback traceback.print_exc() self.delayDisplay('Test caused exception!\n' + str(e))
def run(self, enableScreenshots=0, screenshotScaleFactor=1): """ Run the actual algorithm """ self.delayDisplay("Running test of the Neurosurgical Planning tutorial") self.enableScreenshots = enableScreenshots self.screenshotScaleFactor = screenshotScaleFactor # conventional layout lm = slicer.app.layoutManager() lm.setLayout(2) moduleSelector = slicer.util.mainWindow().moduleSelector() # # first load the data # if self.enableScreenshots == 1: # for the tutorial, do it through the welcome module moduleSelector.selectModule("Welcome") self.delayDisplay("Screenshot") self.takeScreenshot("NeurosurgicalPlanning-Welcome", "Welcome module", -1) else: # otherwise show the sample data module moduleSelector.selectModule("SampleData") # use the sample data module logic to load data for the self test import SampleData sampleDataLogic = SampleData.SampleDataLogic() self.delayDisplay("Getting Baseline volume") baselineVolume = sampleDataLogic.downloadWhiteMatterExplorationBaselineVolume() self.takeScreenshot("NeurosurgicalPlanning-Loaded", "Data loaded", -1) # # link the viewers # if self.enableScreenshots == 1: # for the tutorial, pop up the linking control sliceController = slicer.app.layoutManager().sliceWidget("Red").sliceController() popupWidget = sliceController.findChild("ctkPopupWidget") if popupWidget is not None: popupWidget.pinPopup(1) self.takeScreenshot("NeurosurgicalPlanning-Link", "Link slice viewers", -1) popupWidget.pinPopup(0) sliceLogic = slicer.app.layoutManager().sliceWidget("Red").sliceLogic() compositeNode = sliceLogic.GetSliceCompositeNode() compositeNode.SetLinkedControl(1) # # baseline in the background # sliceLogic.StartSliceCompositeNodeInteraction(1) compositeNode.SetBackgroundVolumeID(baselineVolume.GetID()) sliceLogic.EndSliceCompositeNodeInteraction() self.takeScreenshot("NeurosurgicalPlanning-Baseline", "Baseline in background", -1) # # adjust window level on baseline # moduleSelector.selectModule("Volumes") baselineDisplay = baselineVolume.GetDisplayNode() baselineDisplay.SetAutoWindowLevel(0) baselineDisplay.SetWindow(2600) baselineDisplay.SetLevel(1206) self.takeScreenshot("NeurosurgicalPlanning-WindowLevel", "Set W/L on baseline", -1) # # switch to red slice only # lm.setLayout(6) self.takeScreenshot("NeurosurgicalPlanning-RedSliceOnly", "Set layout to Red Slice only", -1) # # segmentation of tumour # # # create a label map and set it for editing # volumesLogic = slicer.modules.volumes.logic() baselineVolumeLabel = volumesLogic.CreateAndAddLabelVolume( slicer.mrmlScene, baselineVolume, baselineVolume.GetName() + "-label" ) baselineDisplayNode = baselineVolumeLabel.GetDisplayNode() baselineDisplayNode.SetAndObserveColorNodeID("vtkMRMLColorTableNodeFileGenericAnatomyColors.txt") selectionNode = slicer.app.applicationLogic().GetSelectionNode() selectionNode.SetReferenceActiveVolumeID(baselineVolume.GetID()) selectionNode.SetReferenceActiveLabelVolumeID(baselineVolumeLabel.GetID()) slicer.app.applicationLogic().PropagateVolumeSelection(0) # # editor module # moduleSelector.selectModule("Editor") self.takeScreenshot("NeurosurgicalPlanning-Editor", "Showing Editor Module", -1) # set the slice offset so drawing is right sliceNode = sliceLogic.GetSliceNode() sliceOffset = 58.7 sliceNode.SetSliceOffset(sliceOffset) # # paint # parameterNode = EditUtil.getParameterNode() paintEffect = EditorLib.PaintEffectOptions() paintEffect.setMRMLDefaults() paintEffect.__del__() sliceWidget = lm.sliceWidget("Red") paintTool = EditorLib.PaintEffectTool(sliceWidget) self.takeScreenshot("NeurosurgicalPlanning-Paint", "Paint tool in Editor Module", -1) # # paint in cystic part of tumor, using converstion from RAS coords to # avoid slice widget size differences # EditUtil.setLabel(293) displayCoords = self.rasToDisplay(-7.4, 71, sliceOffset) paintTool.paintAddPoint(displayCoords[0], displayCoords[1]) displayCoords = self.rasToDisplay(-11, 73, sliceOffset) paintTool.paintAddPoint(displayCoords[0], displayCoords[1]) displayCoords = self.rasToDisplay(-12, 85, sliceOffset) paintTool.paintAddPoint(displayCoords[0], displayCoords[1]) displayCoords = self.rasToDisplay(-13, 91, sliceOffset) paintTool.paintAddPoint(displayCoords[0], displayCoords[1]) displayCoords = self.rasToDisplay(-15, 78, sliceOffset) paintTool.paintAddPoint(displayCoords[0], displayCoords[1]) paintTool.paintApply() self.takeScreenshot("NeurosurgicalPlanning-PaintCystic", "Paint cystic part of tumor", -1) # # paint in solid part of tumor # EditUtil.setLabel(7) displayCoords = self.rasToDisplay(-0.5, 118.5, sliceOffset) paintTool.paintAddPoint(displayCoords[0], displayCoords[1]) displayCoords = self.rasToDisplay(-7.4, 116, sliceOffset) paintTool.paintAddPoint(displayCoords[0], displayCoords[1]) paintTool.paintApply() self.takeScreenshot("NeurosurgicalPlanning-PaintSolid", "Paint solid part of tumor", -1) # # paint around the tumor # EditUtil.setLabel(295) rMax = 25 rMin = -50 aMax = 145 aMin = 50 rasStep = 5 # draw the top and bottom for r in range(rMin, rMax, rasStep): displayCoords = self.rasToDisplay(r, aMin, sliceOffset) paintTool.paintAddPoint(displayCoords[0], displayCoords[1]) displayCoords = self.rasToDisplay(r, aMax, sliceOffset) paintTool.paintAddPoint(displayCoords[0], displayCoords[1]) # draw the left and right for a in range(aMin, aMax, rasStep): displayCoords = self.rasToDisplay(rMin, a, sliceOffset) paintTool.paintAddPoint(displayCoords[0], displayCoords[1]) displayCoords = self.rasToDisplay(rMax, a, sliceOffset) paintTool.paintAddPoint(displayCoords[0], displayCoords[1]) paintTool.paintApply() self.takeScreenshot("NeurosurgicalPlanning-PaintAround", "Paint around tumor", -1) # # clean up after painting # paintTool.cleanup() paintTool = None # # Grow cut # growCutLogic = EditorLib.GrowCutEffectLogic(sliceWidget.sliceLogic()) growCutLogic.growCut() self.takeScreenshot("NeurosurgicalPlanning-Growcut", "Growcut", -1) # # Merge split volume # slicer.util.selectModule("Editor") slicer.util.findChildren(text="Split Merge Volume")[0].clicked() self.takeScreenshot("NeurosurgicalPlanning-SplitMerge", "SplitMerge", -1) # # go to the data module # moduleSelector.selectModule("Data") self.takeScreenshot("NeurosurgicalPlanning-SplitMergeData", "SplitMerge results in Data", -1) # # Ventricles Segmentation # moduleSelector.selectModule("Editor") # # select the label volume with the area around the tumor slicer.util.findChildren(name="PerStructureVolumesFrame")[0].collapsed = False treeView = slicer.util.findChildren(name="StructuresView")[0] selection = qt.QItemSelection() # selecting the last split volume in the third row row = 2 rowStart = treeView.model().index(row, 0) rowEnd = treeView.model().index(row, treeView.model().columnCount() - 1) # rowSel = qt.QItemSelection(rowStart, rowEnd) selection.select(rowStart, rowEnd) # backup: select the label map in the slice logic too baselinelabel295 = slicer.mrmlScene.GetFirstNodeByName("BaselineVolume-region 3-label") sliceLogic.StartSliceCompositeNodeInteraction(1) compositeNode.SetLabelVolumeID(baselinelabel295.GetID()) sliceLogic.EndSliceCompositeNodeInteraction() self.takeScreenshot("NeurosurgicalPlanning-SelOutside", "Select outside region", -1) # # Threshold tool # slicer.modules.EditorWidget.toolsBox.selectEffect("ThresholdEffect") parameterNode = EditUtil.getParameterNode() parameterNode.SetParameter("ThresholdEffect,min", str(1700)) slicer.modules.EditorWidget.toolsBox.currentTools[0].apply() self.takeScreenshot("NeurosurgicalPlanning-Ventricles", "Ventricles segmentation", -1) # # Save Islands # slicer.modules.EditorWidget.toolsBox.selectEffect("SaveIslandEffect") saveIslandLogic = EditorLib.SaveIslandEffectLogic(sliceWidget.sliceLogic()) displayCoords = self.rasToDisplay(25.3, 5.8, sliceOffset) xy = (displayCoords[0], displayCoords[1]) saveIslandLogic.saveIsland(xy) self.takeScreenshot("NeurosurgicalPlanning-SaveIsland", "Ventricles save island", -1) # # Merge and build # slicer.util.findChildren(text="Merge And Build")[0].clicked() # # switch to conventional layout # lm.setLayout(2) self.takeScreenshot("NeurosurgicalPlanning-MergeAndBuild", "Merged and built models", -1) # # select label volume with label 293, in the second row # row = 1 rowStart = treeView.model().index(row, 0) rowEnd = treeView.model().index(row, treeView.model().columnCount() - 1) # rowSel = qt.QItemSelection(rowStart, rowEnd) selection.select(rowStart, rowEnd) # backup: select the label map in the slice logic too baselinelabel293 = slicer.mrmlScene.GetFirstNodeByName("BaselineVolume-region 1-label") sliceLogic.StartSliceCompositeNodeInteraction(1) compositeNode.SetLabelVolumeID(baselinelabel293.GetID()) sliceLogic.EndSliceCompositeNodeInteraction() self.takeScreenshot("NeurosurgicalPlanning-SelCystic", "Select cystic region", -1) # # Dilate # slicer.modules.EditorWidget.toolsBox.selectEffect("DilateEffect") EditUtil.setLabel(293) self.takeScreenshot("NeurosurgicalPlanning-Dilate", "Dilate tool", -1) # tutorial says to click apply three times for d in range(1, 3): print d # slicer.util.findChildren(name='DilateEffectOptionsApply')[0].clicked() # slicer.modules.EditorWidget.toolsBox.currentTools[0].apply() slicer.modules.EditorWidget.toolsBox.currentOption.onApply() self.takeScreenshot("NeurosurgicalPlanning-Dilated", "Dilated tumor", -1) return True
def test_ThresholdThreading(self): """ Replicate the issue reported in bug 1822 where splitting a grow-cut produced volume causes a multi-threading related issue on mac release builds """ # # first, get some sample data # self.delayDisplay("Get some data") import SampleData sampleDataLogic = SampleData.SampleDataLogic() head = sampleDataLogic.downloadMRHead() # # now, define an ROI in it # roi = slicer.vtkMRMLAnnotationROINode() slicer.mrmlScene.AddNode(roi) roi.SetXYZ(-2, 104, -80) roi.SetRadiusXYZ(30, 30, 30) # # apply the cropping to the head # cropLogic = slicer.modules.cropvolume.logic() cvpn = slicer.vtkMRMLCropVolumeParametersNode() cvpn.SetROINodeID( roi.GetID() ) cvpn.SetInputVolumeNodeID( head.GetID() ) cropLogic.Apply( cvpn ) croppedHead = slicer.mrmlScene.GetNodeByID( cvpn.GetOutputVolumeNodeID() ) # # create a label map and set it for editing # volumesLogic = slicer.modules.volumes.logic() croppedHeadLabel = volumesLogic.CreateAndAddLabelVolume( slicer.mrmlScene, croppedHead, croppedHead.GetName() + '-label' ) selectionNode = slicer.app.applicationLogic().GetSelectionNode() selectionNode.SetActiveVolumeID( croppedHead.GetID() ) selectionNode.SetActiveLabelVolumeID( croppedHeadLabel.GetID() ) slicer.app.applicationLogic().PropagateVolumeSelection(0) # # got to the editor and do some drawing # self.delayDisplay("Paint some things") parameterNode = EditUtil.getParameterNode() lm = slicer.app.layoutManager() paintEffect = EditorLib.PaintEffectOptions() paintEffect.setMRMLDefaults() paintEffect.__del__() sliceWidget = lm.sliceWidget('Red') paintTool = EditorLib.PaintEffectTool(sliceWidget) EditUtil.setLabel(1) paintTool.paintAddPoint(100,100) paintTool.paintApply() EditUtil.setLabel(2) paintTool.paintAddPoint(200,200) paintTool.paintApply() paintTool.cleanup() paintTool = None self.delayDisplay("Now grow cut") # # now do GrowCut # growCutLogic = EditorLib.GrowCutEffectLogic(sliceWidget.sliceLogic()) growCutLogic.growCut() # # now split the volume, merge it back, and see if it looks right # preArray = slicer.util.array(croppedHeadLabel.GetName()) slicer.util.selectModule('Editor') slicer.util.findChildren(text='Split Merge Volume')[0].clicked() slicer.util.findChildren(text='Merge All')[0].clicked() postArray = slicer.util.array(croppedHeadLabel.GetName()) if (postArray - preArray).max() != 0: print("!$!$!#!@#!@!@$%! Test Failed!!") else: print("Ahh... test passed.") self.assertEqual((postArray - preArray).max(), 0) self.delayDisplay("Test passed!")
def run(self, enableScreenshots=0, screenshotScaleFactor=1): """ Run the actual algorithm """ self.delayDisplay( 'Running test of the Neurosurgical Planning tutorial') self.enableScreenshots = enableScreenshots self.screenshotScaleFactor = screenshotScaleFactor # conventional layout lm = slicer.app.layoutManager() lm.setLayout(2) moduleSelector = slicer.util.mainWindow().moduleSelector() # # first load the data # if self.enableScreenshots == 1: # for the tutorial, do it through the welcome module moduleSelector.selectModule('Welcome') self.delayDisplay("Screenshot") self.takeScreenshot('NeurosurgicalPlanning-Welcome', 'Welcome module', -1) else: # otherwise show the sample data module moduleSelector.selectModule('SampleData') # use the sample data module logic to load data for the self test import SampleData sampleDataLogic = SampleData.SampleDataLogic() self.delayDisplay("Getting Baseline volume") baselineVolume = sampleDataLogic.downloadWhiteMatterExplorationBaselineVolume( ) self.delayDisplay("Getting DTI volume") dtiVolume = sampleDataLogic.downloadWhiteMatterExplorationDTIVolume() self.takeScreenshot('NeurosurgicalPlanning-Loaded', 'Data loaded', -1) # # link the viewers # if self.enableScreenshots == 1: # for the tutorial, pop up the linking control sliceController = slicer.app.layoutManager().sliceWidget( "Red").sliceController() popupWidget = sliceController.findChild("ctkPopupWidget") if popupWidget != None: popupWidget.pinPopup(1) self.takeScreenshot('NeurosurgicalPlanning-Link', 'Link slice viewers', -1) popupWidget.pinPopup(0) sliceLogic = slicer.app.layoutManager().sliceWidget('Red').sliceLogic() compositeNode = sliceLogic.GetSliceCompositeNode() compositeNode.SetLinkedControl(1) # # baseline in the background # sliceLogic.StartSliceCompositeNodeInteraction(1) compositeNode.SetBackgroundVolumeID(baselineVolume.GetID()) sliceLogic.EndSliceCompositeNodeInteraction() self.takeScreenshot('NeurosurgicalPlanning-Baseline', 'Baseline in background', -1) # # adjust window level on baseline # moduleSelector.selectModule('Volumes') baselineDisplay = baselineVolume.GetDisplayNode() baselineDisplay.SetAutoWindowLevel(0) baselineDisplay.SetWindow(2600) baselineDisplay.SetLevel(1206) self.takeScreenshot('NeurosurgicalPlanning-WindowLevel', 'Set W/L on baseline', -1) # # switch to red slice only # lm.setLayout(6) self.takeScreenshot('NeurosurgicalPlanning-RedSliceOnly', 'Set layout to Red Slice only', -1) # # segmentation of tumour # # # create a label map and set it for editing # volumesLogic = slicer.modules.volumes.logic() baselineVolumeLabel = volumesLogic.CreateAndAddLabelVolume( slicer.mrmlScene, baselineVolume, baselineVolume.GetName() + '-label') baselineDisplayNode = baselineVolumeLabel.GetDisplayNode() baselineDisplayNode.SetAndObserveColorNodeID( 'vtkMRMLColorTableNodeFileGenericAnatomyColors.txt') selectionNode = slicer.app.applicationLogic().GetSelectionNode() selectionNode.SetReferenceActiveVolumeID(baselineVolume.GetID()) selectionNode.SetReferenceActiveLabelVolumeID( baselineVolumeLabel.GetID()) slicer.app.applicationLogic().PropagateVolumeSelection(0) # # editor module # moduleSelector.selectModule('Editor') self.takeScreenshot('NeurosurgicalPlanning-Editor', 'Showing Editor Module', -1) # set the slice offset so drawing is right sliceNode = sliceLogic.GetSliceNode() sliceOffset = 58.7 sliceNode.SetSliceOffset(sliceOffset) # # paint # parameterNode = EditUtil.getParameterNode() paintEffect = EditorLib.PaintEffectOptions() paintEffect.setMRMLDefaults() paintEffect.__del__() sliceWidget = lm.sliceWidget('Red') paintTool = EditorLib.PaintEffectTool(sliceWidget) self.takeScreenshot('NeurosurgicalPlanning-Paint', 'Paint tool in Editor Module', -1) # # paint in cystic part of tumor, using converstion from RAS coords to # avoid slice widget size differences # EditUtil.setLabel(293) displayCoords = self.rasToDisplay(-7.4, 71, sliceOffset) paintTool.paintAddPoint(displayCoords[0], displayCoords[1]) displayCoords = self.rasToDisplay(-11, 73, sliceOffset) paintTool.paintAddPoint(displayCoords[0], displayCoords[1]) displayCoords = self.rasToDisplay(-12, 85, sliceOffset) paintTool.paintAddPoint(displayCoords[0], displayCoords[1]) displayCoords = self.rasToDisplay(-13, 91, sliceOffset) paintTool.paintAddPoint(displayCoords[0], displayCoords[1]) displayCoords = self.rasToDisplay(-15, 78, sliceOffset) paintTool.paintAddPoint(displayCoords[0], displayCoords[1]) paintTool.paintApply() self.takeScreenshot('NeurosurgicalPlanning-PaintCystic', 'Paint cystic part of tumor', -1) # # paint in solid part of tumor # EditUtil.setLabel(7) displayCoords = self.rasToDisplay(-0.5, 118.5, sliceOffset) paintTool.paintAddPoint(displayCoords[0], displayCoords[1]) displayCoords = self.rasToDisplay(-7.4, 116, sliceOffset) paintTool.paintAddPoint(displayCoords[0], displayCoords[1]) paintTool.paintApply() self.takeScreenshot('NeurosurgicalPlanning-PaintSolid', 'Paint solid part of tumor', -1) # # paint around the tumor # EditUtil.setLabel(295) rMax = 25 rMin = -50 aMax = 145 aMin = 50 rasStep = 5 # draw the top and bottom for r in range(rMin, rMax, rasStep): displayCoords = self.rasToDisplay(r, aMin, sliceOffset) paintTool.paintAddPoint(displayCoords[0], displayCoords[1]) displayCoords = self.rasToDisplay(r, aMax, sliceOffset) paintTool.paintAddPoint(displayCoords[0], displayCoords[1]) # draw the left and right for a in range(aMin, aMax, rasStep): displayCoords = self.rasToDisplay(rMin, a, sliceOffset) paintTool.paintAddPoint(displayCoords[0], displayCoords[1]) displayCoords = self.rasToDisplay(rMax, a, sliceOffset) paintTool.paintAddPoint(displayCoords[0], displayCoords[1]) paintTool.paintApply() self.takeScreenshot('NeurosurgicalPlanning-PaintAround', 'Paint around tumor', -1) # # clean up after painting # paintTool.cleanup() paintTool = None # # Grow cut # growCutLogic = EditorLib.GrowCutEffectLogic(sliceWidget.sliceLogic()) growCutLogic.growCut() self.takeScreenshot('NeurosurgicalPlanning-Growcut', 'Growcut', -1) # # Merge split volume # slicer.util.selectModule('Editor') slicer.util.findChildren(text='Split Merge Volume')[0].clicked() self.takeScreenshot('NeurosurgicalPlanning-SplitMerge', 'SplitMerge', -1) # # go to the data module # moduleSelector.selectModule('Data') self.takeScreenshot('NeurosurgicalPlanning-SplitMergeData', 'SplitMerge results in Data', -1) # # Ventricles Segmentation # moduleSelector.selectModule('Editor') # # select the label volume with the area around the tumor slicer.util.findChildren( name='PerStructureVolumesFrame')[0].collapsed = False treeView = slicer.util.findChildren(name='StructuresView')[0] selection = qt.QItemSelection() # selecting the last split volume in the third row row = 2 rowStart = treeView.model().index(row, 0) rowEnd = treeView.model().index(row, treeView.model().columnCount() - 1) # rowSel = qt.QItemSelection(rowStart, rowEnd) selection.select(rowStart, rowEnd) # backup: select the label map in the slice logic too baselinelabel295 = slicer.mrmlScene.GetFirstNodeByName( "BaselineVolume-region 3-label") sliceLogic.StartSliceCompositeNodeInteraction(1) compositeNode.SetLabelVolumeID(baselinelabel295.GetID()) sliceLogic.EndSliceCompositeNodeInteraction() self.takeScreenshot('NeurosurgicalPlanning-SelOutside', 'Select outside region', -1) # # Threshold tool # slicer.modules.EditorWidget.toolsBox.selectEffect('ThresholdEffect') parameterNode = EditUtil.getParameterNode() parameterNode.SetParameter('ThresholdEffect,min', str(1700)) slicer.modules.EditorWidget.toolsBox.currentTools[0].apply() self.takeScreenshot('NeurosurgicalPlanning-Ventricles', 'Ventricles segmentation', -1) # # Save Islands # slicer.modules.EditorWidget.toolsBox.selectEffect('SaveIslandEffect') saveIslandLogic = EditorLib.SaveIslandEffectLogic( sliceWidget.sliceLogic()) displayCoords = self.rasToDisplay(25.3, 5.8, sliceOffset) xy = (displayCoords[0], displayCoords[1]) saveIslandLogic.saveIsland(xy) self.takeScreenshot('NeurosurgicalPlanning-SaveIsland', 'Ventricles save island', -1) # # Merge and build # slicer.util.findChildren(text='Merge And Build')[0].clicked() # # switch to conventional layout # lm.setLayout(2) self.takeScreenshot('NeurosurgicalPlanning-MergeAndBuild', 'Merged and built models', -1) # # Tractography label map seeding # # # select label volume with label 293, in the second row # row = 1 rowStart = treeView.model().index(row, 0) rowEnd = treeView.model().index(row, treeView.model().columnCount() - 1) # rowSel = qt.QItemSelection(rowStart, rowEnd) selection.select(rowStart, rowEnd) # backup: select the label map in the slice logic too baselinelabel293 = slicer.mrmlScene.GetFirstNodeByName( "BaselineVolume-region 1-label") sliceLogic.StartSliceCompositeNodeInteraction(1) compositeNode.SetLabelVolumeID(baselinelabel293.GetID()) sliceLogic.EndSliceCompositeNodeInteraction() self.takeScreenshot('NeurosurgicalPlanning-SelCystic', 'Select cystic region', -1) # # Dilate # slicer.modules.EditorWidget.toolsBox.selectEffect('DilateEffect') EditUtil.setLabel(293) self.takeScreenshot('NeurosurgicalPlanning-Dilate', 'Dilate tool', -1) # tutorial says to click apply three times for d in range(1, 3): print d # slicer.util.findChildren(name='DilateEffectOptionsApply')[0].clicked() # slicer.modules.EditorWidget.toolsBox.currentTools[0].apply() slicer.modules.EditorWidget.toolsBox.currentOption.onApply() self.takeScreenshot('NeurosurgicalPlanning-Dilated', 'Dilated tumor', -1) # # Tractography Label Map Seeding module # moduleSelector.selectModule('TractographyLabelMapSeeding') self.takeScreenshot('NeurosurgicalPlanning-LabelMapSeedingModule', 'Showing Tractography Label Seeding Module', -1) tractographyLabelSeeding = slicer.modules.tractographylabelmapseeding parameters = {} parameters['InputVolume'] = dtiVolume.GetID() baselinelabel293 = slicer.mrmlScene.GetFirstNodeByName( "BaselineVolume-region 1-label") # VTK6 TODO - set 'InputROIPipelineInfo' parameters['InputROI'] = baselinelabel293.GetID() fibers = slicer.vtkMRMLFiberBundleNode() slicer.mrmlScene.AddNode(fibers) parameters['OutputFibers'] = fibers.GetID() parameters['UseIndexSpace'] = 1 parameters['StoppingValue'] = 0.15 parameters['ROIlabel'] = 293 parameters['StoppingMode'] = 'FractionalAnisotropy' # defaults # parameters['ClTh'] = 0.3 # parameters['MinimumLength'] = 20 # parameters['MaximumLength'] = 800 # parameters['StoppingCurvature'] = 0.7 # parameters['IntegrationStepLength'] = 0.5 # parameters['SeedSpacing'] = 2 # and run it slicer.cli.run(tractographyLabelSeeding, None, parameters) self.takeScreenshot('NeurosurgicalPlanning-LabelMapSeeding', 'Showing Tractography Label Seeding Results', -1) # # tractography fiducial seeding # moduleSelector.selectModule('TractographyInteractiveSeeding') self.takeScreenshot('NeurosurgicalPlanning-TIS', 'Showing Tractography Interactive Seeding Module', -1) # DTI in background sliceLogic.StartSliceCompositeNodeInteraction(1) compositeNode.SetBackgroundVolumeID(dtiVolume.GetID()) sliceLogic.EndSliceCompositeNodeInteraction() # DTI visible in 3D sliceNode = sliceLogic.GetSliceNode() sliceLogic.StartSliceNodeInteraction(128) sliceNode.SetSliceVisible(1) sliceLogic.EndSliceNodeInteraction() self.takeScreenshot( 'NeurosurgicalPlanning-TIS-DTI', 'DTI volume with Tractography Interactive Seeding Module', -1) # place a fiducial displayNode = slicer.vtkMRMLMarkupsDisplayNode() slicer.mrmlScene.AddNode(displayNode) fidNode = slicer.vtkMRMLMarkupsFiducialNode() fidNode.SetName('F') slicer.mrmlScene.AddNode(fidNode) fidNode.SetAndObserveDisplayNodeID(displayNode.GetID()) r = 28.338526 a = 34.064367 s = sliceOffset fidNode.AddFiducial(r, a, s) # make it active selectionNode = slicer.mrmlScene.GetNodeByID( "vtkMRMLSelectionNodeSingleton") if (selectionNode != None): selectionNode.SetReferenceActivePlaceNodeID(fidNode.GetID()) self.takeScreenshot( 'NeurosurgicalPlanning-TIS-Fid1', 'Fiducial in Tractography Interactive Seeding Module', -1) # set up the arguments wr = slicer.modules.tractographyinteractiveseeding.widgetRepresentation( ) wr.setDiffusionTensorVolumeNode(dtiVolume) # create a fiber bundle fiducialFibers = slicer.vtkMRMLFiberBundleNode() slicer.mrmlScene.AddNode(fiducialFibers) wr.setFiberBundleNode(fiducialFibers) wr.setSeedingNode(fidNode) wr.setMinimumPath(10) wr.setStoppingValue(0.15) self.takeScreenshot('NeurosurgicalPlanning-TIS-Args', 'Tractography Interactive Seeding arguments', -1) self.delayDisplay("Moving the fiducial") for y in range(-20, 100, 5): msg = "Moving the fiducial to y = " + str(y) self.delayDisplay(msg, 250) fidNode.SetNthFiducialPosition(0, r, y, s) self.takeScreenshot( 'NeurosurgicalPlanning-TIS-Moved', 'Moved fiducial and did Tractography Interactive Seeding', -1) return True
def test_ThresholdThreading(self): """ Replicate the issue reported in bug 1822 where spliting a grow-cut produced volume causes a multi-threading related issue on mac release builds """ # # first, get some sample data # self.delayDisplay("Get some data") import SampleData sampleDataLogic = SampleData.SampleDataLogic() head = sampleDataLogic.downloadMRHead() # # now, define an ROI in it # roi = slicer.vtkMRMLAnnotationROINode() slicer.mrmlScene.AddNode(roi) roi.SetXYZ(-2, 104, -80) roi.SetRadiusXYZ(30, 30, 30) # # apply the cropping to the head # cropLogic = slicer.modules.cropvolume.logic() cvpn = slicer.vtkMRMLCropVolumeParametersNode() cvpn.SetROINodeID(roi.GetID()) cvpn.SetInputVolumeNodeID(head.GetID()) cropLogic.Apply(cvpn) croppedHead = slicer.mrmlScene.GetNodeByID( cvpn.GetOutputVolumeNodeID()) # # create a label map and set it for editing # volumesLogic = slicer.modules.volumes.logic() croppedHeadLabel = volumesLogic.CreateAndAddLabelVolume( slicer.mrmlScene, croppedHead, croppedHead.GetName() + '-label') selectionNode = slicer.app.applicationLogic().GetSelectionNode() selectionNode.SetActiveVolumeID(croppedHead.GetID()) selectionNode.SetActiveLabelVolumeID(croppedHeadLabel.GetID()) slicer.app.applicationLogic().PropagateVolumeSelection(0) # # got to the editor and do some drawing # self.delayDisplay("Paint some things") parameterNode = EditUtil.getParameterNode() lm = slicer.app.layoutManager() paintEffect = EditorLib.PaintEffectOptions() paintEffect.setMRMLDefaults() paintEffect.__del__() sliceWidget = lm.sliceWidget('Red') paintTool = EditorLib.PaintEffectTool(sliceWidget) EditUtil.setLabel(1) paintTool.paintAddPoint(100, 100) paintTool.paintApply() EditUtil.setLabel(2) paintTool.paintAddPoint(200, 200) paintTool.paintApply() paintTool.cleanup() paintTool = None self.delayDisplay("Now grow cut") # # now do GrowCut # growCutLogic = EditorLib.GrowCutEffectLogic(sliceWidget.sliceLogic()) growCutLogic.growCut() # # now split the volume, merge it back, and see if it looks right # preArray = slicer.util.array(croppedHeadLabel.GetName()) slicer.util.selectModule('Editor') slicer.util.findChildren(text='Split Merge Volume')[0].clicked() slicer.util.findChildren(text='Merge All')[0].clicked() postArray = slicer.util.array(croppedHeadLabel.GetName()) if (postArray - preArray).max() != 0: print("!$!$!#!@#!@!@$%! Test Failed!!") else: print("Ahh... test passed.") self.assertEqual((postArray - preArray).max(), 0) self.delayDisplay("Test passed!")
def test_SEGExporterSelfTest1(self): """ Test DICOM import, segmentation, export """ self.messageDelay = 50 import os self.delayDisplay("Starting the DICOM SEG Export test") # # first, get the data - a zip file of dicom data # import urllib downloads = (( 'http://slicer.kitware.com/midas3/download/item/220834/PieperMRHead.zip', 'PieperMRHead.zip'), ) self.delayDisplay("Downloading") for url, name in downloads: filePath = slicer.app.temporaryPath + '/' + name if not os.path.exists(filePath) or os.stat(filePath).st_size == 0: self.delayDisplay('Requesting download %s from %s...\n' % (name, url)) urllib.urlretrieve(url, filePath) self.delayDisplay('Finished with download\n') self.delayDisplay("Unzipping") dicomFilesDirectory = slicer.app.temporaryPath + '/dicomFiles' qt.QDir().mkpath(dicomFilesDirectory) slicer.app.applicationLogic().Unzip(filePath, dicomFilesDirectory) try: self.delayDisplay("Switching to temp database directory") tempDatabaseDirectory = slicer.app.temporaryPath + '/tempDICOMDatabase' import shutil shutil.rmtree(tempDatabaseDirectory) qt.QDir().mkpath(tempDatabaseDirectory) if slicer.dicomDatabase: originalDatabaseDirectory = os.path.split( slicer.dicomDatabase.databaseFilename)[0] else: originalDatabaseDirectory = None settings = qt.QSettings() settings.setValue('DatabaseDirectory', tempDatabaseDirectory) dicomWidget = slicer.modules.dicom.widgetRepresentation().self() dicomWidget.onDatabaseDirectoryChanged(tempDatabaseDirectory) self.delayDisplay('Importing DICOM') mainWindow = slicer.util.mainWindow() mainWindow.moduleSelector().selectModule('DICOM') indexer = ctk.ctkDICOMIndexer() indexer.addDirectory(slicer.dicomDatabase, dicomFilesDirectory, None) indexer.waitForImportFinished() dicomWidget.detailsPopup.open() # load the data by series UID mrHeadSeriesUID = "2.16.840.1.113662.4.4168496325.1025306170.548651188813145058" dicomWidget.detailsPopup.offerLoadables(mrHeadSeriesUID, 'Series') dicomWidget.detailsPopup.examineForLoading() self.delayDisplay('Loading Selection') dicomWidget.detailsPopup.loadCheckedLoadables() # # create a label map and set it for editing # masterNode = slicer.util.getNode('2: SAG*') volumesLogic = slicer.modules.volumes.logic() mergeNode = volumesLogic.CreateAndAddLabelVolume( slicer.mrmlScene, masterNode, masterNode.GetName() + '-label') mergeNode.GetDisplayNode().SetAndObserveColorNodeID( 'vtkMRMLColorTableNodeFileGenericAnatomyColors.txt') selectionNode = slicer.app.applicationLogic().GetSelectionNode() selectionNode.SetReferenceActiveVolumeID(masterNode.GetID()) selectionNode.SetReferenceActiveLabelVolumeID(mergeNode.GetID()) slicer.app.applicationLogic().PropagateVolumeSelection(0) # # go to the editor and do some drawing # slicer.util.selectModule('Editor') import EditorLib from EditorLib.EditUtil import EditUtil parameterNode = EditUtil.getParameterNode() parameterNode.SetParameter("LabelEffect,paintThreshold", "1") parameterNode.SetParameter("LabelEffect,paintThresholdMin", "70.0") parameterNode.SetParameter("LabelEffect,paintThresholdMax", "279.75") parameterNode.SetParameter("PaintEffect,radius", "40") parameterNode.SetParameter("PaintEffect,sphere", "1") self.delayDisplay("Paint some things") parameterNode = EditUtil.getParameterNode() lm = slicer.app.layoutManager() paintEffect = EditorLib.PaintEffectOptions() paintEffect.setMRMLDefaults() paintEffect.__del__() sliceWidget = lm.sliceWidget('Red') paintTool = EditorLib.PaintEffectTool(sliceWidget) EditUtil.setLabel(1) paintTool.paintAddPoint(100, 100) paintTool.paintApply() EditUtil.setLabel(2) paintTool.paintAddPoint(200, 200) paintTool.paintApply() paintTool.cleanup() paintTool = None # save these to compare with the one we read back originalSegmentationArray = slicer.util.array(mergeNode.GetID()) originalSegmentationNodeCopy = slicer.vtkMRMLLabelMapVolumeNode() originalSegmentationNodeCopy.CopyOrientation(mergeNode) # export the volumes into a SEG tempSEGDirectory = slicer.app.temporaryPath + '/tempDICOMSEG' qt.QDir().mkpath(tempSEGDirectory) segFilePath = os.path.join(tempSEGDirectory, "test.SEG.dcm") self.delayDisplay('spliting...', 200) EditUtil.splitPerStructureVolumes(masterNode, mergeNode) self.delayDisplay('exporting...', 200) EditUtil.exportAsDICOMSEG(masterNode) # close scene re-load the input data and SEG slicer.mrmlScene.Clear(0) indexer.addDirectory(slicer.dicomDatabase, tempSEGDirectory, None) indexer.waitForImportFinished() mrHeadStudyUID = "2.16.840.1.113662.4.4168496325.1025305873.7118351817185979330" dicomWidget.detailsPopup.offerLoadables(mrHeadStudyUID, 'Study') dicomWidget.detailsPopup.examineForLoading() self.delayDisplay('Loading Selection') dicomWidget.detailsPopup.loadCheckedLoadables() # confirm that segmentations are correctly reloaded headLabelName = '2: SAG/RF-FAST/VOL/FLIP 30-label' reloadedLabel = slicer.util.getNode(headLabelName) reloadedSegmentationArray = slicer.util.array( reloadedLabel.GetID()) import numpy self.assertTrue( numpy.alltrue( originalSegmentationArray == reloadedSegmentationArray)) geometryWarnings = volumesLogic.CompareVolumeGeometry( mergeNode, reloadedLabel) print(geometryWarnings) self.assertTrue(geometryWarnings == '') # re-export # close scene re-load the input data and SEG # confirm that segmentations are available again as per-structure volumes self.delayDisplay('Test passed!') except Exception, e: import traceback traceback.print_exc() self.delayDisplay('Test caused exception!\n' + str(e))