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_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.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 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
class ParenchymaWidget(ScriptedLoadableModuleWidget): """Uses ScriptedLoadableModuleWidget base class, available at: https://github.com/Slicer/Slicer/blob/master/Base/Python/slicer/ScriptedLoadableModule.py """ def __init__(self, parent = None): ScriptedLoadableModuleWidget.__init__(self, parent) self.masterNode = None self.labelNode = None self.paint = None self.paintMode = False self.correct = None self.correctMode = False self.logic = ParenchymaLogic() self.editUtil = EditUtil() #self.editUtil = EditorLib.EditUtil.EditUtil() #self.localParEditorWidget = None def setup(self): ScriptedLoadableModuleWidget.setup(self) # Instantiate and connect widgets ... # # Parameters Area # parametersCollapsibleButton = ctk.ctkCollapsibleButton() parametersCollapsibleButton.text = "Parameters" self.layout.addWidget(parametersCollapsibleButton) # Layout within the dummy collapsible button parametersLayout = qt.QFormLayout(parametersCollapsibleButton) # # input volume selector # self.inputSelector = slicer.qMRMLNodeComboBox() self.inputSelector.nodeTypes = ( ("vtkMRMLScalarVolumeNode"), "" ) self.inputSelector.addAttribute( "vtkMRMLScalarVolumeNode", "LabelMap", 0 ) self.inputSelector.selectNodeUponCreation = True self.inputSelector.addEnabled = False self.inputSelector.removeEnabled = False self.inputSelector.noneEnabled = True self.inputSelector.showHidden = False self.inputSelector.showChildNodeTypes = False self.inputSelector.setMRMLScene( slicer.mrmlScene ) self.inputSelector.setToolTip( "Pick the input to the algorithm." ) parametersLayout.addRow("Input Volume: ", self.inputSelector) #self.activeVolume = self.inputSelector.currentNode() #self.inputSelector.connect("currentNodeChanged(vtkMRMLNode*)", self.onSelect) #self.labelSelector = slicer.qSlicerLabelMapVolumeDisplayWidget() #parametersLayout.addRow("Label Map: ", self.labelSelector) # # Select Button # self.selectButton = qt.QPushButton("Select") self.selectButton.toolTip = "Select the volume." self.selectButton.enabled = True parametersLayout.addRow(self.selectButton) # # Gradient Button # self.gradientButton = qt.QPushButton("Gradient - sergio reimplementation") self.gradientButton.toolTip = "re-implementation of sergio's gradient." self.gradientButton.enabled = True parametersLayout.addRow(self.gradientButton) # # Paint Button # self.paintButton = qt.QPushButton("Paint") self.paintButton.toolTip = "Turn on paint." self.paintButton.enabled = True self.paintButton.checkable = True parametersLayout.addRow(self.paintButton) # # Apply mask Button # self.applyButton = qt.QPushButton("Apply mask") self.applyButton.toolTip = "Find area of mask." self.applyButton.enabled = True parametersLayout.addRow(self.applyButton) # # Range for threshold # self.threshold = ctk.ctkRangeWidget() lo, hi = self.getLoHiImageValues() self.threshold.minimum, self.threshold.maximum = lo, hi self.threshold.singleStep = (hi - lo) / 1000. parametersLayout.addRow(self.threshold) # # Grow Button # self.growButton = qt.QPushButton("Grow with Threshold") self.growButton.toolTip = "Grow into 3D with connected threshold." self.growButton.enabled = True parametersLayout.addRow(self.growButton) # # Liver 2D Button # self.liver2DButton = qt.QPushButton("Liver 2D") self.liver2DButton.toolTip = "Grow from mask in 2D, but up down into next slices." self.liver2DButton.enabled = True parametersLayout.addRow(self.liver2DButton) # # Cross remove Button # self.crossButton = qt.QPushButton("Cross remove") self.crossButton.toolTip = "re-implementation of sergio's cross remove." self.crossButton.enabled = True parametersLayout.addRow(self.crossButton) # # Connectivity reduction Button # self.connectivityButton = qt.QPushButton("Connectivity reduction") self.connectivityButton.toolTip = "re-implementation of sergio's connectivity reduction." self.connectivityButton.enabled = True parametersLayout.addRow(self.connectivityButton) # # Paint Button (correction) # self.correctButton = qt.QPushButton("Correct") self.correctButton.toolTip = "Turn on paint for annotating corrections." self.correctButton.enabled = True self.correctButton.checkable = True parametersLayout.addRow(self.correctButton) # # Track centroid under mask # self.trackMaskButton = qt.QPushButton("Track correction") self.trackMaskButton.toolTip = "Try to use correction mask, and track the centroid in has inside it" self.trackMaskButton.enabled = True parametersLayout.addRow(self.trackMaskButton) # # Erase mask (including all under) # self.eraseMaskButton = qt.QPushButton("Erase correction") self.eraseMaskButton.toolTip = "Delete the correction mask to hopefully orphan other areas" self.eraseMaskButton.enabled = True parametersLayout.addRow(self.eraseMaskButton) # # Remove unconnected # self.removeIsolatedButton = qt.QPushButton("Remove unconnected") self.removeIsolatedButton.toolTip = "try to see just the main blob and remove stuff not connected." self.removeIsolatedButton.enabled = True parametersLayout.addRow(self.removeIsolatedButton) # connections #buttons self.selectButton.connect('clicked(bool)', self.onSelectButton) self.gradientButton.connect('clicked(bool)', self.onGradientButton) self.paintButton.connect('clicked(bool)', self.onPaintButton) self.applyButton.connect('clicked(bool)', self.onApplyButton) self.growButton.connect('clicked(bool)', self.onGrowButton) self.liver2DButton.connect('clicked(bool)', self.onliver2DButton) self.crossButton.connect('clicked(bool)', self.onCrossButton) self.connectivityButton.connect('clicked(bool)', self.onConnectivityButton) # correction tools buttons self.correctButton.connect('clicked(bool)', self.onCorrectButton) self.trackMaskButton.connect('clicked(bool)', self.onTrackMaskButton) self.eraseMaskButton.connect('clicked(bool)', self.onEraseMaskButton) self.removeIsolatedButton.connect('clicked(bool)', self.onRemoveIsolatedButton) self.inputSelector.connect("currentNodeChanged(vtkMRMLNode*)", self.onSelect) self.threshold.connect('valuesChanged(double,double)', self.onThresholdValuesChanged) # Creates and adds the custom Editor Widget to the module #self.localParEditorWidget = ParEditorWidget(parent=self.parent, showVolumesFrame=False) #self.localParEditorWidget.setup() #self.localParEditorWidget.enter() # Add vertical spacer self.layout.addStretch(1) # sets the layout to Red Slice Only layoutManager = slicer.app.layoutManager() layoutManager.setLayout(slicer.vtkMRMLLayoutNode.SlicerLayoutOneUpRedSliceView) '''-----------------------------------------------------------------------------''' def cleanup(self): pass def onSelect(self): self.applyButton.enabled = self.inputSelector.currentNode() self.masterNode = self.inputSelector.currentNode() def onSelectButton(self): self.masterNode = self.inputSelector.currentNode() lo, hi = self.getLoHiImageValues() self.threshold.minimum, self.threshold.maximum = lo, hi self.threshold.singleStep = (hi - lo) / 1000. #print(self.inputSelector.currentNode()) def onLabelButton(self): self.labelNode = self.logic.createLabelMap(self.inputSelector.currentNode()) def onProcessFilterButton(self): self.logic.processFilter(self.masterNode) def onPaintButton(self): if self.paintMode: self.paintMode = False print("deleting paint") self.painter.cleanup() self.painter = None #self.paint.removeObs() else: self.paintMode = True # just in case? selectionNode = slicer.app.applicationLogic().GetSelectionNode() selectionNode.SetReferenceActiveVolumeID( self.masterNode.GetID() ) if self.labelNode == None: self.labelNode = self.logic.createLabelMap(self.inputSelector.currentNode()) selectionNode.SetReferenceActiveLabelVolumeID( self.labelNode.GetID() ) slicer.app.applicationLogic().PropagateVolumeSelection(0) self.editUtil.setLabel(1) # green print("create paint (editor paint effect tool)") lm = slicer.app.layoutManager() paintEffect = EditorLib.PaintEffectOptions() paintEffect.setMRMLDefaults() paintEffect.__del__() sliceWidget = lm.sliceWidget('Red') self.painter = EditorLib.PaintEffectTool(sliceWidget) def onApplyButton(self): self.logic.runMask(self.masterNode, self.labelNode) mean, std = self.logic.getMeanSD() max = mean + std min = mean - std hi = mean + 4*std lo = mean - 4*std self.threshold.minimum, self.threshold.maximum = lo, hi self.setThresholdValues(min, max) def onGrowButton(self): self.logic.runThreshold(self.masterNode, self.labelNode) def onGradientButton(self): self.logic.runGradient(self.masterNode) def onliver2DButton(self): print("Liver button") #runFindLiver2D(self,masterNode,labelNode): self.logic.runFindLiver2D(self.masterNode, self.labelNode) def onCrossButton(self): self.logic.runCrossRemove(self.masterNode, self.labelNode, 2) # need to pass in size of cross def onConnectivityButton(self): self.logic.runConnectivity(self.masterNode, self.labelNode, 10) # need to pass in number of pixels around it that need to be 1 def onCorrectButton(self): if self.correctMode: self.correctMode = False print("deleting correct") self.painter.cleanup() self.painter = None #self.paint.removeObs() else: self.correctMode = True # just in case? selectionNode = slicer.app.applicationLogic().GetSelectionNode() selectionNode.SetReferenceActiveVolumeID( self.masterNode.GetID() ) if self.labelNode == None: self.labelNode = self.logic.createLabelMap(self.inputSelector.currentNode()) selectionNode.SetReferenceActiveLabelVolumeID( self.labelNode.GetID() ) slicer.app.applicationLogic().PropagateVolumeSelection(0) self.editUtil.setLabel(5) # red print("create correct (editor paint effect tool)") lm = slicer.app.layoutManager() paintEffect = EditorLib.PaintEffectOptions() paintEffect.setMRMLDefaults() paintEffect.__del__() sliceWidget = lm.sliceWidget('Red') self.painter = EditorLib.PaintEffectTool(sliceWidget) def onTrackMaskButton(self): self.logic.runTrackMask(self.masterNode, self.labelNode) def onEraseMaskButton(self): self.logic.runEraseMask(self.masterNode, self.labelNode) def onRemoveIsolatedButton(self): self.logic.runRemoveIsolated(self.masterNode, self.labelNode) def onEdgeButton(self): self.logic.runFindEdge(self.masterNode, self.labelNode) def getLoHiImageValues(self): backgroundImage = self.masterNode lo = 0 hi = 100 if backgroundImage: data = backgroundImage.GetImageData() lo, hi = data.GetScalarRange() print('Low: ', lo) print('High: ', hi) return lo, hi def onThresholdValuesChanged(self): print('value changed') min = self.threshold.minimumValue max = self.threshold.maximumValue print(min, max) def setThresholdValues(self, min, max): self.threshold.setMinimumValue( min ) self.threshold.setMaximumValue( max )
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
class ParenchymaWidget(ScriptedLoadableModuleWidget): """Uses ScriptedLoadableModuleWidget base class, available at: https://github.com/Slicer/Slicer/blob/master/Base/Python/slicer/ScriptedLoadableModule.py """ def __init__(self, parent=None): ScriptedLoadableModuleWidget.__init__(self, parent) self.masterNode = None self.labelNode = None self.paint = None self.paintMode = False self.correct = None self.correctMode = False self.logic = ParenchymaLogic() self.editUtil = EditUtil() #self.editUtil = EditorLib.EditUtil.EditUtil() #self.localParEditorWidget = None def setup(self): ScriptedLoadableModuleWidget.setup(self) # Instantiate and connect widgets ... # # Parameters Area # parametersCollapsibleButton = ctk.ctkCollapsibleButton() parametersCollapsibleButton.text = "Parameters" self.layout.addWidget(parametersCollapsibleButton) # Layout within the dummy collapsible button parametersLayout = qt.QFormLayout(parametersCollapsibleButton) # # input volume selector # self.inputSelector = slicer.qMRMLNodeComboBox() self.inputSelector.nodeTypes = (("vtkMRMLScalarVolumeNode"), "") self.inputSelector.addAttribute("vtkMRMLScalarVolumeNode", "LabelMap", 0) self.inputSelector.selectNodeUponCreation = True self.inputSelector.addEnabled = False self.inputSelector.removeEnabled = False self.inputSelector.noneEnabled = True self.inputSelector.showHidden = False self.inputSelector.showChildNodeTypes = False self.inputSelector.setMRMLScene(slicer.mrmlScene) self.inputSelector.setToolTip("Pick the input to the algorithm.") parametersLayout.addRow("Input Volume: ", self.inputSelector) #self.activeVolume = self.inputSelector.currentNode() #self.inputSelector.connect("currentNodeChanged(vtkMRMLNode*)", self.onSelect) #self.labelSelector = slicer.qSlicerLabelMapVolumeDisplayWidget() #parametersLayout.addRow("Label Map: ", self.labelSelector) # # Select Button # self.selectButton = qt.QPushButton("Select") self.selectButton.toolTip = "Select the volume." self.selectButton.enabled = True parametersLayout.addRow(self.selectButton) # # Gradient Button # self.gradientButton = qt.QPushButton( "Gradient - sergio reimplementation") self.gradientButton.toolTip = "re-implementation of sergio's gradient." self.gradientButton.enabled = True parametersLayout.addRow(self.gradientButton) # # Paint Button # self.paintButton = qt.QPushButton("Paint") self.paintButton.toolTip = "Turn on paint." self.paintButton.enabled = True self.paintButton.checkable = True parametersLayout.addRow(self.paintButton) # # Apply mask Button # self.applyButton = qt.QPushButton("Apply mask") self.applyButton.toolTip = "Find area of mask." self.applyButton.enabled = True parametersLayout.addRow(self.applyButton) # # Range for threshold # self.threshold = ctk.ctkRangeWidget() lo, hi = self.getLoHiImageValues() self.threshold.minimum, self.threshold.maximum = lo, hi self.threshold.singleStep = (hi - lo) / 1000. parametersLayout.addRow(self.threshold) # # Grow Button # self.growButton = qt.QPushButton("Grow with Threshold") self.growButton.toolTip = "Grow into 3D with connected threshold." self.growButton.enabled = True parametersLayout.addRow(self.growButton) # # Liver 2D Button # self.liver2DButton = qt.QPushButton("Liver 2D") self.liver2DButton.toolTip = "Grow from mask in 2D, but up down into next slices." self.liver2DButton.enabled = True parametersLayout.addRow(self.liver2DButton) # # Cross remove Button # self.crossButton = qt.QPushButton("Cross remove") self.crossButton.toolTip = "re-implementation of sergio's cross remove." self.crossButton.enabled = True parametersLayout.addRow(self.crossButton) # # Connectivity reduction Button # self.connectivityButton = qt.QPushButton("Connectivity reduction") self.connectivityButton.toolTip = "re-implementation of sergio's connectivity reduction." self.connectivityButton.enabled = True parametersLayout.addRow(self.connectivityButton) # # Paint Button (correction) # self.correctButton = qt.QPushButton("Correct") self.correctButton.toolTip = "Turn on paint for annotating corrections." self.correctButton.enabled = True self.correctButton.checkable = True parametersLayout.addRow(self.correctButton) # # Track centroid under mask # self.trackMaskButton = qt.QPushButton("Track correction") self.trackMaskButton.toolTip = "Try to use correction mask, and track the centroid in has inside it" self.trackMaskButton.enabled = True parametersLayout.addRow(self.trackMaskButton) # # Erase mask (including all under) # self.eraseMaskButton = qt.QPushButton("Erase correction") self.eraseMaskButton.toolTip = "Delete the correction mask to hopefully orphan other areas" self.eraseMaskButton.enabled = True parametersLayout.addRow(self.eraseMaskButton) # # Remove unconnected # self.removeIsolatedButton = qt.QPushButton("Remove unconnected") self.removeIsolatedButton.toolTip = "try to see just the main blob and remove stuff not connected." self.removeIsolatedButton.enabled = True parametersLayout.addRow(self.removeIsolatedButton) # connections #buttons self.selectButton.connect('clicked(bool)', self.onSelectButton) self.gradientButton.connect('clicked(bool)', self.onGradientButton) self.paintButton.connect('clicked(bool)', self.onPaintButton) self.applyButton.connect('clicked(bool)', self.onApplyButton) self.growButton.connect('clicked(bool)', self.onGrowButton) self.liver2DButton.connect('clicked(bool)', self.onliver2DButton) self.crossButton.connect('clicked(bool)', self.onCrossButton) self.connectivityButton.connect('clicked(bool)', self.onConnectivityButton) # correction tools buttons self.correctButton.connect('clicked(bool)', self.onCorrectButton) self.trackMaskButton.connect('clicked(bool)', self.onTrackMaskButton) self.eraseMaskButton.connect('clicked(bool)', self.onEraseMaskButton) self.removeIsolatedButton.connect('clicked(bool)', self.onRemoveIsolatedButton) self.inputSelector.connect("currentNodeChanged(vtkMRMLNode*)", self.onSelect) self.threshold.connect('valuesChanged(double,double)', self.onThresholdValuesChanged) # Creates and adds the custom Editor Widget to the module #self.localParEditorWidget = ParEditorWidget(parent=self.parent, showVolumesFrame=False) #self.localParEditorWidget.setup() #self.localParEditorWidget.enter() # Add vertical spacer self.layout.addStretch(1) # sets the layout to Red Slice Only layoutManager = slicer.app.layoutManager() layoutManager.setLayout( slicer.vtkMRMLLayoutNode.SlicerLayoutOneUpRedSliceView) '''-----------------------------------------------------------------------------''' def cleanup(self): pass def onSelect(self): self.applyButton.enabled = self.inputSelector.currentNode() self.masterNode = self.inputSelector.currentNode() def onSelectButton(self): self.masterNode = self.inputSelector.currentNode() lo, hi = self.getLoHiImageValues() self.threshold.minimum, self.threshold.maximum = lo, hi self.threshold.singleStep = (hi - lo) / 1000. #print(self.inputSelector.currentNode()) def onLabelButton(self): self.labelNode = self.logic.createLabelMap( self.inputSelector.currentNode()) def onProcessFilterButton(self): self.logic.processFilter(self.masterNode) def onPaintButton(self): if self.paintMode: self.paintMode = False print("deleting paint") self.painter.cleanup() self.painter = None #self.paint.removeObs() else: self.paintMode = True # just in case? selectionNode = slicer.app.applicationLogic().GetSelectionNode() selectionNode.SetReferenceActiveVolumeID(self.masterNode.GetID()) if self.labelNode == None: self.labelNode = self.logic.createLabelMap( self.inputSelector.currentNode()) selectionNode.SetReferenceActiveLabelVolumeID( self.labelNode.GetID()) slicer.app.applicationLogic().PropagateVolumeSelection(0) self.editUtil.setLabel(1) # green print("create paint (editor paint effect tool)") lm = slicer.app.layoutManager() paintEffect = EditorLib.PaintEffectOptions() paintEffect.setMRMLDefaults() paintEffect.__del__() sliceWidget = lm.sliceWidget('Red') self.painter = EditorLib.PaintEffectTool(sliceWidget) def onApplyButton(self): self.logic.runMask(self.masterNode, self.labelNode) mean, std = self.logic.getMeanSD() max = mean + std min = mean - std hi = mean + 4 * std lo = mean - 4 * std self.threshold.minimum, self.threshold.maximum = lo, hi self.setThresholdValues(min, max) def onGrowButton(self): self.logic.runThreshold(self.masterNode, self.labelNode) def onGradientButton(self): self.logic.runGradient(self.masterNode) def onliver2DButton(self): print("Liver button") #runFindLiver2D(self,masterNode,labelNode): self.logic.runFindLiver2D(self.masterNode, self.labelNode) def onCrossButton(self): self.logic.runCrossRemove(self.masterNode, self.labelNode, 2) # need to pass in size of cross def onConnectivityButton(self): self.logic.runConnectivity( self.masterNode, self.labelNode, 10) # need to pass in number of pixels around it that need to be 1 def onCorrectButton(self): if self.correctMode: self.correctMode = False print("deleting correct") self.painter.cleanup() self.painter = None #self.paint.removeObs() else: self.correctMode = True # just in case? selectionNode = slicer.app.applicationLogic().GetSelectionNode() selectionNode.SetReferenceActiveVolumeID(self.masterNode.GetID()) if self.labelNode == None: self.labelNode = self.logic.createLabelMap( self.inputSelector.currentNode()) selectionNode.SetReferenceActiveLabelVolumeID( self.labelNode.GetID()) slicer.app.applicationLogic().PropagateVolumeSelection(0) self.editUtil.setLabel(5) # red print("create correct (editor paint effect tool)") lm = slicer.app.layoutManager() paintEffect = EditorLib.PaintEffectOptions() paintEffect.setMRMLDefaults() paintEffect.__del__() sliceWidget = lm.sliceWidget('Red') self.painter = EditorLib.PaintEffectTool(sliceWidget) def onTrackMaskButton(self): self.logic.runTrackMask(self.masterNode, self.labelNode) def onEraseMaskButton(self): self.logic.runEraseMask(self.masterNode, self.labelNode) def onRemoveIsolatedButton(self): self.logic.runRemoveIsolated(self.masterNode, self.labelNode) def onEdgeButton(self): self.logic.runFindEdge(self.masterNode, self.labelNode) def getLoHiImageValues(self): backgroundImage = self.masterNode lo = 0 hi = 100 if backgroundImage: data = backgroundImage.GetImageData() lo, hi = data.GetScalarRange() print('Low: ', lo) print('High: ', hi) return lo, hi def onThresholdValuesChanged(self): print('value changed') min = self.threshold.minimumValue max = self.threshold.maximumValue print(min, max) def setThresholdValues(self, min, max): self.threshold.setMinimumValue(min) self.threshold.setMaximumValue(max)
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))