def test_SegmentStatisticsBasic(self): """ This tests some aspects of the label statistics """ self.delayDisplay("Starting test_SegmentStatisticsBasic") import vtkSegmentationCorePython as vtkSegmentationCore import vtkSlicerSegmentationsModuleLogicPython as vtkSlicerSegmentationsModuleLogic import SampleData from SegmentStatistics import SegmentStatisticsLogic self.delayDisplay("Load master volume") sampleDataLogic = SampleData.SampleDataLogic() masterVolumeNode = sampleDataLogic.downloadMRBrainTumor1() self.delayDisplay("Create segmentation containing a few spheres") segmentationNode = slicer.vtkMRMLSegmentationNode() slicer.mrmlScene.AddNode(segmentationNode) segmentationNode.CreateDefaultDisplayNodes() segmentationNode.SetReferenceImageGeometryParameterFromVolumeNode(masterVolumeNode) # Geometry for each segment is defined by: radius, posX, posY, posZ segmentGeometries = [[10, -6,30,28], [20, 0,65,32], [15, 1, -14, 30], [12, 0, 28, -7], [5, 0,30,64], [12, 31, 33, 27], [17, -42, 30, 27]] for segmentGeometry in segmentGeometries: sphereSource = vtk.vtkSphereSource() sphereSource.SetRadius(segmentGeometry[0]) sphereSource.SetCenter(segmentGeometry[1], segmentGeometry[2], segmentGeometry[3]) sphereSource.Update() segment = vtkSegmentationCore.vtkSegment() segment.SetName(segmentationNode.GetSegmentation().GenerateUniqueSegmentID("Test")) segment.AddRepresentation(vtkSegmentationCore.vtkSegmentationConverter.GetSegmentationClosedSurfaceRepresentationName(), sphereSource.GetOutput()) segmentationNode.GetSegmentation().AddSegment(segment) self.delayDisplay("Compute statistics") segStatLogic = SegmentStatisticsLogic() segStatLogic.computeStatistics(segmentationNode, masterVolumeNode) self.delayDisplay("Check a few numerical results") self.assertEqual( segStatLogic.statistics["Test_2","LM voxel count"], 9807) self.assertEqual( segStatLogic.statistics["Test_4","GS voxel count"], 380) self.delayDisplay("Export results to table") resultsTableNode = slicer.vtkMRMLTableNode() slicer.mrmlScene.AddNode(resultsTableNode) segStatLogic.exportToTable(resultsTableNode) segStatLogic.showTable(resultsTableNode) self.delayDisplay("Export results to string") logging.info(segStatLogic.exportToString()) outputFilename = slicer.app.temporaryPath + '/SegmentStatisticsTestOutput.csv' self.delayDisplay("Export results to CSV file: "+outputFilename) segStatLogic.exportToCSVFile(outputFilename) self.delayDisplay('test_SegmentStatisticsBasic passed!')
def __init__(self,parent=None, parameterNode=None, pluginName=None): super(qt.QDialog,self).__init__(parent) self.title = "Edit Segment Statistics Parameters" self.parameterNode = parameterNode self.pluginName = pluginName self.logic = SegmentStatisticsLogic() # for access to plugins and editor widgets self.logic.setParameterNode(self.parameterNode) self.setup()
def __init__(self): SegmentStatisticsLogic.__init__(self) self.plugins = [ p for p in self.plugins if not isinstance(p, LabelmapSegmentStatisticsPlugin) ] self.reset() self.terminologyLogic = slicer.modules.terminologies.logic()
def exportToTable(self, table=None, nonEmptyKeysOnly=True): if not table: table = slicer.vtkMRMLTableNode() table.SetName(slicer.mrmlScene.GenerateUniqueName(self.grayscaleNode.GetName() + ' statistics')) slicer.mrmlScene.AddNode(table) table.SetUseColumnNameAsColumnHeader(True) SegmentStatisticsLogic.exportToTable(self, table, nonEmptyKeysOnly) return table
def getStatForVol(self, volFile, folderSaveName, condition, seriesName=""): # Load the volume, get a tuple of (success, vtkMRMLScalarVolumeNode) vol = slicer.util.loadVolume(volFile, returnNode=True) # If the volume was not successfully loaded, exit if not vol[0]: # Print error if volume does not exist or is inaccessible raise IOError("Volume could not be loaded from: " + volFile) # Get the volume node volNode = vol[1] # Instantiate a SegmentStatisticsLogic object to store the statistics segStatLogic = SegmentStatisticsLogic() segStatLogic.getParameterNode().SetParameter("Segmentation", self.segNode.GetID()) segStatLogic.getParameterNode().SetParameter("ScalarVolume", volNode.GetID()) # Compute the statistics using the specified volume as the master volume segStatLogic.computeStatistics() # If the --getsnr argument was specified if self.getsnr: statistics = segStatLogic.getStatistics() # Get the noise segment's standard deviation noiseStdev = statistics[( self.noiseSegmentID, "ScalarVolumeSegmentStatisticsPlugin.stdev")] # Compute the SNRs of other segments segStatLogic = self.computeSnrs(segStatLogic, statistics['SegmentIDs'], noiseStdev) # If this object's statistics dictionary does not contain this series if seriesName not in self.metaStats[condition]: # Initialize it into an empty list self.metaStats[condition][seriesName] = [] # Append current volume's statistics to the statistics dictionary self.metaStats[condition][seriesName].append( segStatLogic.getStatistics()) # Specify the folder name of output documentsDir = os.path.normpath( os.path.expanduser( r"~\\Documents\\StatsCollector\\SegmentStatistics")) # Specify the folder path of the output fileParentDir = os.path.join(documentsDir, folderSaveName) # Specify the full file path of the Excel file to output filePath = os.path.join(fileParentDir, condition) # Make the folder directories if they don't exist if not os.path.exists(fileParentDir): os.makedirs(fileParentDir) # Export the stats to a file self.exportStatsToXl(segStatLogic, filePath, volNode.GetName(), seriesName)
def exportToTable(self, table=None, nonEmptyKeysOnly=True): if not table: table = slicer.vtkMRMLTableNode() table.SetName( slicer.mrmlScene.GenerateUniqueName( self.grayscaleNode.GetName() + ' statistics')) slicer.mrmlScene.AddNode(table) table.SetUseColumnNameAsColumnHeader(True) SegmentStatisticsLogic.exportToTable(self, table, nonEmptyKeysOnly) return table
def calculateStatistics(self): from SegmentStatistics import SegmentStatisticsLogic segStatLogic = SegmentStatisticsLogic() segStatLogic.getParameterNode().SetParameter( "Segmentation", self.segmentationEditorWidget.segmentationNodeID()) self.segmentationEditorWidget.segmentationNode( ).CreateDefaultDisplayNodes() segStatLogic.computeStatistics() resultsTableNode = slicer.vtkMRMLTableNode() slicer.mrmlScene.AddNode(resultsTableNode) segStatLogic.exportToTable(resultsTableNode) segStatLogic.showTable(resultsTableNode)
def setup(self): ScriptedLoadableModuleWidget.setup(self) self.logic = SegmentStatisticsLogic() self.grayscaleNode = None self.labelNode = None self.parameterNode = None self.parameterNodeObserver = None # Instantiate and connect widgets ... # # Parameter set selector self.parameterNodeSelector = slicer.qMRMLNodeComboBox() self.parameterNodeSelector.nodeTypes = ["vtkMRMLScriptedModuleNode"] self.parameterNodeSelector.addAttribute("vtkMRMLScriptedModuleNode", "ModuleName", "SegmentStatistics") self.parameterNodeSelector.selectNodeUponCreation = True self.parameterNodeSelector.addEnabled = True self.parameterNodeSelector.renameEnabled = True self.parameterNodeSelector.removeEnabled = True self.parameterNodeSelector.noneEnabled = False self.parameterNodeSelector.showHidden = True self.parameterNodeSelector.showChildNodeTypes = False self.parameterNodeSelector.baseName = "SegmentStatistics" self.parameterNodeSelector.setMRMLScene(slicer.mrmlScene) self.parameterNodeSelector.setToolTip("Pick parameter set") self.layout.addWidget(self.parameterNodeSelector) # Inputs inputsCollapsibleButton = ctk.ctkCollapsibleButton() inputsCollapsibleButton.text = "Inputs" self.layout.addWidget(inputsCollapsibleButton) inputsFormLayout = qt.QFormLayout(inputsCollapsibleButton) # Segmentation selector self.segmentationSelector = slicer.qMRMLNodeComboBox() self.segmentationSelector.nodeTypes = ["vtkMRMLSegmentationNode"] self.segmentationSelector.addEnabled = False self.segmentationSelector.removeEnabled = True self.segmentationSelector.renameEnabled = True self.segmentationSelector.setMRMLScene(slicer.mrmlScene) self.segmentationSelector.setToolTip( "Pick the segmentation to compute statistics for") inputsFormLayout.addRow("Segmentation:", self.segmentationSelector) # Scalar volume selector self.scalarSelector = slicer.qMRMLNodeComboBox() self.scalarSelector.nodeTypes = ["vtkMRMLScalarVolumeNode"] self.scalarSelector.addEnabled = False self.scalarSelector.removeEnabled = True self.scalarSelector.renameEnabled = True self.scalarSelector.noneEnabled = True self.scalarSelector.showChildNodeTypes = False self.scalarSelector.setMRMLScene(slicer.mrmlScene) self.scalarSelector.setToolTip( "Select the scalar volume for intensity statistics calculations") inputsFormLayout.addRow("Scalar volume:", self.scalarSelector) # Output table selector outputCollapsibleButton = ctk.ctkCollapsibleButton() outputCollapsibleButton.text = "Output" self.layout.addWidget(outputCollapsibleButton) outputFormLayout = qt.QFormLayout(outputCollapsibleButton) self.outputTableSelector = slicer.qMRMLNodeComboBox() self.outputTableSelector.noneDisplay = "Create new table" self.outputTableSelector.setMRMLScene(slicer.mrmlScene) self.outputTableSelector.nodeTypes = ["vtkMRMLTableNode"] self.outputTableSelector.addEnabled = True self.outputTableSelector.selectNodeUponCreation = True self.outputTableSelector.renameEnabled = True self.outputTableSelector.removeEnabled = True self.outputTableSelector.noneEnabled = True self.outputTableSelector.setToolTip( "Select the table where statistics will be saved into") self.outputTableSelector.setCurrentNode(None) outputFormLayout.addRow("Output table:", self.outputTableSelector) # Parameter set parametersCollapsibleButton = ctk.ctkCollapsibleButton() parametersCollapsibleButton.text = "Advanced" parametersCollapsibleButton.collapsed = True self.layout.addWidget(parametersCollapsibleButton) self.parametersLayout = qt.QFormLayout(parametersCollapsibleButton) # Edit parameter set button to open SegmentStatisticsParameterEditorDialog # Note: we add the plugins' option widgets to the module widget instead of using the editor dialog #self.editParametersButton = qt.QPushButton("Edit Parameter Set") #self.editParametersButton.toolTip = "Editor Statistics Plugin Parameter Set." #self.parametersLayout.addRow(self.editParametersButton) #self.editParametersButton.connect('clicked()', self.onEditParameters) # add caclulator's option widgets self.addPluginOptionWidgets() # Apply Button self.applyButton = qt.QPushButton("Apply") self.applyButton.toolTip = "Calculate Statistics." self.applyButton.enabled = False self.parent.layout().addWidget(self.applyButton) # Add vertical spacer self.parent.layout().addStretch(1) # connections self.applyButton.connect('clicked()', self.onApply) self.scalarSelector.connect('currentNodeChanged(vtkMRMLNode*)', self.onNodeSelectionChanged) self.segmentationSelector.connect('currentNodeChanged(vtkMRMLNode*)', self.onNodeSelectionChanged) self.outputTableSelector.connect('currentNodeChanged(vtkMRMLNode*)', self.onNodeSelectionChanged) self.parameterNodeSelector.connect('currentNodeChanged(vtkMRMLNode*)', self.onNodeSelectionChanged) self.parameterNodeSelector.connect('currentNodeChanged(vtkMRMLNode*)', self.onParameterSetSelected) self.parameterNodeSelector.setCurrentNode( self.logic.getParameterNode()) self.onNodeSelectionChanged() self.onParameterSetSelected()
def test_SegmentStatisticsBasic(self): """ This tests some aspects of the label statistics """ self.delayDisplay("Starting test_SegmentStatisticsBasic") import vtkSegmentationCorePython as vtkSegmentationCore import SampleData from SegmentStatistics import SegmentStatisticsLogic self.delayDisplay("Load master volume") masterVolumeNode = SampleData.downloadSample('MRBrainTumor1') self.delayDisplay("Create segmentation containing a few spheres") segmentationNode = slicer.mrmlScene.AddNewNodeByClass( 'vtkMRMLSegmentationNode') segmentationNode.CreateDefaultDisplayNodes() segmentationNode.SetReferenceImageGeometryParameterFromVolumeNode( masterVolumeNode) # Geometry for each segment is defined by: radius, posX, posY, posZ segmentGeometries = [[10, -6, 30, 28], [20, 0, 65, 32], [15, 1, -14, 30], [12, 0, 28, -7], [5, 0, 30, 64], [12, 31, 33, 27], [17, -42, 30, 27]] for segmentGeometry in segmentGeometries: sphereSource = vtk.vtkSphereSource() sphereSource.SetRadius(segmentGeometry[0]) sphereSource.SetCenter(segmentGeometry[1], segmentGeometry[2], segmentGeometry[3]) sphereSource.Update() uniqueSegmentID = segmentationNode.GetSegmentation( ).GenerateUniqueSegmentID("Test") segmentationNode.AddSegmentFromClosedSurfaceRepresentation( sphereSource.GetOutput(), uniqueSegmentID) self.delayDisplay("Compute statistics") segStatLogic = SegmentStatisticsLogic() segStatLogic.getParameterNode().SetParameter("Segmentation", segmentationNode.GetID()) segStatLogic.getParameterNode().SetParameter("ScalarVolume", masterVolumeNode.GetID()) segStatLogic.computeStatistics() self.delayDisplay("Check a few numerical results") self.assertEqual( segStatLogic.getStatistics()[ "Test_2", "LabelmapSegmentStatisticsPlugin.voxel_count"], 9807) self.assertEqual( segStatLogic.getStatistics() ["Test_4", "ScalarVolumeSegmentStatisticsPlugin.voxel_count"], 380) self.delayDisplay("Export results to table") resultsTableNode = slicer.vtkMRMLTableNode() slicer.mrmlScene.AddNode(resultsTableNode) segStatLogic.exportToTable(resultsTableNode) segStatLogic.showTable(resultsTableNode) self.delayDisplay("Export results to string") logging.info(segStatLogic.exportToString()) outputFilename = slicer.app.temporaryPath + '/SegmentStatisticsTestOutput.csv' self.delayDisplay("Export results to CSV file: " + outputFilename) segStatLogic.exportToCSVFile(outputFilename) self.delayDisplay('test_SegmentStatisticsBasic passed!')
class SegmentStatisticsParameterEditorDialog(qt.QDialog): """Dialog to edit parameters of segment statistics plugins. Most users will only need to call the static method editParameters(...) """ @staticmethod def editParameters(parameterNode, pluginName=None): """Executes a modal dialog to edit a segment statistics parameter node if a pluginName is specified, only options for this plugin are displayed" """ dialog = SegmentStatisticsParameterEditorDialog( parent=None, parameterNode=parameterNode, pluginName=pluginName) return dialog.exec_() def __init__(self, parent=None, parameterNode=None, pluginName=None): super(qt.QDialog, self).__init__(parent) self.title = "Edit Segment Statistics Parameters" self.parameterNode = parameterNode self.pluginName = pluginName self.logic = SegmentStatisticsLogic( ) # for access to plugins and editor widgets self.logic.setParameterNode(self.parameterNode) self.setup() def setParameterNode(self, parameterNode): """Set the parameter node the dialog will operate on""" if parameterNode == self.parameterNode: return self.parameterNode = parameterNode self.logic.setParameterNode(self.parameterNode) def setup(self): self.setLayout(qt.QVBoxLayout()) self.descriptionLabel = qt.QLabel( "Edit segment statistics plugin parameters:", 0) self.doneButton = qt.QPushButton("Done") self.doneButton.toolTip = "Finish editing." doneWidget = qt.QWidget(self) doneWidget.setLayout(qt.QHBoxLayout()) doneWidget.layout().addStretch(1) doneWidget.layout().addWidget(self.doneButton, 0) parametersScrollArea = qt.QScrollArea(self) self.parametersWidget = qt.QWidget(parametersScrollArea) self.parametersLayout = qt.QFormLayout(self.parametersWidget) self._addPluginOptionWidgets() parametersScrollArea.setWidget(self.parametersWidget) parametersScrollArea.widgetResizable = True parametersScrollArea.setVerticalScrollBarPolicy( qt.Qt.ScrollBarAsNeeded) parametersScrollArea.setHorizontalScrollBarPolicy( qt.Qt.ScrollBarAsNeeded) self.layout().addWidget(self.descriptionLabel, 0) self.layout().addWidget(parametersScrollArea, 1) self.layout().addWidget(doneWidget, 0) self.doneButton.connect('clicked()', lambda: self.done(1)) def _addPluginOptionWidgets(self): description = "Edit segment statistics plugin parameters:" if self.pluginName: description = "Edit " + self.pluginName + " plugin parameters:" self.descriptionLabel.text = description if self.pluginName: for plugin in self.logic.plugins: if plugin.name == self.pluginName: self.parametersLayout.addRow(plugin.optionsWidget) else: for plugin in self.logic.plugins: pluginOptionsCollapsibleButton = ctk.ctkCollapsibleGroupBox( self.parametersWidget) pluginOptionsCollapsibleButton.setTitle(plugin.name) pluginOptionsFormLayout = qt.QFormLayout( pluginOptionsCollapsibleButton) pluginOptionsFormLayout.addRow(plugin.optionsWidget) self.parametersLayout.addRow(pluginOptionsCollapsibleButton)
class SegmentStatisticsWidget(ScriptedLoadableModuleWidget): """Uses ScriptedLoadableModuleWidget base class, available at: https://github.com/Slicer/Slicer/blob/master/Base/Python/slicer/ScriptedLoadableModule.py """ def setup(self): ScriptedLoadableModuleWidget.setup(self) self.logic = SegmentStatisticsLogic() self.grayscaleNode = None self.labelNode = None self.parameterNode = None self.parameterNodeObserver = None # Instantiate and connect widgets ... # # Parameter set selector self.parameterNodeSelector = slicer.qMRMLNodeComboBox() self.parameterNodeSelector.nodeTypes = ["vtkMRMLScriptedModuleNode"] self.parameterNodeSelector.addAttribute("vtkMRMLScriptedModuleNode", "ModuleName", "SegmentStatistics") self.parameterNodeSelector.selectNodeUponCreation = True self.parameterNodeSelector.addEnabled = True self.parameterNodeSelector.renameEnabled = True self.parameterNodeSelector.removeEnabled = True self.parameterNodeSelector.noneEnabled = False self.parameterNodeSelector.showHidden = True self.parameterNodeSelector.showChildNodeTypes = False self.parameterNodeSelector.baseName = "SegmentStatistics" self.parameterNodeSelector.setMRMLScene(slicer.mrmlScene) self.parameterNodeSelector.setToolTip("Pick parameter set") self.layout.addWidget(self.parameterNodeSelector) # Inputs inputsCollapsibleButton = ctk.ctkCollapsibleButton() inputsCollapsibleButton.text = "Inputs" self.layout.addWidget(inputsCollapsibleButton) inputsFormLayout = qt.QFormLayout(inputsCollapsibleButton) # Segmentation selector self.segmentationSelector = slicer.qMRMLNodeComboBox() self.segmentationSelector.nodeTypes = ["vtkMRMLSegmentationNode"] self.segmentationSelector.addEnabled = False self.segmentationSelector.removeEnabled = True self.segmentationSelector.renameEnabled = True self.segmentationSelector.setMRMLScene(slicer.mrmlScene) self.segmentationSelector.setToolTip( "Pick the segmentation to compute statistics for") inputsFormLayout.addRow("Segmentation:", self.segmentationSelector) # Scalar volume selector self.scalarSelector = slicer.qMRMLNodeComboBox() self.scalarSelector.nodeTypes = ["vtkMRMLScalarVolumeNode"] self.scalarSelector.addEnabled = False self.scalarSelector.removeEnabled = True self.scalarSelector.renameEnabled = True self.scalarSelector.noneEnabled = True self.scalarSelector.showChildNodeTypes = False self.scalarSelector.setMRMLScene(slicer.mrmlScene) self.scalarSelector.setToolTip( "Select the scalar volume for intensity statistics calculations") inputsFormLayout.addRow("Scalar volume:", self.scalarSelector) # Output table selector outputCollapsibleButton = ctk.ctkCollapsibleButton() outputCollapsibleButton.text = "Output" self.layout.addWidget(outputCollapsibleButton) outputFormLayout = qt.QFormLayout(outputCollapsibleButton) self.outputTableSelector = slicer.qMRMLNodeComboBox() self.outputTableSelector.noneDisplay = "Create new table" self.outputTableSelector.setMRMLScene(slicer.mrmlScene) self.outputTableSelector.nodeTypes = ["vtkMRMLTableNode"] self.outputTableSelector.addEnabled = True self.outputTableSelector.selectNodeUponCreation = True self.outputTableSelector.renameEnabled = True self.outputTableSelector.removeEnabled = True self.outputTableSelector.noneEnabled = True self.outputTableSelector.setToolTip( "Select the table where statistics will be saved into") self.outputTableSelector.setCurrentNode(None) outputFormLayout.addRow("Output table:", self.outputTableSelector) # Parameter set parametersCollapsibleButton = ctk.ctkCollapsibleButton() parametersCollapsibleButton.text = "Advanced" parametersCollapsibleButton.collapsed = True self.layout.addWidget(parametersCollapsibleButton) self.parametersLayout = qt.QFormLayout(parametersCollapsibleButton) # Edit parameter set button to open SegmentStatisticsParameterEditorDialog # Note: we add the plugins' option widgets to the module widget instead of using the editor dialog #self.editParametersButton = qt.QPushButton("Edit Parameter Set") #self.editParametersButton.toolTip = "Editor Statistics Plugin Parameter Set." #self.parametersLayout.addRow(self.editParametersButton) #self.editParametersButton.connect('clicked()', self.onEditParameters) # add caclulator's option widgets self.addPluginOptionWidgets() # Apply Button self.applyButton = qt.QPushButton("Apply") self.applyButton.toolTip = "Calculate Statistics." self.applyButton.enabled = False self.parent.layout().addWidget(self.applyButton) # Add vertical spacer self.parent.layout().addStretch(1) # connections self.applyButton.connect('clicked()', self.onApply) self.scalarSelector.connect('currentNodeChanged(vtkMRMLNode*)', self.onNodeSelectionChanged) self.segmentationSelector.connect('currentNodeChanged(vtkMRMLNode*)', self.onNodeSelectionChanged) self.outputTableSelector.connect('currentNodeChanged(vtkMRMLNode*)', self.onNodeSelectionChanged) self.parameterNodeSelector.connect('currentNodeChanged(vtkMRMLNode*)', self.onNodeSelectionChanged) self.parameterNodeSelector.connect('currentNodeChanged(vtkMRMLNode*)', self.onParameterSetSelected) self.parameterNodeSelector.setCurrentNode( self.logic.getParameterNode()) self.onNodeSelectionChanged() self.onParameterSetSelected() def enter(self): """Runs whenever the module is reopened """ if self.parameterNodeSelector.currentNode() is None: parameterNode = self.logic.getParameterNode() slicer.mrmlScene.AddNode(parameterNode) self.parameterNodeSelector.setCurrentNode(parameterNode) if self.segmentationSelector.currentNode() is None: segmentationNode = slicer.mrmlScene.GetFirstNodeByClass( "vtkMRMLSegmentationNode") self.segmentationSelector.setCurrentNode(segmentationNode) def cleanup(self): if self.parameterNode and self.parameterNodeObserver: self.parameterNode.RemoveObserver(self.parameterNodeObserver) def onNodeSelectionChanged(self): self.applyButton.enabled = ( self.segmentationSelector.currentNode() is not None and self.parameterNodeSelector.currentNode() is not None) if self.segmentationSelector.currentNode(): self.outputTableSelector.baseName = self.segmentationSelector.currentNode( ).GetName() + ' statistics' def onApply(self): """Calculate the label statistics """ if not self.outputTableSelector.currentNode(): newTable = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLTableNode") self.outputTableSelector.setCurrentNode(newTable) # Lock GUI self.applyButton.text = "Working..." self.applyButton.setEnabled(False) slicer.app.processEvents() # set up parameters for computation self.logic.getParameterNode().SetParameter( "Segmentation", self.segmentationSelector.currentNode().GetID()) if self.scalarSelector.currentNode(): self.logic.getParameterNode().SetParameter( "ScalarVolume", self.scalarSelector.currentNode().GetID()) else: self.logic.getParameterNode().UnsetParameter("ScalarVolume") self.logic.getParameterNode().SetParameter( "MeasurementsTable", self.outputTableSelector.currentNode().GetID()) # Compute statistics self.logic.computeStatistics() self.logic.exportToTable(self.outputTableSelector.currentNode()) # Unlock GUI self.applyButton.setEnabled(True) self.applyButton.text = "Apply" self.logic.showTable(self.outputTableSelector.currentNode()) def onEditParameters(self, pluginName=None): """Open dialog box to edit plugin's parameters""" if self.parameterNodeSelector.currentNode(): SegmentStatisticsParameterEditorDialog.editParameters( self.parameterNodeSelector.currentNode(), pluginName) def addPluginOptionWidgets(self): self.pluginEnabledCheckboxes = {} self.parametersLayout.addRow( qt.QLabel("Enabled segment statistics plugins:")) for plugin in self.logic.plugins: checkbox = qt.QCheckBox(plugin.name + " Statistics") checkbox.checked = True checkbox.connect('stateChanged(int)', self.updateParameterNodeFromGui) optionButton = qt.QPushButton("Options") from functools import partial optionButton.connect('clicked()', partial(self.onEditParameters, plugin.name)) editWidget = qt.QWidget() editWidget.setLayout(qt.QHBoxLayout()) editWidget.layout().margin = 0 editWidget.layout().addWidget(checkbox, 0) editWidget.layout().addStretch(1) editWidget.layout().addWidget(optionButton, 0) self.pluginEnabledCheckboxes[plugin.name] = checkbox self.parametersLayout.addRow(editWidget) # embed widgets for editing plugin' parameters #for plugin in self.logic.plugins: # pluginOptionsCollapsibleButton = ctk.ctkCollapsibleGroupBox() # pluginOptionsCollapsibleButton.setTitle( plugin.name ) # pluginOptionsFormLayout = qt.QFormLayout(pluginOptionsCollapsibleButton) # pluginOptionsFormLayout.addRow(plugin.optionsWidget) # self.parametersLayout.addRow(pluginOptionsCollapsibleButton) def onParameterSetSelected(self): if self.parameterNode and self.parameterNodeObserver: self.parameterNode.RemoveObserver(self.parameterNodeObserver) self.parameterNode = self.parameterNodeSelector.currentNode() if self.parameterNode: self.logic.setParameterNode(self.parameterNode) self.parameterNodeObserver = self.parameterNode.AddObserver( vtk.vtkCommand.ModifiedEvent, self.updateGuiFromParameterNode) self.updateGuiFromParameterNode() def updateGuiFromParameterNode(self, caller=None, event=None): if not self.parameterNode: return for plugin in self.logic.plugins: pluginName = plugin.__class__.__name__ parameter = pluginName + '.enabled' checkbox = self.pluginEnabledCheckboxes[plugin.name] value = self.parameterNode.GetParameter(parameter) == 'True' if checkbox.checked != value: previousState = checkbox.blockSignals(True) checkbox.checked = value checkbox.blockSignals(previousState) def updateParameterNodeFromGui(self): if not self.parameterNode: return for plugin in self.logic.plugins: pluginName = plugin.__class__.__name__ parameter = pluginName + '.enabled' checkbox = self.pluginEnabledCheckboxes[plugin.name] self.parameterNode.SetParameter(parameter, str(checkbox.checked))
def setup(self): ScriptedLoadableModuleWidget.setup(self) self.logic = SegmentStatisticsLogic() self.grayscaleNode = None self.labelNode = None self.parameterNode = None self.parameterNodeObserver = None # Instantiate and connect widgets ... # # Parameter set selector self.parameterNodeSelector = slicer.qMRMLNodeComboBox() self.parameterNodeSelector.nodeTypes = ["vtkMRMLScriptedModuleNode"] self.parameterNodeSelector.addAttribute( "vtkMRMLScriptedModuleNode", "ModuleName", "SegmentStatistics" ) self.parameterNodeSelector.selectNodeUponCreation = True self.parameterNodeSelector.addEnabled = True self.parameterNodeSelector.renameEnabled = True self.parameterNodeSelector.removeEnabled = True self.parameterNodeSelector.noneEnabled = False self.parameterNodeSelector.showHidden = True self.parameterNodeSelector.showChildNodeTypes = False self.parameterNodeSelector.baseName = "SegmentStatistics" self.parameterNodeSelector.setMRMLScene( slicer.mrmlScene ) self.parameterNodeSelector.setToolTip( "Pick parameter set" ) self.layout.addWidget(self.parameterNodeSelector) # Inputs inputsCollapsibleButton = ctk.ctkCollapsibleButton() inputsCollapsibleButton.text = "Inputs" self.layout.addWidget(inputsCollapsibleButton) inputsFormLayout = qt.QFormLayout(inputsCollapsibleButton) # Segmentation selector self.segmentationSelector = slicer.qMRMLNodeComboBox() self.segmentationSelector.nodeTypes = ["vtkMRMLSegmentationNode"] self.segmentationSelector.addEnabled = False self.segmentationSelector.removeEnabled = True self.segmentationSelector.renameEnabled = True self.segmentationSelector.setMRMLScene( slicer.mrmlScene ) self.segmentationSelector.setToolTip( "Pick the segmentation to compute statistics for" ) inputsFormLayout.addRow("Segmentation:", self.segmentationSelector) # Scalar volume selector self.scalarSelector = slicer.qMRMLNodeComboBox() self.scalarSelector.nodeTypes = ["vtkMRMLScalarVolumeNode"] self.scalarSelector.addEnabled = False self.scalarSelector.removeEnabled = True self.scalarSelector.renameEnabled = True self.scalarSelector.noneEnabled = True self.scalarSelector.showChildNodeTypes = False self.scalarSelector.setMRMLScene( slicer.mrmlScene ) self.scalarSelector.setToolTip( "Select the scalar volume for intensity statistics calculations") inputsFormLayout.addRow("Scalar volume:", self.scalarSelector) # Output table selector outputCollapsibleButton = ctk.ctkCollapsibleButton() outputCollapsibleButton.text = "Output" self.layout.addWidget(outputCollapsibleButton) outputFormLayout = qt.QFormLayout(outputCollapsibleButton) self.outputTableSelector = slicer.qMRMLNodeComboBox() self.outputTableSelector.noneDisplay = "Create new table" self.outputTableSelector.setMRMLScene(slicer.mrmlScene) self.outputTableSelector.nodeTypes = ["vtkMRMLTableNode"] self.outputTableSelector.addEnabled = True self.outputTableSelector.selectNodeUponCreation = True self.outputTableSelector.renameEnabled = True self.outputTableSelector.removeEnabled = True self.outputTableSelector.noneEnabled = True self.outputTableSelector.setToolTip("Select the table where statistics will be saved into") self.outputTableSelector.setCurrentNode(None) outputFormLayout.addRow("Output table:", self.outputTableSelector) # Parameter set parametersCollapsibleButton = ctk.ctkCollapsibleButton() parametersCollapsibleButton.text = "Advanced" parametersCollapsibleButton.collapsed = True self.layout.addWidget(parametersCollapsibleButton) self.parametersLayout = qt.QFormLayout(parametersCollapsibleButton) # Edit parameter set button to open SegmentStatisticsParameterEditorDialog # Note: we add the plugins' option widgets to the module widget instead of using the editor dialog #self.editParametersButton = qt.QPushButton("Edit Parameter Set") #self.editParametersButton.toolTip = "Editor Statistics Plugin Parameter Set." #self.parametersLayout.addRow(self.editParametersButton) #self.editParametersButton.connect('clicked()', self.onEditParameters) # add caclulator's option widgets self.addPluginOptionWidgets() # Apply Button self.applyButton = qt.QPushButton("Apply") self.applyButton.toolTip = "Calculate Statistics." self.applyButton.enabled = False self.parent.layout().addWidget(self.applyButton) # Add vertical spacer self.parent.layout().addStretch(1) # connections self.applyButton.connect('clicked()', self.onApply) self.scalarSelector.connect('currentNodeChanged(vtkMRMLNode*)', self.onNodeSelectionChanged) self.segmentationSelector.connect('currentNodeChanged(vtkMRMLNode*)', self.onNodeSelectionChanged) self.outputTableSelector.connect('currentNodeChanged(vtkMRMLNode*)', self.onNodeSelectionChanged) self.parameterNodeSelector.connect('currentNodeChanged(vtkMRMLNode*)', self.onNodeSelectionChanged) self.parameterNodeSelector.connect('currentNodeChanged(vtkMRMLNode*)', self.onParameterSetSelected) self.parameterNodeSelector.setCurrentNode(self.logic.getParameterNode()) self.onNodeSelectionChanged() self.onParameterSetSelected()
def test_SegmentStatisticsPlugins(self): """ This tests some aspects of the segment statistics plugins """ self.delayDisplay("Starting test_SegmentStatisticsPlugins") import vtkSegmentationCorePython as vtkSegmentationCore import SampleData from SegmentStatistics import SegmentStatisticsLogic self.delayDisplay("Load master volume") masterVolumeNode = SampleData.downloadSample('MRBrainTumor1') self.delayDisplay("Create segmentation containing a few spheres") segmentationNode = slicer.mrmlScene.AddNewNodeByClass('vtkMRMLSegmentationNode') segmentationNode.CreateDefaultDisplayNodes() segmentationNode.SetReferenceImageGeometryParameterFromVolumeNode(masterVolumeNode) # Geometry for each segment is defined by: radius, posX, posY, posZ segmentGeometries = [[10, -6,30,28], [20, 0,65,32], [15, 1, -14, 30], [12, 0, 28, -7], [5, 0,30,64], [12, 31, 33, 27], [17, -42, 30, 27]] for segmentGeometry in segmentGeometries: sphereSource = vtk.vtkSphereSource() sphereSource.SetRadius(segmentGeometry[0]) sphereSource.SetCenter(segmentGeometry[1], segmentGeometry[2], segmentGeometry[3]) sphereSource.Update() segment = vtkSegmentationCore.vtkSegment() uniqueSegmentID = segmentationNode.GetSegmentation().GenerateUniqueSegmentID("Test") segmentationNode.AddSegmentFromClosedSurfaceRepresentation(sphereSource.GetOutput(), uniqueSegmentID) # test calculating only measurements for selected segments self.delayDisplay("Test calculating only measurements for individual segments") segStatLogic = SegmentStatisticsLogic() segStatLogic.getParameterNode().SetParameter("Segmentation", segmentationNode.GetID()) segStatLogic.getParameterNode().SetParameter("ScalarVolume", masterVolumeNode.GetID()) segStatLogic.updateStatisticsForSegment('Test_2') resultsTableNode = slicer.vtkMRMLTableNode() slicer.mrmlScene.AddNode(resultsTableNode) segStatLogic.exportToTable(resultsTableNode) segStatLogic.showTable(resultsTableNode) self.assertEqual( segStatLogic.getStatistics()["Test_2","LabelmapSegmentStatisticsPlugin.voxel_count"], 9807) with self.assertRaises(KeyError): segStatLogic.getStatistics()["Test_4","ScalarVolumeSegmentStatisticsPlugin.voxel count"] # assert there are no result for this segment segStatLogic.updateStatisticsForSegment('Test_4') segStatLogic.exportToTable(resultsTableNode) segStatLogic.showTable(resultsTableNode) self.assertEqual( segStatLogic.getStatistics()["Test_2","LabelmapSegmentStatisticsPlugin.voxel_count"], 9807) self.assertEqual( segStatLogic.getStatistics()["Test_4","LabelmapSegmentStatisticsPlugin.voxel_count"], 380) with self.assertRaises(KeyError): segStatLogic.getStatistics()["Test_5","ScalarVolumeSegmentStatisticsPlugin.voxel count"] # assert there are no result for this segment # calculate measurements for all segments segStatLogic.computeStatistics() self.assertEqual( segStatLogic.getStatistics()["Test","LabelmapSegmentStatisticsPlugin.voxel_count"], 2948) self.assertEqual( segStatLogic.getStatistics()["Test_1","LabelmapSegmentStatisticsPlugin.voxel_count"], 23281) # test updating measurements for segments one by one self.delayDisplay("Update some segments in the segmentation") segmentGeometriesNew = [[5, -6,30,28], [21, 0,65,32]] # We add/remove representations, so we temporarily block segment modifications # to make sure display managers don't try to access data while it is in an # inconsistent state. wasModified = segmentationNode.StartModify() for i in range(len(segmentGeometriesNew)): segmentGeometry = segmentGeometriesNew[i] sphereSource = vtk.vtkSphereSource() sphereSource.SetRadius(segmentGeometry[0]) sphereSource.SetCenter(segmentGeometry[1], segmentGeometry[2], segmentGeometry[3]) sphereSource.Update() segment = segmentationNode.GetSegmentation().GetNthSegment(i) segment.RemoveAllRepresentations() closedSurfaceName = vtkSegmentationCore.vtkSegmentationConverter.GetSegmentationClosedSurfaceRepresentationName() segment.AddRepresentation(closedSurfaceName, sphereSource.GetOutput()) segmentationNode.EndModify(wasModified) self.assertEqual( segStatLogic.getStatistics()["Test","LabelmapSegmentStatisticsPlugin.voxel_count"], 2948) self.assertEqual( segStatLogic.getStatistics()["Test_1","LabelmapSegmentStatisticsPlugin.voxel_count"], 23281) segStatLogic.updateStatisticsForSegment('Test_1') self.assertEqual( segStatLogic.getStatistics()["Test","LabelmapSegmentStatisticsPlugin.voxel_count"], 2948) self.assertTrue( segStatLogic.getStatistics()["Test_1","LabelmapSegmentStatisticsPlugin.voxel_count"]!=23281) segStatLogic.updateStatisticsForSegment('Test') self.assertTrue( segStatLogic.getStatistics()["Test","LabelmapSegmentStatisticsPlugin.voxel_count"]!=2948) self.assertTrue( segStatLogic.getStatistics()["Test_1","LabelmapSegmentStatisticsPlugin.voxel_count"]!=23281) # test enabling/disabling of individual measurements self.delayDisplay("Test disabling of individual measurements") segStatLogic = SegmentStatisticsLogic() segStatLogic.getParameterNode().SetParameter("Segmentation", segmentationNode.GetID()) segStatLogic.getParameterNode().SetParameter("ScalarVolume", masterVolumeNode.GetID()) segStatLogic.getParameterNode().SetParameter("LabelmapSegmentStatisticsPlugin.voxel_count.enabled",str(False)) segStatLogic.getParameterNode().SetParameter("LabelmapSegmentStatisticsPlugin.volume_cm3.enabled",str(False)) segStatLogic.computeStatistics() segStatLogic.exportToTable(resultsTableNode) segStatLogic.showTable(resultsTableNode) columnHeaders = [resultsTableNode.GetColumnName(i) for i in range(resultsTableNode.GetNumberOfColumns())] self.assertFalse('Number of voxels [voxels] (1)' in columnHeaders) self.assertTrue('Volume [mm3] (1)' in columnHeaders) self.assertFalse('Volume [cm3] (3)' in columnHeaders) self.delayDisplay("Test re-enabling of individual measurements") segStatLogic.getParameterNode().SetParameter("LabelmapSegmentStatisticsPlugin.voxel_count.enabled",str(True)) segStatLogic.getParameterNode().SetParameter("LabelmapSegmentStatisticsPlugin.volume_cm3.enabled",str(True)) segStatLogic.computeStatistics() segStatLogic.exportToTable(resultsTableNode) segStatLogic.showTable(resultsTableNode) columnHeaders = [resultsTableNode.GetColumnName(i) for i in range(resultsTableNode.GetNumberOfColumns())] self.assertTrue('Number of voxels [voxels] (1)' in columnHeaders) self.assertTrue('Volume [mm3] (1)' in columnHeaders) self.assertTrue('Volume [cm3] (1)' in columnHeaders) # test enabling/disabling of individual plugins self.delayDisplay("Test disabling of plugin") segStatLogic.getParameterNode().SetParameter("LabelmapSegmentStatisticsPlugin.enabled",str(False)) segStatLogic.computeStatistics() segStatLogic.exportToTable(resultsTableNode) segStatLogic.showTable(resultsTableNode) columnHeaders = [resultsTableNode.GetColumnName(i) for i in range(resultsTableNode.GetNumberOfColumns())] self.assertFalse('Number of voxels [voxels] (3)' in columnHeaders) self.assertFalse('Volume [mm3] (3)' in columnHeaders) self.assertTrue('Volume [mm3] (2)' in columnHeaders) self.delayDisplay("Test re-enabling of plugin") segStatLogic.getParameterNode().SetParameter("LabelmapSegmentStatisticsPlugin.enabled",str(True)) segStatLogic.computeStatistics() segStatLogic.exportToTable(resultsTableNode) segStatLogic.showTable(resultsTableNode) columnHeaders = [resultsTableNode.GetColumnName(i) for i in range(resultsTableNode.GetNumberOfColumns())] self.assertTrue('Number of voxels [voxels] (2)' in columnHeaders) self.assertTrue('Volume [mm3] (3)' in columnHeaders) # test unregistering/registering of plugins self.delayDisplay("Test of removing all registered plugins") SegmentStatisticsLogic.registeredPlugins = [] # remove all registered plugins segStatLogic = SegmentStatisticsLogic() segStatLogic.getParameterNode().SetParameter("Segmentation", segmentationNode.GetID()) segStatLogic.getParameterNode().SetParameter("ScalarVolume", masterVolumeNode.GetID()) segStatLogic.computeStatistics() segStatLogic.exportToTable(resultsTableNode) segStatLogic.showTable(resultsTableNode) columnHeaders = [resultsTableNode.GetColumnName(i) for i in range(resultsTableNode.GetNumberOfColumns())] self.assertEqual(len(columnHeaders),1) # only header element should be "Segment" self.assertEqual(columnHeaders[0],"Segment") # only header element should be "Segment" self.delayDisplay("Test registering plugins") SegmentStatisticsLogic.registerPlugin(LabelmapSegmentStatisticsPlugin()) SegmentStatisticsLogic.registerPlugin(ScalarVolumeSegmentStatisticsPlugin()) SegmentStatisticsLogic.registerPlugin(ClosedSurfaceSegmentStatisticsPlugin()) segStatLogic = SegmentStatisticsLogic() segStatLogic.getParameterNode().SetParameter("Segmentation", segmentationNode.GetID()) segStatLogic.getParameterNode().SetParameter("ScalarVolume", masterVolumeNode.GetID()) segStatLogic.computeStatistics() segStatLogic.exportToTable(resultsTableNode) segStatLogic.showTable(resultsTableNode) columnHeaders = [resultsTableNode.GetColumnName(i) for i in range(resultsTableNode.GetNumberOfColumns())] self.assertTrue('Number of voxels [voxels] (1)' in columnHeaders) self.assertTrue('Number of voxels [voxels] (2)' in columnHeaders) self.assertTrue('Surface area [mm2]' in columnHeaders) self.delayDisplay('test_SegmentStatisticsPlugins passed!')
def setup(self): ScriptedLoadableModuleWidget.setup(self) self.logic = SegmentStatisticsLogic() self.grayscaleNode = None self.labelNode = None self.fileName = None self.fileDialog = None # Instantiate and connect widgets ... # # Inputs inputsCollapsibleButton = ctk.ctkCollapsibleButton() inputsCollapsibleButton.text = "Inputs" self.layout.addWidget(inputsCollapsibleButton) inputsFormLayout = qt.QFormLayout(inputsCollapsibleButton) # Segmentation selector self.segmentationSelector = slicer.qMRMLNodeComboBox() self.segmentationSelector.nodeTypes = ["vtkMRMLSegmentationNode"] self.segmentationSelector.addEnabled = False self.segmentationSelector.removeEnabled = True self.segmentationSelector.renameEnabled = True self.segmentationSelector.setMRMLScene( slicer.mrmlScene ) self.segmentationSelector.setToolTip( "Pick the segmentation to compute statistics for" ) inputsFormLayout.addRow("Segmentation:", self.segmentationSelector) # Grayscale volume selector self.grayscaleSelector = slicer.qMRMLNodeComboBox() self.grayscaleSelector.nodeTypes = ["vtkMRMLScalarVolumeNode"] self.grayscaleSelector.addEnabled = False self.grayscaleSelector.removeEnabled = True self.grayscaleSelector.renameEnabled = True self.grayscaleSelector.noneEnabled = True self.grayscaleSelector.showChildNodeTypes = False self.grayscaleSelector.setMRMLScene( slicer.mrmlScene ) self.grayscaleSelector.setToolTip( "Select the grayscale volume for intensity statistics calculations") inputsFormLayout.addRow("Grayscale volume:", self.grayscaleSelector) # Output table selector outputCollapsibleButton = ctk.ctkCollapsibleButton() outputCollapsibleButton.text = "Output" self.layout.addWidget(outputCollapsibleButton) outputFormLayout = qt.QFormLayout(outputCollapsibleButton) self.outputTableSelector = slicer.qMRMLNodeComboBox() self.outputTableSelector.nodeTypes = ["vtkMRMLTableNode"] self.outputTableSelector.addEnabled = True self.outputTableSelector.selectNodeUponCreation = True self.outputTableSelector.renameEnabled = True self.outputTableSelector.removeEnabled = True self.outputTableSelector.noneEnabled = False self.outputTableSelector.setMRMLScene( slicer.mrmlScene ) self.outputTableSelector.setToolTip( "Select the table where statistics will be saved into") outputFormLayout.addRow("Output table:", self.outputTableSelector) # Apply Button self.applyButton = qt.QPushButton("Apply") self.applyButton.toolTip = "Calculate Statistics." self.applyButton.enabled = False self.parent.layout().addWidget(self.applyButton) # Add vertical spacer self.parent.layout().addStretch(1) # connections self.applyButton.connect('clicked()', self.onApply) self.grayscaleSelector.connect('currentNodeChanged(vtkMRMLNode*)', self.onNodeSelectionChanged) self.segmentationSelector.connect('currentNodeChanged(vtkMRMLNode*)', self.onNodeSelectionChanged) self.outputTableSelector.connect('currentNodeChanged(vtkMRMLNode*)', self.onNodeSelectionChanged) self.onNodeSelectionChanged()
def test_SurfaceCut1(self): """ Basic automated test of the segmentation method: - Create segmentation by placing fiducials around tumor - Apply - Verify results using segment statistics The test can be executed from SelfTests module (test name: SegmentEditorSurfaceCut) """ self.delayDisplay("Starting test_SurfaceCut1") ################################## self.delayDisplay("Load master volume") import SampleData sampleDataLogic = SampleData.SampleDataLogic() masterVolumeNode = sampleDataLogic.downloadMRBrainTumor1() ################################## self.delayDisplay("Create tumor segmentation") segmentationNode = slicer.vtkMRMLSegmentationNode() slicer.mrmlScene.AddNode(segmentationNode) segmentationNode.CreateDefaultDisplayNodes() segmentationNode.SetReferenceImageGeometryParameterFromVolumeNode(masterVolumeNode) segmentName = "Tumor" import vtkSegmentationCorePython as vtkSegmentationCore segment = vtkSegmentationCore.vtkSegment() segment.SetName(segmentationNode.GetSegmentation().GenerateUniqueSegmentID(segmentName)) segmentationNode.GetSegmentation().AddSegment(segment) ################################## self.delayDisplay("Create segment editor") segmentEditorWidget = slicer.qMRMLSegmentEditorWidget() segmentEditorWidget.show() segmentEditorWidget.setMRMLScene(slicer.mrmlScene) segmentEditorNode = slicer.vtkMRMLSegmentEditorNode() slicer.mrmlScene.AddNode(segmentEditorNode) segmentEditorWidget.setMRMLSegmentEditorNode(segmentEditorNode) segmentEditorWidget.setSegmentationNode(segmentationNode) segmentEditorWidget.setMasterVolumeNode(masterVolumeNode) ################################## self.delayDisplay("Run segmentation") segmentEditorWidget.setActiveEffectByName("Surface cut") effect = segmentEditorWidget.activeEffect() effect.self().fiducialPlacementToggle.placeButton().click() points =[[2.589283578714074, 44.60536690073953, 27.299999999999997], [8.515228351086698, 35.22262101114956, 27.299999999999997], [13.700430026912741, 25.099132025013006, 27.299999999999997], [5.799170330415919, 19.17318725264039, 27.299999999999997], [2.589283578714074, 9.296612632019361, 27.299999999999997], [-10.250263428093263, 12.25958501820567, 27.299999999999997], [-16.17620820046588, 18.185529790578286, 27.299999999999997], [-20.373752414229813, 27.568275680168263, 27.299999999999997], [-15.929293834950343, 38.679422128366916, 27.299999999999997], [-11.484835255670887, 44.11153816970849, 27.299999999999997], [6.539913426962492, 33.49422045254088, 31.499999999999993], [1.354711751136449, 42.383137611099805, 31.499999999999993], [-8.768777235000101, 44.35845253522401, 31.499999999999993], [-14.200893276341674, 36.70410720424271, 31.499999999999993], [-18.398437490105607, 27.07444694913721, 31.499999999999993], [-12.719407083248512, 16.704043597485132, 31.499999999999993], [-7.534205407422476, 11.765756287174618, 31.499999999999993], [0.12013992355882408, 12.25958501820567, 31.499999999999993], [5.799170330415919, 16.21021486645408, 31.499999999999993], [8.268313985571176, 21.642330907795646, 31.499999999999993], [13.947344392428263, 26.827532583621682, 31.499999999999993], [-3.0897468281430065, 32.50656299047878, 45.49999999999998], [2.589283578714074, 27.32136131465274, 45.49999999999998], [-5.3119761177827485, 21.642330907795646, 45.49999999999998], [-8.02803413845352, 27.32136131465274, 45.49999999999998], [-14.694722007372718, 30.778162431870093, 38.499999999999986], [-8.02803413845352, 12.01267065269014, 38.499999999999986], [-3.583575559174065, 39.66707959042902, 11.900000000000007], [3.576941040776184, 31.765819893932196, 11.900000000000007], [0.12013992355882408, 20.901587811249065, 11.900000000000007], [-9.26260596603116, 28.555933142230366, 11.900000000000007], [6.046084695931441, 38.432507762851394, 17.500000000000007], [-17.163865662527982, 33.7411348180564, 17.500000000000007], [-14.200893276341674, 21.889245273311168, 17.500000000000007]] for p in points: effect.self().segmentMarkupNode.AddFiducialFromArray(p) effect.self().onApply() ################################## self.delayDisplay("Make segmentation results nicely visible in 3D") segmentationDisplayNode = segmentationNode.GetDisplayNode() segmentationDisplayNode.SetSegmentVisibility(segmentName, True) slicer.util.findChild(segmentEditorWidget, "Show3DButton").checked = True segmentationDisplayNode.SetSegmentOpacity3D("Background",0.5) ################################## self.delayDisplay("Compute statistics") from SegmentStatistics import SegmentStatisticsLogic segStatLogic = SegmentStatisticsLogic() segStatLogic.getParameterNode().SetParameter("Segmentation", segmentationNode.GetID()) segStatLogic.getParameterNode().SetParameter("ScalarVolume", masterVolumeNode.GetID()) segStatLogic.getParameterNode().SetParameter("visibleSegmentsOnly", "False") segStatLogic.computeStatistics() # Export results to table (just to see all results) resultsTableNode = slicer.vtkMRMLTableNode() slicer.mrmlScene.AddNode(resultsTableNode) segStatLogic.exportToTable(resultsTableNode) segStatLogic.showTable(resultsTableNode) self.delayDisplay("Check a few numerical results") stats = segStatLogic.getStatistics() self.assertEqual( round(stats['Tumor', 'LabelmapSegmentStatisticsPlugin.volume_mm3']), 19498.0) self.delayDisplay('test_SurfaceCut1 passed')
def test_SplitVolume1(self): """ Basic automated test of the segmentation method: - Create segmentation by placing sphere-shaped seeds - Run segmentation - Verify results using segment statistics The test can be executed from SelfTests module (test name: SegmentEditorSplitVolume) """ self.delayDisplay("Starting test_SplitVolume1") import vtkSegmentationCorePython as vtkSegmentationCore import vtkSlicerSegmentationsModuleLogicPython as vtkSlicerSegmentationsModuleLogic import SampleData from SegmentStatistics import SegmentStatisticsLogic ################################## self.delayDisplay("Load master volume") import SampleData sampleDataLogic = SampleData.SampleDataLogic() masterVolumeNode = sampleDataLogic.downloadMRBrainTumor1() ################################## self.delayDisplay("Create segmentation containing a few spheres") segmentationNode = slicer.vtkMRMLSegmentationNode() slicer.mrmlScene.AddNode(segmentationNode) segmentationNode.CreateDefaultDisplayNodes() segmentationNode.SetReferenceImageGeometryParameterFromVolumeNode( masterVolumeNode) # Segments are defined by a list of: name and a list of sphere [radius, posX, posY, posZ] segmentGeometries = [['Tumor', [[10, -6, 30, 28]]], [ 'Background', [[10, 0, 65, 22], [15, 1, -14, 30], [12, 0, 28, -7], [5, 0, 30, 54], [12, 31, 33, 27], [17, -42, 30, 27], [6, -2, -17, 71]] ], ['Air', [[10, 76, 73, 0], [15, -70, 74, 0]]]] for segmentGeometry in segmentGeometries: segmentName = segmentGeometry[0] appender = vtk.vtkAppendPolyData() for sphere in segmentGeometry[1]: sphereSource = vtk.vtkSphereSource() sphereSource.SetRadius(sphere[0]) sphereSource.SetCenter(sphere[1], sphere[2], sphere[3]) appender.AddInputConnection(sphereSource.GetOutputPort()) segment = vtkSegmentationCore.vtkSegment() segment.SetName( segmentationNode.GetSegmentation().GenerateUniqueSegmentID( segmentName)) appender.Update() segment.AddRepresentation( vtkSegmentationCore.vtkSegmentationConverter. GetSegmentationClosedSurfaceRepresentationName(), appender.GetOutput()) segmentationNode.GetSegmentation().AddSegment(segment) ################################## self.delayDisplay("Create segment editor") segmentEditorWidget = slicer.qMRMLSegmentEditorWidget() segmentEditorWidget.show() segmentEditorWidget.setMRMLScene(slicer.mrmlScene) segmentEditorNode = slicer.vtkMRMLSegmentEditorNode() slicer.mrmlScene.AddNode(segmentEditorNode) segmentEditorWidget.setMRMLSegmentEditorNode(segmentEditorNode) segmentEditorWidget.setSegmentationNode(segmentationNode) segmentEditorWidget.setMasterVolumeNode(masterVolumeNode) ################################## self.delayDisplay("Run segmentation") segmentEditorWidget.setActiveEffectByName("SplitVolume") effect = segmentEditorWidget.activeEffect() effect.self().onApply() ################################## self.delayDisplay("Make segmentation results nicely visible in 3D") segmentationDisplayNode = segmentationNode.GetDisplayNode() segmentationDisplayNode.SetSegmentVisibility("Air", False) segmentationDisplayNode.SetSegmentOpacity3D("Background", 0.5) ################################## self.delayDisplay("Check extent of cropped volumes") expectedBounds = [[ 100.31225000000003, 119.99975000000003, 101.24974999999999, 119.99974999999999, -78.4, -58.8 ], [ 19.68725000000002, 119.99975000000003, 16.874749999999977, 119.99974999999999, -78.4, 16.80000000000001 ], [ -49.687749999999994, 119.99975000000003, 90.93724999999999, 119.99974999999999, -78.4, -47.6 ]] for segmentIndex in range( segmentationNode.GetSegmentation().GetNumberOfSegments()): segmentID = segmentationNode.GetSegmentation().GetNthSegmentID( segmentIndex) outputVolumeName = masterVolumeNode.GetName() + '_' + segmentID outputVolume = slicer.util.getNode(outputVolumeName) bounds = [0, 0, 0, 0, 0, 0] outputVolume.GetBounds(bounds) self.assertEqual(bounds, expectedBounds) ################################## self.delayDisplay("Compute statistics") segStatLogic = SegmentStatisticsLogic() segStatLogic.computeStatistics(segmentationNode, masterVolumeNode) # Export results to table (just to see all results) resultsTableNode = slicer.vtkMRMLTableNode() slicer.mrmlScene.AddNode(resultsTableNode) segStatLogic.exportToTable(resultsTableNode) segStatLogic.showTable(resultsTableNode) self.delayDisplay("Check a few numerical results") self.assertEqual( round(segStatLogic.statistics["Tumor", "LM volume cc"]), 16) self.assertEqual( round(segStatLogic.statistics["Background", "LM volume cc"]), 3010) self.delayDisplay('test_SplitVolume1 passed')
def test_ScriptedSegmentEditorEffectModuleTemplate1(self): """ Basic automated test of the segmentation method: - Create segmentation by placing sphere-shaped seeds - Run segmentation - Verify results using segment statistics The test can be executed from SelfTests module (test name: SegmentEditorScriptedSegmentEditorEffectModuleTemplate) """ self.delayDisplay("Starting test_ScriptedSegmentEditorEffectModuleTemplate1") import vtkSegmentationCorePython as vtkSegmentationCore import vtkSlicerSegmentationsModuleLogicPython as vtkSlicerSegmentationsModuleLogic import SampleData from SegmentStatistics import SegmentStatisticsLogic ################################## self.delayDisplay("Load master volume") import SampleData sampleDataLogic = SampleData.SampleDataLogic() masterVolumeNode = sampleDataLogic.downloadMRBrainTumor1() ################################## self.delayDisplay("Create segmentation containing a few spheres") segmentationNode = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLSegmentationNode") segmentationNode.CreateDefaultDisplayNodes() segmentationNode.SetReferenceImageGeometryParameterFromVolumeNode(masterVolumeNode) # Segments are defined by a list of: name and a list of sphere [radius, posX, posY, posZ] segmentGeometries = [ ['Tumor', [[10, -6,30,28]]], ['Background', [[10, 0,65,22], [15, 1, -14, 30], [12, 0, 28, -7], [5, 0,30,54], [12, 31, 33, 27], [17, -42, 30, 27], [6, -2,-17,71]]], ['Air', [[10, 76,73,0], [15, -70,74,0]]] ] for segmentGeometry in segmentGeometries: segmentName = segmentGeometry[0] appender = vtk.vtkAppendPolyData() for sphere in segmentGeometry[1]: sphereSource = vtk.vtkSphereSource() sphereSource.SetRadius(sphere[0]) sphereSource.SetCenter(sphere[1], sphere[2], sphere[3]) appender.AddInputConnection(sphereSource.GetOutputPort()) segment = vtkSegmentationCore.vtkSegment() segment.SetName(segmentationNode.GetSegmentation().GenerateUniqueSegmentID(segmentName)) appender.Update() segment.AddRepresentation(vtkSegmentationCore.vtkSegmentationConverter.GetSegmentationClosedSurfaceRepresentationName(), appender.GetOutput()) segmentationNode.GetSegmentation().AddSegment(segment) ################################## self.delayDisplay("Create segment editor") segmentEditorWidget = slicer.qMRMLSegmentEditorWidget() segmentEditorWidget.show() segmentEditorWidget.setMRMLScene(slicer.mrmlScene) segmentEditorNode = slicer.vtkMRMLSegmentEditorNode() slicer.mrmlScene.AddNode(segmentEditorNode) segmentEditorWidget.setMRMLSegmentEditorNode(segmentEditorNode) segmentEditorWidget.setSegmentationNode(segmentationNode) segmentEditorWidget.setMasterVolumeNode(masterVolumeNode) ################################## self.delayDisplay("Run segmentation") segmentEditorWidget.setActiveEffectByName("ScriptedSegmentEditorEffectModuleTemplate") effect = segmentEditorWidget.activeEffect() effect.setParameter("ObjectScaleMm", 3.0) effect.self().onApply() ################################## self.delayDisplay("Make segmentation results nicely visible in 3D") segmentationDisplayNode = segmentationNode.GetDisplayNode() segmentationDisplayNode.SetSegmentVisibility("Air", False) segmentationDisplayNode.SetSegmentOpacity3D("Background",0.5) ################################## self.delayDisplay("Compute statistics") segStatLogic = SegmentStatisticsLogic() segStatLogic.computeStatistics(segmentationNode, masterVolumeNode) # Export results to table (just to see all results) resultsTableNode = slicer.vtkMRMLTableNode() slicer.mrmlScene.AddNode(resultsTableNode) segStatLogic.exportToTable(resultsTableNode) segStatLogic.showTable(resultsTableNode) self.delayDisplay("Check a few numerical results") self.assertEqual( round(segStatLogic.statistics["Tumor","LM volume cc"]), 16) self.assertEqual( round(segStatLogic.statistics["Background","LM volume cc"]), 3010) self.delayDisplay('test_ScriptedSegmentEditorEffectModuleTemplate1 passed')
def test_WrapSolidify1(self): """ Basic automated test of the segmentation method: - Create segmentation by placing sphere-shaped seeds - Run segmentation - Verify results using segment statistics The test can be executed from SelfTests module (test name: SegmentEditorWrapSolidify) """ self.delayDisplay("Starting test_WrapSolidify1") import vtkSegmentationCorePython as vtkSegmentationCore import vtkSlicerSegmentationsModuleLogicPython as vtkSlicerSegmentationsModuleLogic import SampleData from SegmentStatistics import SegmentStatisticsLogic ################################## self.delayDisplay("Load master volume") masterVolumeNode = SampleData.downloadSample('MRBrainTumor1') ################################## self.delayDisplay("Create segmentation containing a two spheres") segmentationNode = slicer.mrmlScene.AddNewNodeByClass( 'vtkMRMLSegmentationNode') segmentationNode.CreateDefaultDisplayNodes() segmentationNode.SetReferenceImageGeometryParameterFromVolumeNode( masterVolumeNode) features = ["none", "carveCavities", "createShell", "both"] spheres = [[20, 5, 5, 5], [20, -5, -5, -5]] appender = vtk.vtkAppendPolyData() for sphere in spheres: sphereSource = vtk.vtkSphereSource() sphereSource.SetRadius(sphere[0]) sphereSource.SetCenter(sphere[1], sphere[2], sphere[3]) appender.AddInputConnection(sphereSource.GetOutputPort()) for m in features: segmentName = str(m) segment = vtkSegmentationCore.vtkSegment() segment.SetName( segmentationNode.GetSegmentation().GenerateUniqueSegmentID( segmentName)) appender.Update() segment.AddRepresentation( vtkSegmentationCore.vtkSegmentationConverter. GetSegmentationClosedSurfaceRepresentationName(), appender.GetOutput()) segmentationNode.GetSegmentation().AddSegment(segment) ################################## self.delayDisplay("Create segment editor") segmentEditorWidget = slicer.qMRMLSegmentEditorWidget() segmentEditorWidget.show() segmentEditorWidget.setMRMLScene(slicer.mrmlScene) segmentEditorNode = slicer.vtkMRMLSegmentEditorNode() slicer.mrmlScene.AddNode(segmentEditorNode) segmentEditorWidget.setMRMLSegmentEditorNode(segmentEditorNode) segmentEditorWidget.setSegmentationNode(segmentationNode) segmentEditorWidget.setMasterVolumeNode(masterVolumeNode) ################################## self.delayDisplay("Run WrapSolidify Effect") segmentEditorWidget.setActiveEffectByName("Wrap Solidify") effect = segmentEditorWidget.activeEffect() for t in ["SEGMENTATION", "MODEL"]: effect.setParameter("outputType", t) self.delayDisplay( "Creating Output Type %s, activated feature none" % (t)) segmentEditorWidget.setCurrentSegmentID( segmentationNode.GetSegmentation().GetSegmentIdBySegmentName( 'none')) effect.setParameter("carveCavities", False) effect.setParameter("createShell", False) effect.self().onApply() self.delayDisplay( "Creating Output Type %s, activated feature carveCavities" % (t)) effect.setParameter("carveCavities", True) effect.setParameter("createShell", False) segmentEditorWidget.setCurrentSegmentID( segmentationNode.GetSegmentation().GetSegmentIdBySegmentName( 'carveCavities')) effect.self().onApply() self.delayDisplay( "Creating Output Type %s, activated feature createShell" % (t)) effect.setParameter("carveCavities", False) effect.setParameter("createShell", True) segmentEditorWidget.setCurrentSegmentID( segmentationNode.GetSegmentation().GetSegmentIdBySegmentName( 'createShell')) effect.self().onApply() self.delayDisplay( "Creating Output Type %s, activated feature both" % (t)) effect.setParameter("carveCavities", True) effect.setParameter("createShell", True) segmentEditorWidget.setCurrentSegmentID( segmentationNode.GetSegmentation().GetSegmentIdBySegmentName( 'both')) effect.self().onApply() ################################## self.delayDisplay("Creating Segments from Models") for m in features: model = slicer.util.getNode(m) segmentName = "MODEL_%s" % m segment = vtkSegmentationCore.vtkSegment() segment.SetName( segmentationNode.GetSegmentation().GenerateUniqueSegmentID( segmentName)) segment.SetColor(model.GetDisplayNode().GetColor()) segment.AddRepresentation( vtkSegmentationCore.vtkSegmentationConverter. GetSegmentationClosedSurfaceRepresentationName(), model.GetPolyData()) segmentationNode.GetSegmentation().AddSegment(segment) ################################## self.delayDisplay("Compute statistics") segStatLogic = SegmentStatisticsLogic() segStatLogic.getParameterNode().SetParameter("Segmentation", segmentationNode.GetID()) segStatLogic.getParameterNode().SetParameter("ScalarVolume", masterVolumeNode.GetID()) segStatLogic.computeStatistics() statistics = segStatLogic.getStatistics() ################################## self.delayDisplay("Check a few numerical results") # logging.info(round(statistics["none",'ScalarVolumeSegmentStatisticsPlugin.volume_mm3'])) # logging.info(round(statistics["MODEL_none",'ScalarVolumeSegmentStatisticsPlugin.volume_mm3'])) # logging.info(round(statistics["carveCavities",'ScalarVolumeSegmentStatisticsPlugin.volume_mm3'])) # logging.info(round(statistics["MODEL_carveCavities",'ScalarVolumeSegmentStatisticsPlugin.volume_mm3'])) # logging.info(round(statistics["createShell",'ScalarVolumeSegmentStatisticsPlugin.volume_mm3'])) # logging.info(round(statistics["MODEL_createShell",'ScalarVolumeSegmentStatisticsPlugin.volume_mm3'])) # logging.info(round(statistics["both",'ScalarVolumeSegmentStatisticsPlugin.volume_mm3'])) # logging.info(round(statistics["MODEL_both",'ScalarVolumeSegmentStatisticsPlugin.volume_mm3'])) self.assertEqual( round( statistics["none", 'ScalarVolumeSegmentStatisticsPlugin.volume_mm3']), 46605) self.assertEqual( round( statistics["MODEL_none", 'ScalarVolumeSegmentStatisticsPlugin.volume_mm3']), 46320) self.assertEqual( round( statistics["carveCavities", 'ScalarVolumeSegmentStatisticsPlugin.volume_mm3']), 46605) self.assertEqual( round( statistics["MODEL_carveCavities", 'ScalarVolumeSegmentStatisticsPlugin.volume_mm3']), 46321) self.assertEqual( round( statistics["createShell", 'ScalarVolumeSegmentStatisticsPlugin.volume_mm3']), 9257) self.assertEqual( round( statistics["MODEL_createShell", 'ScalarVolumeSegmentStatisticsPlugin.volume_mm3']), 9230) self.assertEqual( round( statistics["both", 'ScalarVolumeSegmentStatisticsPlugin.volume_mm3']), 9254) self.assertEqual( round( statistics["MODEL_both", 'ScalarVolumeSegmentStatisticsPlugin.volume_mm3']), 9245) self.delayDisplay('test_WrapSolidify1 passed')
class SegmentStatisticsWidget(ScriptedLoadableModuleWidget): """Uses ScriptedLoadableModuleWidget base class, available at: https://github.com/Slicer/Slicer/blob/master/Base/Python/slicer/ScriptedLoadableModule.py """ def setup(self): ScriptedLoadableModuleWidget.setup(self) self.logic = SegmentStatisticsLogic() self.grayscaleNode = None self.labelNode = None self.fileName = None self.fileDialog = None # Instantiate and connect widgets ... # # Inputs inputsCollapsibleButton = ctk.ctkCollapsibleButton() inputsCollapsibleButton.text = "Inputs" self.layout.addWidget(inputsCollapsibleButton) inputsFormLayout = qt.QFormLayout(inputsCollapsibleButton) # Segmentation selector self.segmentationSelector = slicer.qMRMLNodeComboBox() self.segmentationSelector.nodeTypes = ["vtkMRMLSegmentationNode"] self.segmentationSelector.addEnabled = False self.segmentationSelector.removeEnabled = True self.segmentationSelector.renameEnabled = True self.segmentationSelector.setMRMLScene(slicer.mrmlScene) self.segmentationSelector.setToolTip( "Pick the segmentation to compute statistics for") inputsFormLayout.addRow("Segmentation:", self.segmentationSelector) # Grayscale volume selector self.grayscaleSelector = slicer.qMRMLNodeComboBox() self.grayscaleSelector.nodeTypes = ["vtkMRMLScalarVolumeNode"] self.grayscaleSelector.addEnabled = False self.grayscaleSelector.removeEnabled = True self.grayscaleSelector.renameEnabled = True self.grayscaleSelector.noneEnabled = True self.grayscaleSelector.showChildNodeTypes = False self.grayscaleSelector.setMRMLScene(slicer.mrmlScene) self.grayscaleSelector.setToolTip( "Select the grayscale volume for intensity statistics calculations" ) inputsFormLayout.addRow("Grayscale volume:", self.grayscaleSelector) # Output table selector outputCollapsibleButton = ctk.ctkCollapsibleButton() outputCollapsibleButton.text = "Output" self.layout.addWidget(outputCollapsibleButton) outputFormLayout = qt.QFormLayout(outputCollapsibleButton) self.outputTableSelector = slicer.qMRMLNodeComboBox() self.outputTableSelector.nodeTypes = ["vtkMRMLTableNode"] self.outputTableSelector.addEnabled = True self.outputTableSelector.selectNodeUponCreation = True self.outputTableSelector.renameEnabled = True self.outputTableSelector.removeEnabled = True self.outputTableSelector.noneEnabled = False self.outputTableSelector.setMRMLScene(slicer.mrmlScene) self.outputTableSelector.setToolTip( "Select the table where statistics will be saved into") outputFormLayout.addRow("Output table:", self.outputTableSelector) # Apply Button self.applyButton = qt.QPushButton("Apply") self.applyButton.toolTip = "Calculate Statistics." self.applyButton.enabled = False self.parent.layout().addWidget(self.applyButton) # Add vertical spacer self.parent.layout().addStretch(1) # connections self.applyButton.connect('clicked()', self.onApply) self.grayscaleSelector.connect('currentNodeChanged(vtkMRMLNode*)', self.onNodeSelectionChanged) self.segmentationSelector.connect('currentNodeChanged(vtkMRMLNode*)', self.onNodeSelectionChanged) self.outputTableSelector.connect('currentNodeChanged(vtkMRMLNode*)', self.onNodeSelectionChanged) self.onNodeSelectionChanged() def onNodeSelectionChanged(self): self.applyButton.enabled = (self.segmentationSelector.currentNode( ) is not None) and (self.outputTableSelector.currentNode() is not None) if self.segmentationSelector.currentNode(): self.outputTableSelector.baseName = self.segmentationSelector.currentNode( ).GetName() + ' statistics' def onApply(self): """Calculate the label statistics """ # Lock GUI self.applyButton.text = "Working..." self.applyButton.setEnabled(False) slicer.app.processEvents() # Compute statistics self.logic.computeStatistics(self.segmentationSelector.currentNode(), self.grayscaleSelector.currentNode()) self.logic.exportToTable(self.outputTableSelector.currentNode()) # Unlock GUI self.applyButton.setEnabled(True) self.applyButton.text = "Apply" self.logic.showTable(self.outputTableSelector.currentNode())
def __init__(self): SegmentStatisticsLogic.__init__(self) self.plugins = [p for p in self.plugins if not isinstance(p,LabelmapSegmentStatisticsPlugin)] self.reset() self.terminologyLogic = slicer.modules.terminologies.logic()
def test_SegmentStatisticsPlugins(self): """ This tests some aspects of the segment statistics plugins """ self.delayDisplay("Starting test_SegmentStatisticsPlugins") import vtkSegmentationCorePython as vtkSegmentationCore import SampleData from SegmentStatistics import SegmentStatisticsLogic self.delayDisplay("Load master volume") masterVolumeNode = SampleData.downloadSample('MRBrainTumor1') self.delayDisplay("Create segmentation containing a few spheres") segmentationNode = slicer.mrmlScene.AddNewNodeByClass( 'vtkMRMLSegmentationNode') segmentationNode.CreateDefaultDisplayNodes() segmentationNode.SetReferenceImageGeometryParameterFromVolumeNode( masterVolumeNode) # Geometry for each segment is defined by: radius, posX, posY, posZ segmentGeometries = [[10, -6, 30, 28], [20, 0, 65, 32], [15, 1, -14, 30], [12, 0, 28, -7], [5, 0, 30, 64], [12, 31, 33, 27], [17, -42, 30, 27]] for segmentGeometry in segmentGeometries: sphereSource = vtk.vtkSphereSource() sphereSource.SetRadius(segmentGeometry[0]) sphereSource.SetCenter(segmentGeometry[1], segmentGeometry[2], segmentGeometry[3]) sphereSource.Update() segment = vtkSegmentationCore.vtkSegment() uniqueSegmentID = segmentationNode.GetSegmentation( ).GenerateUniqueSegmentID("Test") segmentationNode.AddSegmentFromClosedSurfaceRepresentation( sphereSource.GetOutput(), uniqueSegmentID) # test calculating only measurements for selected segments self.delayDisplay( "Test calculating only measurements for individual segments") segStatLogic = SegmentStatisticsLogic() segStatLogic.getParameterNode().SetParameter("Segmentation", segmentationNode.GetID()) segStatLogic.getParameterNode().SetParameter("ScalarVolume", masterVolumeNode.GetID()) segStatLogic.updateStatisticsForSegment('Test_2') resultsTableNode = slicer.vtkMRMLTableNode() slicer.mrmlScene.AddNode(resultsTableNode) segStatLogic.exportToTable(resultsTableNode) segStatLogic.showTable(resultsTableNode) self.assertEqual( segStatLogic.getStatistics()[ "Test_2", "LabelmapSegmentStatisticsPlugin.voxel_count"], 9807) with self.assertRaises(KeyError): segStatLogic.getStatistics()[ "Test_4", "ScalarVolumeSegmentStatisticsPlugin.voxel count"] # assert there are no result for this segment segStatLogic.updateStatisticsForSegment('Test_4') segStatLogic.exportToTable(resultsTableNode) segStatLogic.showTable(resultsTableNode) self.assertEqual( segStatLogic.getStatistics()[ "Test_2", "LabelmapSegmentStatisticsPlugin.voxel_count"], 9807) self.assertEqual( segStatLogic.getStatistics()[ "Test_4", "LabelmapSegmentStatisticsPlugin.voxel_count"], 380) with self.assertRaises(KeyError): segStatLogic.getStatistics()[ "Test_5", "ScalarVolumeSegmentStatisticsPlugin.voxel count"] # assert there are no result for this segment # calculate measurements for all segments segStatLogic.computeStatistics() self.assertEqual( segStatLogic.getStatistics()[ "Test", "LabelmapSegmentStatisticsPlugin.voxel_count"], 2948) self.assertEqual( segStatLogic.getStatistics() ["Test_1", "LabelmapSegmentStatisticsPlugin.voxel_count"], 23281) # test updating measurements for segments one by one self.delayDisplay("Update some segments in the segmentation") segmentGeometriesNew = [[5, -6, 30, 28], [21, 0, 65, 32]] # We add/remove representations, so we temporarily block segment modifications # to make sure display managers don't try to access data while it is in an # inconsistent state. wasModified = segmentationNode.StartModify() for i in range(len(segmentGeometriesNew)): segmentGeometry = segmentGeometriesNew[i] sphereSource = vtk.vtkSphereSource() sphereSource.SetRadius(segmentGeometry[0]) sphereSource.SetCenter(segmentGeometry[1], segmentGeometry[2], segmentGeometry[3]) sphereSource.Update() segment = segmentationNode.GetSegmentation().GetNthSegment(i) segment.RemoveAllRepresentations() closedSurfaceName = vtkSegmentationCore.vtkSegmentationConverter.GetSegmentationClosedSurfaceRepresentationName( ) segment.AddRepresentation(closedSurfaceName, sphereSource.GetOutput()) segmentationNode.EndModify(wasModified) self.assertEqual( segStatLogic.getStatistics()[ "Test", "LabelmapSegmentStatisticsPlugin.voxel_count"], 2948) self.assertEqual( segStatLogic.getStatistics() ["Test_1", "LabelmapSegmentStatisticsPlugin.voxel_count"], 23281) segStatLogic.updateStatisticsForSegment('Test_1') self.assertEqual( segStatLogic.getStatistics()[ "Test", "LabelmapSegmentStatisticsPlugin.voxel_count"], 2948) self.assertTrue(segStatLogic.getStatistics()[ "Test_1", "LabelmapSegmentStatisticsPlugin.voxel_count"] != 23281) segStatLogic.updateStatisticsForSegment('Test') self.assertTrue(segStatLogic.getStatistics()[ "Test", "LabelmapSegmentStatisticsPlugin.voxel_count"] != 2948) self.assertTrue(segStatLogic.getStatistics()[ "Test_1", "LabelmapSegmentStatisticsPlugin.voxel_count"] != 23281) # test enabling/disabling of individual measurements self.delayDisplay("Test disabling of individual measurements") segStatLogic = SegmentStatisticsLogic() segStatLogic.getParameterNode().SetParameter("Segmentation", segmentationNode.GetID()) segStatLogic.getParameterNode().SetParameter("ScalarVolume", masterVolumeNode.GetID()) segStatLogic.getParameterNode().SetParameter( "LabelmapSegmentStatisticsPlugin.voxel_count.enabled", str(False)) segStatLogic.getParameterNode().SetParameter( "LabelmapSegmentStatisticsPlugin.volume_cm3.enabled", str(False)) segStatLogic.computeStatistics() segStatLogic.exportToTable(resultsTableNode) segStatLogic.showTable(resultsTableNode) columnHeaders = [ resultsTableNode.GetColumnName(i) for i in range(resultsTableNode.GetNumberOfColumns()) ] self.assertFalse('Number of voxels [voxels] (1)' in columnHeaders) self.assertTrue('Volume [mm3] (1)' in columnHeaders) self.assertFalse('Volume [cm3] (3)' in columnHeaders) self.delayDisplay("Test re-enabling of individual measurements") segStatLogic.getParameterNode().SetParameter( "LabelmapSegmentStatisticsPlugin.voxel_count.enabled", str(True)) segStatLogic.getParameterNode().SetParameter( "LabelmapSegmentStatisticsPlugin.volume_cm3.enabled", str(True)) segStatLogic.computeStatistics() segStatLogic.exportToTable(resultsTableNode) segStatLogic.showTable(resultsTableNode) columnHeaders = [ resultsTableNode.GetColumnName(i) for i in range(resultsTableNode.GetNumberOfColumns()) ] self.assertTrue('Number of voxels [voxels] (1)' in columnHeaders) self.assertTrue('Volume [mm3] (1)' in columnHeaders) self.assertTrue('Volume [cm3] (1)' in columnHeaders) # test enabling/disabling of individual plugins self.delayDisplay("Test disabling of plugin") segStatLogic.getParameterNode().SetParameter( "LabelmapSegmentStatisticsPlugin.enabled", str(False)) segStatLogic.computeStatistics() segStatLogic.exportToTable(resultsTableNode) segStatLogic.showTable(resultsTableNode) columnHeaders = [ resultsTableNode.GetColumnName(i) for i in range(resultsTableNode.GetNumberOfColumns()) ] self.assertFalse('Number of voxels [voxels] (3)' in columnHeaders) self.assertFalse('Volume [mm3] (3)' in columnHeaders) self.assertTrue('Volume [mm3] (2)' in columnHeaders) self.delayDisplay("Test re-enabling of plugin") segStatLogic.getParameterNode().SetParameter( "LabelmapSegmentStatisticsPlugin.enabled", str(True)) segStatLogic.computeStatistics() segStatLogic.exportToTable(resultsTableNode) segStatLogic.showTable(resultsTableNode) columnHeaders = [ resultsTableNode.GetColumnName(i) for i in range(resultsTableNode.GetNumberOfColumns()) ] self.assertTrue('Number of voxels [voxels] (2)' in columnHeaders) self.assertTrue('Volume [mm3] (3)' in columnHeaders) # test unregistering/registering of plugins self.delayDisplay("Test of removing all registered plugins") SegmentStatisticsLogic.registeredPlugins = [ ] # remove all registered plugins segStatLogic = SegmentStatisticsLogic() segStatLogic.getParameterNode().SetParameter("Segmentation", segmentationNode.GetID()) segStatLogic.getParameterNode().SetParameter("ScalarVolume", masterVolumeNode.GetID()) segStatLogic.computeStatistics() segStatLogic.exportToTable(resultsTableNode) segStatLogic.showTable(resultsTableNode) columnHeaders = [ resultsTableNode.GetColumnName(i) for i in range(resultsTableNode.GetNumberOfColumns()) ] self.assertEqual(len(columnHeaders), 1) # only header element should be "Segment" self.assertEqual(columnHeaders[0], "Segment") # only header element should be "Segment" self.delayDisplay("Test registering plugins") SegmentStatisticsLogic.registerPlugin( LabelmapSegmentStatisticsPlugin()) SegmentStatisticsLogic.registerPlugin( ScalarVolumeSegmentStatisticsPlugin()) SegmentStatisticsLogic.registerPlugin( ClosedSurfaceSegmentStatisticsPlugin()) segStatLogic = SegmentStatisticsLogic() segStatLogic.getParameterNode().SetParameter("Segmentation", segmentationNode.GetID()) segStatLogic.getParameterNode().SetParameter("ScalarVolume", masterVolumeNode.GetID()) segStatLogic.computeStatistics() segStatLogic.exportToTable(resultsTableNode) segStatLogic.showTable(resultsTableNode) columnHeaders = [ resultsTableNode.GetColumnName(i) for i in range(resultsTableNode.GetNumberOfColumns()) ] self.assertTrue('Number of voxels [voxels] (1)' in columnHeaders) self.assertTrue('Number of voxels [voxels] (2)' in columnHeaders) self.assertTrue('Surface area [mm2]' in columnHeaders) self.delayDisplay('test_SegmentStatisticsPlugins passed!')
class SegmentStatisticsWidget(ScriptedLoadableModuleWidget): """Uses ScriptedLoadableModuleWidget base class, available at: https://github.com/Slicer/Slicer/blob/master/Base/Python/slicer/ScriptedLoadableModule.py """ def setup(self): ScriptedLoadableModuleWidget.setup(self) self.logic = SegmentStatisticsLogic() self.grayscaleNode = None self.labelNode = None self.parameterNode = None self.parameterNodeObserver = None # Instantiate and connect widgets ... # # Parameter set selector self.parameterNodeSelector = slicer.qMRMLNodeComboBox() self.parameterNodeSelector.nodeTypes = ["vtkMRMLScriptedModuleNode"] self.parameterNodeSelector.addAttribute( "vtkMRMLScriptedModuleNode", "ModuleName", "SegmentStatistics" ) self.parameterNodeSelector.selectNodeUponCreation = True self.parameterNodeSelector.addEnabled = True self.parameterNodeSelector.renameEnabled = True self.parameterNodeSelector.removeEnabled = True self.parameterNodeSelector.noneEnabled = False self.parameterNodeSelector.showHidden = True self.parameterNodeSelector.showChildNodeTypes = False self.parameterNodeSelector.baseName = "SegmentStatistics" self.parameterNodeSelector.setMRMLScene( slicer.mrmlScene ) self.parameterNodeSelector.setToolTip( "Pick parameter set" ) self.layout.addWidget(self.parameterNodeSelector) # Inputs inputsCollapsibleButton = ctk.ctkCollapsibleButton() inputsCollapsibleButton.text = "Inputs" self.layout.addWidget(inputsCollapsibleButton) inputsFormLayout = qt.QFormLayout(inputsCollapsibleButton) # Segmentation selector self.segmentationSelector = slicer.qMRMLNodeComboBox() self.segmentationSelector.nodeTypes = ["vtkMRMLSegmentationNode"] self.segmentationSelector.addEnabled = False self.segmentationSelector.removeEnabled = True self.segmentationSelector.renameEnabled = True self.segmentationSelector.setMRMLScene( slicer.mrmlScene ) self.segmentationSelector.setToolTip( "Pick the segmentation to compute statistics for" ) inputsFormLayout.addRow("Segmentation:", self.segmentationSelector) # Scalar volume selector self.scalarSelector = slicer.qMRMLNodeComboBox() self.scalarSelector.nodeTypes = ["vtkMRMLScalarVolumeNode"] self.scalarSelector.addEnabled = False self.scalarSelector.removeEnabled = True self.scalarSelector.renameEnabled = True self.scalarSelector.noneEnabled = True self.scalarSelector.showChildNodeTypes = False self.scalarSelector.setMRMLScene( slicer.mrmlScene ) self.scalarSelector.setToolTip( "Select the scalar volume for intensity statistics calculations") inputsFormLayout.addRow("Scalar volume:", self.scalarSelector) # Output table selector outputCollapsibleButton = ctk.ctkCollapsibleButton() outputCollapsibleButton.text = "Output" self.layout.addWidget(outputCollapsibleButton) outputFormLayout = qt.QFormLayout(outputCollapsibleButton) self.outputTableSelector = slicer.qMRMLNodeComboBox() self.outputTableSelector.noneDisplay = "Create new table" self.outputTableSelector.setMRMLScene(slicer.mrmlScene) self.outputTableSelector.nodeTypes = ["vtkMRMLTableNode"] self.outputTableSelector.addEnabled = True self.outputTableSelector.selectNodeUponCreation = True self.outputTableSelector.renameEnabled = True self.outputTableSelector.removeEnabled = True self.outputTableSelector.noneEnabled = True self.outputTableSelector.setToolTip("Select the table where statistics will be saved into") self.outputTableSelector.setCurrentNode(None) outputFormLayout.addRow("Output table:", self.outputTableSelector) # Parameter set parametersCollapsibleButton = ctk.ctkCollapsibleButton() parametersCollapsibleButton.text = "Advanced" parametersCollapsibleButton.collapsed = True self.layout.addWidget(parametersCollapsibleButton) self.parametersLayout = qt.QFormLayout(parametersCollapsibleButton) # Edit parameter set button to open SegmentStatisticsParameterEditorDialog # Note: we add the plugins' option widgets to the module widget instead of using the editor dialog #self.editParametersButton = qt.QPushButton("Edit Parameter Set") #self.editParametersButton.toolTip = "Editor Statistics Plugin Parameter Set." #self.parametersLayout.addRow(self.editParametersButton) #self.editParametersButton.connect('clicked()', self.onEditParameters) # add caclulator's option widgets self.addPluginOptionWidgets() # Apply Button self.applyButton = qt.QPushButton("Apply") self.applyButton.toolTip = "Calculate Statistics." self.applyButton.enabled = False self.parent.layout().addWidget(self.applyButton) # Add vertical spacer self.parent.layout().addStretch(1) # connections self.applyButton.connect('clicked()', self.onApply) self.scalarSelector.connect('currentNodeChanged(vtkMRMLNode*)', self.onNodeSelectionChanged) self.segmentationSelector.connect('currentNodeChanged(vtkMRMLNode*)', self.onNodeSelectionChanged) self.outputTableSelector.connect('currentNodeChanged(vtkMRMLNode*)', self.onNodeSelectionChanged) self.parameterNodeSelector.connect('currentNodeChanged(vtkMRMLNode*)', self.onNodeSelectionChanged) self.parameterNodeSelector.connect('currentNodeChanged(vtkMRMLNode*)', self.onParameterSetSelected) self.parameterNodeSelector.setCurrentNode(self.logic.getParameterNode()) self.onNodeSelectionChanged() self.onParameterSetSelected() def enter(self): """Runs whenever the module is reopened """ if self.parameterNodeSelector.currentNode() is None: parameterNode = self.logic.getParameterNode() slicer.mrmlScene.AddNode(parameterNode) self.parameterNodeSelector.setCurrentNode(parameterNode) if self.segmentationSelector.currentNode() is None: segmentationNode = slicer.mrmlScene.GetFirstNodeByClass("vtkMRMLSegmentationNode") self.segmentationSelector.setCurrentNode(segmentationNode) def cleanup(self): if self.parameterNode and self.parameterNodeObserver: self.parameterNode.RemoveObserver(self.parameterNodeObserver) def onNodeSelectionChanged(self): self.applyButton.enabled = (self.segmentationSelector.currentNode() is not None and self.parameterNodeSelector.currentNode() is not None) if self.segmentationSelector.currentNode(): self.outputTableSelector.baseName = self.segmentationSelector.currentNode().GetName() + ' statistics' def onApply(self): """Calculate the label statistics """ if not self.outputTableSelector.currentNode(): newTable = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLTableNode") self.outputTableSelector.setCurrentNode(newTable) # Lock GUI self.applyButton.text = "Working..." self.applyButton.setEnabled(False) slicer.app.processEvents() # set up parameters for computation self.logic.getParameterNode().SetParameter("Segmentation", self.segmentationSelector.currentNode().GetID()) if self.scalarSelector.currentNode(): self.logic.getParameterNode().SetParameter("ScalarVolume", self.scalarSelector.currentNode().GetID()) else: self.logic.getParameterNode().UnsetParameter("ScalarVolume") self.logic.getParameterNode().SetParameter("MeasurementsTable", self.outputTableSelector.currentNode().GetID()) # Compute statistics self.logic.computeStatistics() self.logic.exportToTable(self.outputTableSelector.currentNode()) # Unlock GUI self.applyButton.setEnabled(True) self.applyButton.text = "Apply" self.logic.showTable(self.outputTableSelector.currentNode()) def onEditParameters(self, pluginName=None): """Open dialog box to edit plugin's parameters""" if self.parameterNodeSelector.currentNode(): SegmentStatisticsParameterEditorDialog.editParameters(self.parameterNodeSelector.currentNode(),pluginName) def addPluginOptionWidgets(self): self.pluginEnabledCheckboxes = {} self.parametersLayout.addRow(qt.QLabel("Enabled segment statistics plugins:")) for plugin in self.logic.plugins: checkbox = qt.QCheckBox(plugin.name+" Statistics") checkbox.checked = True checkbox.connect('stateChanged(int)', self.updateParameterNodeFromGui) optionButton = qt.QPushButton("Options") from functools import partial optionButton.connect('clicked()',partial(self.onEditParameters, plugin.name)) editWidget = qt.QWidget() editWidget.setLayout(qt.QHBoxLayout()) editWidget.layout().margin = 0 editWidget.layout().addWidget(checkbox, 0) editWidget.layout().addStretch(1) editWidget.layout().addWidget(optionButton, 0) self.pluginEnabledCheckboxes[plugin.name] = checkbox self.parametersLayout.addRow(editWidget) # embed widgets for editing plugin' parameters #for plugin in self.logic.plugins: # pluginOptionsCollapsibleButton = ctk.ctkCollapsibleGroupBox() # pluginOptionsCollapsibleButton.setTitle( plugin.name ) # pluginOptionsFormLayout = qt.QFormLayout(pluginOptionsCollapsibleButton) # pluginOptionsFormLayout.addRow(plugin.optionsWidget) # self.parametersLayout.addRow(pluginOptionsCollapsibleButton) def onParameterSetSelected(self): if self.parameterNode and self.parameterNodeObserver: self.parameterNode.RemoveObserver(self.parameterNodeObserver) self.parameterNode = self.parameterNodeSelector.currentNode() if self.parameterNode: self.logic.setParameterNode(self.parameterNode) self.parameterNodeObserver = self.parameterNode.AddObserver(vtk.vtkCommand.ModifiedEvent, self.updateGuiFromParameterNode) self.updateGuiFromParameterNode() def updateGuiFromParameterNode(self, caller=None, event=None): if not self.parameterNode: return for plugin in self.logic.plugins: pluginName = plugin.__class__.__name__ parameter = pluginName+'.enabled' checkbox = self.pluginEnabledCheckboxes[plugin.name] value = self.parameterNode.GetParameter(parameter)=='True' if checkbox.checked!=value: previousState = checkbox.blockSignals(True) checkbox.checked = value checkbox.blockSignals(previousState) def updateParameterNodeFromGui(self): if not self.parameterNode: return for plugin in self.logic.plugins: pluginName = plugin.__class__.__name__ parameter = pluginName+'.enabled' checkbox = self.pluginEnabledCheckboxes[plugin.name] self.parameterNode.SetParameter(parameter, str(checkbox.checked))
class SegmentStatisticsParameterEditorDialog(qt.QDialog): """Dialog to edit parameters of segment statistics plugins. Most users will only need to call the static method editParameters(...) """ @staticmethod def editParameters(parameterNode, pluginName=None): """Executes a modal dialog to edit a segment statistics parameter node if a pluginName is specified, only options for this plugin are displayed" """ dialog = SegmentStatisticsParameterEditorDialog(parent=None, parameterNode=parameterNode, pluginName=pluginName) return dialog.exec_() def __init__(self,parent=None, parameterNode=None, pluginName=None): super(qt.QDialog,self).__init__(parent) self.title = "Edit Segment Statistics Parameters" self.parameterNode = parameterNode self.pluginName = pluginName self.logic = SegmentStatisticsLogic() # for access to plugins and editor widgets self.logic.setParameterNode(self.parameterNode) self.setup() def setParameterNode(self, parameterNode): """Set the parameter node the dialog will operate on""" if parameterNode==self.parameterNode: return self.parameterNode = parameterNode self.logic.setParameterNode(self.parameterNode) def setup(self): self.setLayout(qt.QVBoxLayout()) self.descriptionLabel = qt.QLabel("Edit segment statistics plugin parameters:",0) self.doneButton = qt.QPushButton("Done") self.doneButton.toolTip = "Finish editing." doneWidget = qt.QWidget(self) doneWidget.setLayout(qt.QHBoxLayout()) doneWidget.layout().addStretch(1) doneWidget.layout().addWidget(self.doneButton, 0) parametersScrollArea = qt.QScrollArea(self) self.parametersWidget = qt.QWidget(parametersScrollArea) self.parametersLayout = qt.QFormLayout(self.parametersWidget) self._addPluginOptionWidgets() parametersScrollArea.setWidget(self.parametersWidget) parametersScrollArea.widgetResizable = True parametersScrollArea.setVerticalScrollBarPolicy(qt.Qt.ScrollBarAsNeeded ) parametersScrollArea.setHorizontalScrollBarPolicy(qt.Qt.ScrollBarAsNeeded) self.layout().addWidget(self.descriptionLabel,0) self.layout().addWidget(parametersScrollArea, 1) self.layout().addWidget(doneWidget, 0) self.doneButton.connect('clicked()', lambda: self.done(1)) def _addPluginOptionWidgets(self): description = "Edit segment statistics plugin parameters:" if self.pluginName: description = "Edit "+self.pluginName+" plugin parameters:" self.descriptionLabel.text = description if self.pluginName: for plugin in self.logic.plugins: if plugin.name==self.pluginName: self.parametersLayout.addRow(plugin.optionsWidget) else: for plugin in self.logic.plugins: pluginOptionsCollapsibleButton = ctk.ctkCollapsibleGroupBox(self.parametersWidget) pluginOptionsCollapsibleButton.setTitle( plugin.name ) pluginOptionsFormLayout = qt.QFormLayout(pluginOptionsCollapsibleButton) pluginOptionsFormLayout.addRow(plugin.optionsWidget) self.parametersLayout.addRow(pluginOptionsCollapsibleButton)
def setup(self): ScriptedLoadableModuleWidget.setup(self) self.logic = SegmentStatisticsLogic() self.grayscaleNode = None self.labelNode = None self.fileName = None self.fileDialog = None # Instantiate and connect widgets ... # # Inputs inputsCollapsibleButton = ctk.ctkCollapsibleButton() inputsCollapsibleButton.text = "Inputs" self.layout.addWidget(inputsCollapsibleButton) inputsFormLayout = qt.QFormLayout(inputsCollapsibleButton) # Segmentation selector self.segmentationSelector = slicer.qMRMLNodeComboBox() self.segmentationSelector.nodeTypes = ["vtkMRMLSegmentationNode"] self.segmentationSelector.addEnabled = False self.segmentationSelector.removeEnabled = True self.segmentationSelector.renameEnabled = True self.segmentationSelector.setMRMLScene(slicer.mrmlScene) self.segmentationSelector.setToolTip( "Pick the segmentation to compute statistics for") inputsFormLayout.addRow("Segmentation:", self.segmentationSelector) # Grayscale volume selector self.grayscaleSelector = slicer.qMRMLNodeComboBox() self.grayscaleSelector.nodeTypes = ["vtkMRMLScalarVolumeNode"] self.grayscaleSelector.addEnabled = False self.grayscaleSelector.removeEnabled = True self.grayscaleSelector.renameEnabled = True self.grayscaleSelector.noneEnabled = True self.grayscaleSelector.showChildNodeTypes = False self.grayscaleSelector.setMRMLScene(slicer.mrmlScene) self.grayscaleSelector.setToolTip( "Select the grayscale volume for intensity statistics calculations" ) inputsFormLayout.addRow("Grayscale volume:", self.grayscaleSelector) # Output table selector outputCollapsibleButton = ctk.ctkCollapsibleButton() outputCollapsibleButton.text = "Output" self.layout.addWidget(outputCollapsibleButton) outputFormLayout = qt.QFormLayout(outputCollapsibleButton) self.outputTableSelector = slicer.qMRMLNodeComboBox() self.outputTableSelector.nodeTypes = ["vtkMRMLTableNode"] self.outputTableSelector.addEnabled = True self.outputTableSelector.selectNodeUponCreation = True self.outputTableSelector.renameEnabled = True self.outputTableSelector.removeEnabled = True self.outputTableSelector.noneEnabled = False self.outputTableSelector.setMRMLScene(slicer.mrmlScene) self.outputTableSelector.setToolTip( "Select the table where statistics will be saved into") outputFormLayout.addRow("Output table:", self.outputTableSelector) # Apply Button self.applyButton = qt.QPushButton("Apply") self.applyButton.toolTip = "Calculate Statistics." self.applyButton.enabled = False self.parent.layout().addWidget(self.applyButton) # Add vertical spacer self.parent.layout().addStretch(1) # connections self.applyButton.connect('clicked()', self.onApply) self.grayscaleSelector.connect('currentNodeChanged(vtkMRMLNode*)', self.onNodeSelectionChanged) self.segmentationSelector.connect('currentNodeChanged(vtkMRMLNode*)', self.onNodeSelectionChanged) self.outputTableSelector.connect('currentNodeChanged(vtkMRMLNode*)', self.onNodeSelectionChanged) self.onNodeSelectionChanged()
def test_NvidiaAIAA1(self): """ Basic automated test of the segmentation method: - Create segmentation by placing sphere-shaped seeds - Run segmentation - Verify results using segment statistics The test can be executed from SelfTests module (test name: SegmentEditorNvidiaAIAA) """ self.delayDisplay("Starting test_NvidiaAIAA1") import vtkSegmentationCorePython as vtkSegmentationCore import vtkSlicerSegmentationsModuleLogicPython as vtkSlicerSegmentationsModuleLogic import SampleData from SegmentStatistics import SegmentStatisticsLogic ################################## self.delayDisplay("Load master volume") masterVolumeNode = SampleData.downloadSample('MRBrainTumor1') ################################## self.delayDisplay("Create segmentation containing a few spheres") segmentationNode = slicer.mrmlScene.AddNewNodeByClass( 'vtkMRMLSegmentationNode') segmentationNode.CreateDefaultDisplayNodes() segmentationNode.SetReferenceImageGeometryParameterFromVolumeNode( masterVolumeNode) # Segments are defined by a list of: name and a list of sphere [radius, posX, posY, posZ] segmentGeometries = [['Tumor', [[10, -6, 30, 28]]], [ 'Background', [[10, 0, 65, 22], [15, 1, -14, 30], [12, 0, 28, -7], [5, 0, 30, 54], [12, 31, 33, 27], [17, -42, 30, 27], [6, -2, -17, 71]] ], ['Air', [[10, 76, 73, 0], [15, -70, 74, 0]]]] for segmentGeometry in segmentGeometries: segmentName = segmentGeometry[0] appender = vtk.vtkAppendPolyData() for sphere in segmentGeometry[1]: sphereSource = vtk.vtkSphereSource() sphereSource.SetRadius(sphere[0]) sphereSource.SetCenter(sphere[1], sphere[2], sphere[3]) appender.AddInputConnection(sphereSource.GetOutputPort()) segment = vtkSegmentationCore.vtkSegment() segment.SetName( segmentationNode.GetSegmentation().GenerateUniqueSegmentID( segmentName)) appender.Update() segment.AddRepresentation( vtkSegmentationCore.vtkSegmentationConverter. GetSegmentationClosedSurfaceRepresentationName(), appender.GetOutput()) segmentationNode.GetSegmentation().AddSegment(segment) ################################## self.delayDisplay("Create segment editor") segmentEditorWidget = slicer.qMRMLSegmentEditorWidget() segmentEditorWidget.show() segmentEditorWidget.setMRMLScene(slicer.mrmlScene) segmentEditorNode = slicer.vtkMRMLSegmentEditorNode() slicer.mrmlScene.AddNode(segmentEditorNode) segmentEditorWidget.setMRMLSegmentEditorNode(segmentEditorNode) segmentEditorWidget.setSegmentationNode(segmentationNode) segmentEditorWidget.setMasterVolumeNode(masterVolumeNode) ################################## self.delayDisplay("Run segmentation") segmentEditorWidget.setActiveEffectByName("NvidiaAIAA") effect = segmentEditorWidget.activeEffect() effect.setParameter("ObjectScaleMm", 3.0) effect.self().onApply() ################################## self.delayDisplay("Make segmentation results nicely visible in 3D") segmentationDisplayNode = segmentationNode.GetDisplayNode() segmentationDisplayNode.SetSegmentVisibility("Air", False) segmentationDisplayNode.SetSegmentOpacity3D("Background", 0.5) ################################## self.delayDisplay("Compute statistics") segStatLogic = SegmentStatisticsLogic() segStatLogic.computeStatistics(segmentationNode, masterVolumeNode) # Export results to table (just to see all results) resultsTableNode = slicer.vtkMRMLTableNode() slicer.mrmlScene.AddNode(resultsTableNode) segStatLogic.exportToTable(resultsTableNode) segStatLogic.showTable(resultsTableNode) self.delayDisplay("Check a few numerical results") self.assertEqual( round(segStatLogic.statistics["Tumor", "LM volume cc"]), 16) self.assertEqual( round(segStatLogic.statistics["Background", "LM volume cc"]), 3010) self.delayDisplay('test_NvidiaAIAA1 passed')
class SegmentStatisticsWidget(ScriptedLoadableModuleWidget): """Uses ScriptedLoadableModuleWidget base class, available at: https://github.com/Slicer/Slicer/blob/master/Base/Python/slicer/ScriptedLoadableModule.py """ def setup(self): ScriptedLoadableModuleWidget.setup(self) self.logic = SegmentStatisticsLogic() self.grayscaleNode = None self.labelNode = None self.fileName = None self.fileDialog = None # Instantiate and connect widgets ... # # Inputs inputsCollapsibleButton = ctk.ctkCollapsibleButton() inputsCollapsibleButton.text = "Inputs" self.layout.addWidget(inputsCollapsibleButton) inputsFormLayout = qt.QFormLayout(inputsCollapsibleButton) # Segmentation selector self.segmentationSelector = slicer.qMRMLNodeComboBox() self.segmentationSelector.nodeTypes = ["vtkMRMLSegmentationNode"] self.segmentationSelector.addEnabled = False self.segmentationSelector.removeEnabled = True self.segmentationSelector.renameEnabled = True self.segmentationSelector.setMRMLScene( slicer.mrmlScene ) self.segmentationSelector.setToolTip( "Pick the segmentation to compute statistics for" ) inputsFormLayout.addRow("Segmentation:", self.segmentationSelector) # Grayscale volume selector self.grayscaleSelector = slicer.qMRMLNodeComboBox() self.grayscaleSelector.nodeTypes = ["vtkMRMLScalarVolumeNode"] self.grayscaleSelector.addEnabled = False self.grayscaleSelector.removeEnabled = True self.grayscaleSelector.renameEnabled = True self.grayscaleSelector.noneEnabled = True self.grayscaleSelector.showChildNodeTypes = False self.grayscaleSelector.setMRMLScene( slicer.mrmlScene ) self.grayscaleSelector.setToolTip( "Select the grayscale volume for intensity statistics calculations") inputsFormLayout.addRow("Grayscale volume:", self.grayscaleSelector) # Output table selector outputCollapsibleButton = ctk.ctkCollapsibleButton() outputCollapsibleButton.text = "Output" self.layout.addWidget(outputCollapsibleButton) outputFormLayout = qt.QFormLayout(outputCollapsibleButton) self.outputTableSelector = slicer.qMRMLNodeComboBox() self.outputTableSelector.nodeTypes = ["vtkMRMLTableNode"] self.outputTableSelector.addEnabled = True self.outputTableSelector.selectNodeUponCreation = True self.outputTableSelector.renameEnabled = True self.outputTableSelector.removeEnabled = True self.outputTableSelector.noneEnabled = False self.outputTableSelector.setMRMLScene( slicer.mrmlScene ) self.outputTableSelector.setToolTip( "Select the table where statistics will be saved into") outputFormLayout.addRow("Output table:", self.outputTableSelector) # Apply Button self.applyButton = qt.QPushButton("Apply") self.applyButton.toolTip = "Calculate Statistics." self.applyButton.enabled = False self.parent.layout().addWidget(self.applyButton) # Add vertical spacer self.parent.layout().addStretch(1) # connections self.applyButton.connect('clicked()', self.onApply) self.grayscaleSelector.connect('currentNodeChanged(vtkMRMLNode*)', self.onNodeSelectionChanged) self.segmentationSelector.connect('currentNodeChanged(vtkMRMLNode*)', self.onNodeSelectionChanged) self.outputTableSelector.connect('currentNodeChanged(vtkMRMLNode*)', self.onNodeSelectionChanged) self.onNodeSelectionChanged() def onNodeSelectionChanged(self): self.applyButton.enabled = (self.segmentationSelector.currentNode() is not None) and (self.outputTableSelector.currentNode() is not None) if self.segmentationSelector.currentNode(): self.outputTableSelector.baseName = self.segmentationSelector.currentNode().GetName() + ' statistics' def onApply(self): """Calculate the label statistics """ # Lock GUI self.applyButton.text = "Working..." self.applyButton.setEnabled(False) slicer.app.processEvents() # Compute statistics self.logic.computeStatistics(self.segmentationSelector.currentNode(), self.grayscaleSelector.currentNode()) self.logic.exportToTable(self.outputTableSelector.currentNode()) # Unlock GUI self.applyButton.setEnabled(True) self.applyButton.text = "Apply" self.logic.showTable(self.outputTableSelector.currentNode())