Esempio n. 1
0
  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")

    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()
      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!')
Esempio n. 2
0
    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 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)
Esempio n. 4
0
    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')
  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_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))
Esempio n. 8
0
  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!')
Esempio n. 9
0
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 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')
  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')
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 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')
Esempio n. 14
0
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())