Beispiel #1
0
    def section_CliTableInputOutput(self):
        self.delayDisplay("Test table writing and reading by CLI module",
                          self.delayMs)

        # Create input and output nodes

        inputTableNode = slicer.vtkMRMLTableNode()
        slicer.mrmlScene.AddNode(inputTableNode)
        inputTableNode.AddColumn()
        inputTableNode.AddColumn()
        inputTableNode.AddColumn()
        inputTableNode.AddEmptyRow()
        inputTableNode.AddEmptyRow()
        inputTableNode.AddEmptyRow()
        for row in range(3):
            for col in range(3):
                inputTableNode.SetCellText(row, col, str(
                    (row + 1) * (col + 1)))
        inputTableNode.SetCellText(0, 0, "source")

        outputTableNode = slicer.vtkMRMLTableNode()
        slicer.mrmlScene.AddNode(outputTableNode)

        # Run CLI module

        self.delayDisplay("Run CLI module", self.delayMs)
        parameters = {}
        parameters["arg0"] = self.createDummyVolume().GetID()
        parameters["arg1"] = self.createDummyVolume().GetID()
        parameters["transform1"] = self.createDummyTransform().GetID()
        parameters["transform2"] = self.createDummyTransform().GetID()
        parameters["inputDT"] = inputTableNode.GetID()
        parameters["outputDT"] = outputTableNode.GetID()
        slicer.cli.run(slicer.modules.executionmodeltour,
                       None,
                       parameters,
                       wait_for_completion=True)

        # Verify the output table content

        self.delayDisplay("Verify results", self.delayMs)
        # the ExecutionModelTour module copies the input table to the output exxcept the first two rows
        # of the first column, which is set to "Computed first" and "Computed second" strings
        for row in range(3):
            for col in range(3):
                if row == 0 and col == 0:
                    self.assertTrue(
                        outputTableNode.GetCellText(row, col) ==
                        "Computed first")
                elif row == 1 and col == 0:
                    self.assertTrue(
                        outputTableNode.GetCellText(row, col) ==
                        "Computed second")
                else:
                    self.assertTrue(
                        outputTableNode.GetCellText(row, col) ==
                        inputTableNode.GetCellText(row, col))
Beispiel #2
0
  def getUserStatisticsTableNode(self):
    parameterNode = self.getParameterNode()
    if parameterNode is None:
      return

    tableNode = parameterNode.GetNodeReference(self.USER_STATISTICS_TABLE_REFERENCE_ROLE)
    if not tableNode is None:
      return tableNode

    if not self.getUserStatisticsEnabled():
      return

    tableNodes = slicer.util.getNodesByClass("vtkMRMLTableNode")
    for node in tableNodes:
      if node.GetAttribute("UserStatistics.TableNode"):
        tableNode = node
        break

    if tableNode is None:
      logging.info("Create new table node")
      tableNode = slicer.vtkMRMLTableNode()
      tableNode.SetName("UserStatisticsTableNode")
      tableNode.SetAttribute("UserStatistics.TableNode", "")
      slicer.mrmlScene.AddNode(tableNode)
      self.setupTimerTableNode(tableNode)
    self.setUserStatisticsTableNode(tableNode)
    return tableNode
Beispiel #3
0
  def exportToTable(self):
    """
    Export statistics to table node
    """

    colorNode = self.getColorNode()

    table = slicer.vtkMRMLTableNode()
    tableWasModified = table.StartModify()

    table.SetName(slicer.mrmlScene.GenerateUniqueName(self.nodeBaseName + ' statistics'))

    # Define table columns
    if colorNode:
      col = table.AddColumn()
      col.SetName("Type")
    for k in self.keys:
      col = table.AddColumn()
      col.SetName(k)
    for i in self.labelStats["Labels"]:
      rowIndex = table.AddEmptyRow()
      columnIndex = 0
      if colorNode:
        table.SetCellText(rowIndex, columnIndex, colorNode.GetColorName(i))
        columnIndex += 1
      # Add other values
      for k in self.keys:
        table.SetCellText(rowIndex, columnIndex, str(self.labelStats[i, k]))
        columnIndex += 1

    table.EndModify(tableWasModified)
    return table
    def section_TableRole(self):
        self.delayDisplay("Table role", self.delayMs)

        # Create sample table node
        tableNode = slicer.vtkMRMLTableNode()
        slicer.mrmlScene.AddNode(tableNode)
        tableNode.SetName(self.sampleTableName)

        # Add node to subject hierarchy
        from vtkSlicerSubjectHierarchyModuleMRML import vtkMRMLSubjectHierarchyNode

        studyNode = slicer.util.getNode(
            self.studyName + slicer.vtkMRMLSubjectHierarchyConstants.GetSubjectHierarchyNodeNamePostfix()
        )
        self.assertTrue(studyNode != None)

        tableShNode = vtkMRMLSubjectHierarchyNode.CreateSubjectHierarchyNode(
            slicer.mrmlScene,
            studyNode,
            slicer.vtkMRMLSubjectHierarchyConstants.GetDICOMLevelSeries(),
            self.sampleTableName,
            tableNode,
        )

        self.assertTrue(tableShNode != None)
        self.assertTrue(tableShNode.GetParentNode() == studyNode)
        self.assertTrue(tableShNode.GetOwnerPluginName() == "Tables")
Beispiel #5
0
 def createAndConfigureTable(self):
   table = slicer.vtkMRMLTableNode()
   slicer.mrmlScene.AddNode(table)
   table.SetAttribute("QuantitativeReporting", "Yes")
   table.SetAttribute("readonly", "Yes")
   table.SetUseColumnNameAsColumnHeader(True)
   return table
Beispiel #6
0
 def createAndConfigureTable(self):
   table = slicer.vtkMRMLTableNode()
   slicer.mrmlScene.AddNode(table)
   table.SetAttribute("QuantitativeReporting", "Yes")
   table.SetAttribute("readonly", "Yes")
   table.SetUseColumnNameAsColumnHeader(True)
   return table
Beispiel #7
0
  def mergeStatisticsTableNodes(self, tableNodes):
    if len(tableNodes) < 2:
      return

    currentRowIndexes = {}
    for tableNode in tableNodes:
      currentRowIndexes[tableNode] = 0

    logging.info("Create new table node")
    newTableNode = slicer.vtkMRMLTableNode()
    newTableNode.SetName("UserStatisticsTableNode")
    newTableNode.SetAttribute("UserStatistics.TableNode", "")
    self.setupTimerTableNode(newTableNode)

    completed = False
    while not completed:
      remainingTableNodes = []

      # Popupulate the list of rows starting at the top of each table and moving down
      for tableNode in tableNodes:
        currentIndex = currentRowIndexes[tableNode]
        if currentIndex < tableNode.GetNumberOfRows():
          remainingTableNodes.append(tableNode)

      # Done! There are no more rows left in any of the tables
      if remainingTableNodes == []:
        completed = True
      else:
        # Find the "minimum" row by comparing the string format contents of all rows
        oldTableNode = None
        rowToAddString = None
        for tableNode in remainingTableNodes:
          rowString = self.serializeFromTable(currentRowIndexes[tableNode], tableNode, self.timerTableColumnNames)

          # This row is the new "minimum" row to be added to the table next
          if oldTableNode is None or rowString < rowToAddString:
            oldTableNode = tableNode
            rowToAddString = rowString

          # This row is the same as the current "minimum". It is a duplicate so discard it
          elif rowString == rowToAddString:
            currentRowIndexes[tableNode] += 1

        # Add the "minimum" row and increment the index of the corresponding table node
        newTableRowIndex = newTableNode.AddEmptyRow()
        oldTableRowIndex = currentRowIndexes[oldTableNode]
        currentRowIndexes[oldTableNode] += 1
        for name in self.timerTableColumnNames:
          oldTableColumnIndex = oldTableNode.GetColumnIndex(name)
          if oldTableColumnIndex < 0:
            continue
          newTableColumnIndex = newTableNode.GetColumnIndex(name)
          if newTableColumnIndex < 0:
            continue
          cellText = oldTableNode.GetCellText(oldTableRowIndex, oldTableColumnIndex)
          newTableNode.SetCellText(newTableRowIndex, newTableColumnIndex, cellText)

    slicer.mrmlScene.AddNode(newTableNode)
    for tableNode in tableNodes:
      slicer.mrmlScene.RemoveNode(tableNode)
Beispiel #8
0
  def exportToTable(self):
    """
    Export statistics to table node
    """

    colorNode = self.getColorNode()

    table = slicer.vtkMRMLTableNode()
    tableWasModified = table.StartModify()

    table.SetName(slicer.mrmlScene.GenerateUniqueName(self.nodeBaseName + ' statistics'))

    # Define table columns
    if colorNode:
      col = table.AddColumn()
      col.SetName("Type")
    for k in self.keys:
      col = table.AddColumn()
      col.SetName(k)
    for i in self.labelStats["Labels"]:
      rowIndex = table.AddEmptyRow()
      columnIndex = 0
      if colorNode:
        table.SetCellText(rowIndex, columnIndex, colorNode.GetColorName(i))
        columnIndex += 1
      # Add other values
      for k in self.keys:
        table.SetCellText(rowIndex, columnIndex, str(self.labelStats[i, k]))
        columnIndex += 1

    table.EndModify(tableWasModified)
    return table
Beispiel #9
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!')
Beispiel #10
0
  def section_CliTableInputOutput(self):
    self.delayDisplay("Test table writing and reading by CLI module",self.delayMs)

    # Create input and output nodes

    inputTableNode = slicer.vtkMRMLTableNode()
    slicer.mrmlScene.AddNode(inputTableNode)
    inputTableNode.AddColumn()
    inputTableNode.AddColumn()
    inputTableNode.AddColumn()
    inputTableNode.AddEmptyRow()
    inputTableNode.AddEmptyRow()
    inputTableNode.AddEmptyRow()
    for row in range(3):
      for col in range(3):
        inputTableNode.SetCellText(row,col,str((row+1)*(col+1)))
    inputTableNode.SetCellText(0,0,"source")

    outputTableNode = slicer.vtkMRMLTableNode()
    slicer.mrmlScene.AddNode(outputTableNode)

    # Run CLI module

    self.delayDisplay("Run CLI module",self.delayMs)
    parameters = {}
    parameters["arg0"] = self.createDummyVolume().GetID()
    parameters["arg1"] = self.createDummyVolume().GetID()
    parameters["transform1"] = self.createDummyTransform().GetID()
    parameters["transform2"] = self.createDummyTransform().GetID()
    parameters["inputDT"] = inputTableNode.GetID()
    parameters["outputDT"] = outputTableNode.GetID()
    slicer.cli.run(slicer.modules.executionmodeltour, None, parameters, wait_for_completion=True)

    # Verify the output table content

    self.delayDisplay("Verify results",self.delayMs)
    # the ExecutionModelTour module copies the input table to the output exxcept the first two rows
    # of the first column, which is set to "Computed first" and "Computed second" strings
    for row in range(3):
      for col in range(3):
        if row==0 and col==0:
          self.assertTrue( outputTableNode.GetCellText(row, col) == "Computed first")
        elif row==1 and col==0:
          self.assertTrue( outputTableNode.GetCellText(row, col) == "Computed second")
        else:
          self.assertTrue( outputTableNode.GetCellText(row, col) == inputTableNode.GetCellText(row, col) )
 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
Beispiel #12
0
 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 runCLIWithParameterFile(self,
                                imageNode,
                                maskNode,
                                tableNode,
                                parameterFilePath,
                                callback=None):
        """
    Run the actual algorithm using the provided customization file and provided image and region of interest(s) (ROIs)

    :param imageNode: Slicer Volume node representing the image from which features should be extracted
    :param labelNode: Slicer Labelmap node containing the ROIs as integer encoded volume (voxel value indicates ROI id)
    or a segmentation node containing the segments of the ROIs (will be converted to binary label maps)
    :param tableNode: Slicer Table node which will hold the calculated results
    :param parameterFilePath: String file path pointing to the parameter file used to customize the extraction
    :param callback: Function which is invoked when the CLI is done (can be used to unlock the GUI)
    """
        if self.cliNode is not None:
            self.logger.warning('Already running an extraction!')
            return

        self.logger.info('Feature extraction started')

        self._parameterFile = parameterFilePath

        self._labelGenerators = []
        if maskNode.IsA('vtkMRMLVolumeNode'):
            self._labelGenerators = chain(
                self._labelGenerators,
                self._getLabelGeneratorFromLabelMap(maskNode, imageNode))
        elif maskNode.IsA('vtkMRMLSegmentationNode'):
            self._labelGenerators = chain(
                self._labelGenerators,
                self._getLabelGeneratorFromSegmentationNode(
                    maskNode, imageNode))
        else:
            self.logger.error('Invalid maskNode')
            return

        self._cli_output = slicer.vtkMRMLTableNode()
        slicer.mrmlScene.AddNode(self._cli_output)

        self.outTable = tableNode
        self._initOutputTable()

        self.callback = callback

        self._startCLI(firstRun=True)
 def _initTableNode_(self):
     """
     Initialize the vtkMRMLTableSQLiteStorageNode and add it to the scene
     """
     self.tableStorageNode = slicer.vtkMRMLTableSQLiteStorageNode()
     slicer.mrmlScene.AddNode(self.tableStorageNode)
     self.tableStorageNode.SetFileName(self._dbFilePath_)
     self.tableStorageNode.SetTableName(self._dbTableName_)
     self.tableNode = slicer.vtkMRMLTableNode()
     slicer.mrmlScene.AddNode(self.tableNode)
     self.tableNode.SetName("{}_table".format(self._dbTableName_))
     self.tableNode.SetAndObserveStorageNodeID(self.tableStorageNode.GetID())
     if os.path.isfile(self._dbFilePath_):
         # Read the previous data
         self.tableStorageNode.ReadData(self.tableNode)
     else:
         logging.info("The storage database has not been created yet")
    def metadata2vtkTableNode(self, metafile):
        with open(metafile) as datafile:
            table = slicer.vtkMRMLTableNode()
            slicer.mrmlScene.AddNode(table)
            table.SetAttribute("QuantitativeReporting", "Yes")
            table.SetAttribute("readonly", "Yes")
            table.SetUseColumnNameAsColumnHeader(True)

            data = json.load(datafile)

            tableWasModified = table.StartModify()

            measurement = data["Measurements"][0]
            col = table.AddColumn()
            col.SetName("Segment")

            for measurementItem in measurement["measurementItems"]:
                col = table.AddColumn()

                if "derivationModifier" in measurementItem.keys():
                    col.SetName(
                        SegmentStatisticsDICOMMeaningMapping.getKeyForValue(
                            measurementItem["derivationModifier"]
                            ["CodeMeaning"]))
                else:
                    col.SetName(
                        SegmentStatisticsDICOMMeaningMapping.getKeyForValue(
                            measurementItem["quantity"]["CodeMeaning"] + " " +
                            measurementItem["units"]["CodeValue"]))

            for measurement in data["Measurements"]:
                name = measurement["TrackingIdentifier"]
                value = measurement["ReferencedSegment"]
                rowIndex = table.AddEmptyRow()
                table.SetCellText(rowIndex, 0, name)
                for columnIndex, measurementItem in enumerate(
                        measurement["measurementItems"]):
                    table.SetCellText(rowIndex, columnIndex + 1,
                                      measurementItem["value"])

            table.EndModify(tableWasModified)
            slicer.app.applicationLogic().GetSelectionNode(
            ).SetReferenceActiveTableID(table.GetID())
            slicer.app.applicationLogic().PropagateTableSelection()
        return table
Beispiel #17
0
    def onApplyButton(self):
        if self.debuggingCheckBox.checked:
            # Setup debug logging for the pyradiomics toolbox
            # PyRadiomics logs to stderr by default, which is picked up by slicer and added to the slicer log.
            radiomics.setVerbosity(logging.DEBUG)
        else:
            radiomics.setVerbosity(logging.WARNING)

        if not self.outputTableSelector.currentNode():
            tableNode = slicer.vtkMRMLTableNode()
            slicer.mrmlScene.AddNode(tableNode)
            self.outputTableSelector.setCurrentNode(tableNode)

        logic = SlicerRadiomicsLogic()
        featureClasses = self.getCheckedFeatureClasses()

        # Lock GUI
        self.applyButton.text = 'Working...'
        self.applyButton.setEnabled(False)
        slicer.app.processEvents()

        # Compute features
        kwargs = {}
        kwargs['binWidth'] = int(self.binWidthSliderWidget.value)
        kwargs['symmetricalGLCM'] = self.symmetricalGLCMCheckBox.checked
        # kwargs['label'] = int(self.labelSliderWidget.value)

        imageNode = self.inputVolumeSelector.currentNode()
        labelNode = self.inputMaskSelector.currentNode()
        segmentationNode = self.inputSegmentationSelector.currentNode()

        try:
            featuresDict = logic.run(imageNode, labelNode, segmentationNode,
                                     featureClasses, **kwargs)
            logic.exportToTable(featuresDict,
                                self.outputTableSelector.currentNode())
        except:
            self.logger.error("Feature calculation failed.")

        # Unlock GUI
        self.applyButton.setEnabled(True)
        self.applyButton.text = 'Apply'

        # Show results
        logic.showTable(self.outputTableSelector.currentNode())
Beispiel #18
0
 def loadTestData(self, collection="MRHead",
                  imageDataType='volume',
                  uid="2.16.840.1.113662.4.4168496325.1025306170.548651188813145058"):
   if not len(slicer.dicomDatabase.filesForSeries(uid)):
     sampleData = TestDataLogic.downloadAndUnzipSampleData(collection)
     TestDataLogic.importIntoDICOMDatabase(sampleData[imageDataType])
   self.loadSeries(uid)
   loadedVolumeNodes = slicer.util.getNodesByClass('vtkMRMLScalarVolumeNode')
   if not loadedVolumeNodes:
     logging.error("No volumes were loaded into Slicer. Canceling.")
     return
   masterNode = loadedVolumeNodes[-1]
   tableNode = slicer.vtkMRMLTableNode()
   tableNode.SetAttribute("QuantitativeReporting", "Yes")
   slicer.mrmlScene.AddNode(tableNode)
   self.measurementReportSelector.setCurrentNode(tableNode)
   self.segmentEditorWidget.editor.setMasterVolumeNode(masterNode)
   self.retrieveTestDataButton.enabled = False
 def loadTestData(self, collection="MRHead",
                  imageDataType='volume',
                  uid="2.16.840.1.113662.4.4168496325.1025306170.548651188813145058"):
   if not len(slicer.dicomDatabase.filesForSeries(uid)):
     sampleData = TestDataLogic.downloadAndUnzipSampleData(collection)
     TestDataLogic.importIntoDICOMDatabase(sampleData[imageDataType])
   self.loadSeries(uid)
   loadedVolumeNodes = slicer.util.getNodesByClass('vtkMRMLScalarVolumeNode')
   if not loadedVolumeNodes:
     logging.error("No volumes were loaded into Slicer. Canceling.")
     return
   masterNode = loadedVolumeNodes[-1]
   tableNode = slicer.vtkMRMLTableNode()
   tableNode.SetAttribute("QuantitativeReporting", "Yes")
   slicer.mrmlScene.AddNode(tableNode)
   self.measurementReportSelector.setCurrentNode(tableNode)
   self.segmentEditorWidget.editor.setMasterVolumeNode(masterNode)
   self.retrieveTestDataButton.enabled = False
Beispiel #20
0
    def onApplyButton(self):
        self.applyButton.setText("Aguarde...")
        self.applyButton.setEnabled(False)
        self.progressBar.setVisible(True)
        slicer.app.processEvents()

        # Criar tabela para os dados
        logging.info('Criando a tabela')
        self.table = slicer.vtkMRMLTableNode()
        tableWasModified = self.table.StartModify()
        self.table.SetName("Export Table")
        self.table.SetUseColumnNameAsColumnHeader(True)
        col = self.table.AddColumn(); col.SetName("Volume")
        col = self.table.AddColumn(); col.SetName("ICort")
        col = self.table.AddColumn(); col.SetName("ITrab")
        col = self.table.AddColumn(); col.SetName("Ilow")
        col = self.table.AddColumn(); col.SetName("FVTO")

        for node in slicer.util.getNodesByClass('vtkMRMLScalarVolumeNode'):
            if node.GetClassName() == "vtkMRMLLabelMapVolumeNode":
                logging.info('Ignorando label: ' + node.GetName())
                continue
            else:
                logging.info('Processando ' + node.GetName())
                input = node
                label = slicer.util.getNode(node.GetName() + '-label')
                ROILabelValue = self.labelROISpin.value
                cortLabelValue = self.labelCortSpin.value
                self.run(input, label, ROILabelValue, cortLabelValue)

        # Adiciona a tabela a cena e exibe
        logging.info('Adicionar tabela e exibir')
        slicer.mrmlScene.AddNode(self.table)
        slicer.app.layoutManager().setLayout(slicer.vtkMRMLLayoutNode.SlicerLayoutFourUpTableView)
        slicer.app.applicationLogic().GetSelectionNode().SetReferenceActiveTableID(self.table.GetID())
        slicer.app.applicationLogic().PropagateTableSelection()
        self.table.EndModify(tableWasModified)

        self.applyButton.setText("Iniciar")
        self.applyButton.setEnabled(True)
        return
Beispiel #21
0
  def section_CreateTable(self):
    self.delayDisplay("Create table",self.delayMs)

    # Create sample table node
    tableNode = slicer.vtkMRMLTableNode()
    slicer.mrmlScene.AddNode(tableNode)
    tableNode.SetName(self.sampleTableName)

    # Add a new column
    column = tableNode.AddColumn()
    self.assertTrue( column is not None )
    column.InsertNextValue("some")
    column.InsertNextValue("data")
    column.InsertNextValue("in this")
    column.InsertNextValue("column")
    tableNode.Modified();

    # Check table
    table = tableNode.GetTable()
    self.assertTrue( table is not None )
    self.assertTrue( table.GetNumberOfRows() == 4 )
    self.assertTrue( table.GetNumberOfColumns() == 1 )
  def exportToTable(self):
    """
    Export statistics to table node
    """

    colorNode = self.getColorNode()

    table = slicer.vtkMRMLTableNode()
    tableWasModified = table.StartModify()

    table.SetName(slicer.mrmlScene.GenerateUniqueName(self.nodeBaseName+' statistics'))
    
    # Define table columns
    if colorNode:
      col=table.AddColumn()
      col.SetName("Type")
    for k in self.keys:
      col=table.AddColumn()
      col.SetName(k)
    for i in self.labelStats["Labels"]:
      rowIndex = table.AddEmptyRow()
      if colorNode:
        columnIndex = 0
        table.SetCellText(rowIndex, columnIndex, colorNode.GetColorName(i))
        columnIndex += 1
      # Add other values
      for k in self.keys:
        table.SetCellText(rowIndex, columnIndex, str(self.labelStats[i,k]))
        columnIndex += 1

    table.EndModify(tableWasModified)

    # Add table to the scene and show it
    slicer.mrmlScene.AddNode(table)
    slicer.app.layoutManager().setLayout(slicer.vtkMRMLLayoutNode.SlicerLayoutFourUpTableView)
    slicer.app.applicationLogic().GetSelectionNode().SetReferenceActiveTableID(table.GetID())
    slicer.app.applicationLogic().PropagateTableSelection()
  def exportToTable(self):
    """
    Export statistics to table node
    """

    colorNode = self.getColorNode()

    table = slicer.vtkMRMLTableNode()
    tableWasModified = table.StartModify()

    table.SetName(slicer.mrmlScene.GenerateUniqueName(self.nodeBaseName+' statistics'))
    
    # Define table columns
    if colorNode:
      col=table.AddColumn()
      col.SetName("Type")
    for k in self.keys:
      col=table.AddColumn()
      col.SetName(k)
    for i in self.labelStats["Labels"]:
      rowIndex = table.AddEmptyRow()
      if colorNode:
        columnIndex = 0
        table.SetCellText(rowIndex, columnIndex, colorNode.GetColorName(i))
        columnIndex += 1
      # Add other values
      for k in self.keys:
        table.SetCellText(rowIndex, columnIndex, str(self.labelStats[i,k]))
        columnIndex += 1

    table.EndModify(tableWasModified)

    # Add table to the scene and show it
    slicer.mrmlScene.AddNode(table)
    slicer.app.layoutManager().setLayout(slicer.vtkMRMLLayoutNode.SlicerLayoutFourUpTableView)
    slicer.app.applicationLogic().GetSelectionNode().SetReferenceActiveTableID(table.GetID())
    slicer.app.applicationLogic().PropagateTableSelection()
Beispiel #24
0
  def metadata2vtkTableNode(self, metafile):
    with open(metafile) as datafile:
      table = slicer.vtkMRMLTableNode()
      slicer.mrmlScene.AddNode(table)
      table.SetAttribute("QuantitativeReporting", "Yes")
      table.SetAttribute("readonly", "Yes")
      table.SetUseColumnNameAsColumnHeader(True)

      data = json.load(datafile)

      tableWasModified = table.StartModify()

      measurement = data["Measurements"][0]
      col = table.AddColumn()
      col.SetName("Segment")

      for measurementItem in measurement["measurementItems"]:
        col = table.AddColumn()

        if "derivationModifier" in measurementItem.keys():
          col.SetName(SegmentStatisticsDICOMMeaningMapping.getKeyForValue(measurementItem["derivationModifier"]["CodeMeaning"]))
        else:
          col.SetName(SegmentStatisticsDICOMMeaningMapping.getKeyForValue(measurementItem["quantity"]["CodeMeaning"] +" "+measurementItem["units"]["CodeValue"]))

      for measurement in data["Measurements"]:
        name = measurement["TrackingIdentifier"]
        value = measurement["ReferencedSegment"]
        rowIndex = table.AddEmptyRow()
        table.SetCellText(rowIndex, 0, name)
        for columnIndex, measurementItem in enumerate(measurement["measurementItems"]):
          table.SetCellText(rowIndex, columnIndex+1, measurementItem["value"])

      table.EndModify(tableWasModified)
      slicer.app.applicationLogic().GetSelectionNode().SetReferenceActiveTableID(table.GetID())
      slicer.app.applicationLogic().PropagateTableSelection()
    return table
Beispiel #25
0
    def hausdorffDist(self):

        # Creation of a node for segments comparison
        self.segCompnode = slicer.vtkMRMLSegmentComparisonNode()
        slicer.mrmlScene.AddNode(self.segCompnode)
        slicer.modules.segmentcomparison.logic().SetMRMLScene(slicer.mrmlScene)

        # Loading of the segmentation node and the first segmentation
        self.segCompnode.SetAndObserveReferenceSegmentationNode(self.segment1)
        self.segCompnode.SetReferenceSegmentID(self.segment1.GetName())

        # Loading of the segmentation node and the segmentation of comparison
        self.segCompnode.SetAndObserveCompareSegmentationNode(self.segment2)
        self.segCompnode.SetCompareSegmentID(self.segment2.GetName())

        # Creation and configuration of a table node where the results will be shown
        self.tableH = slicer.vtkMRMLTableNode()
        self.tableH.SetName("Hausdorff Distance")
        slicer.mrmlScene.AddNode(self.tableH)
        self.segCompnode.SetAndObserveHausdorffTableNode(self.tableH)

        # Display Hausdorff Distance Table (3D Table View)
        slicer.app.layoutManager().setLayout(
            slicer.vtkMRMLLayoutNode.SlicerLayout3DTableView)
        slicer.app.applicationLogic().GetSelectionNode(
        ).SetReferenceActiveTableID(self.tableH.GetID())
        slicer.app.applicationLogic().PropagateTableSelection()

        # Calculation of the Hausdorff Distance
        slicer.modules.segmentcomparison.logic().ComputeHausdorffDistances(
            self.segCompnode)

        # Save table in a CSV file
        storagenode = self.tableH.CreateDefaultStorageNode()
        storagenode.SetFileName("hausdorff.csv")
        storagenode.WriteData(self.tableH)
Beispiel #26
0
    def diceCoeff(self):

        # Creation of a node for segments comparison
        self.segCompNode = slicer.vtkMRMLSegmentComparisonNode()
        slicer.mrmlScene.AddNode(self.segCompNode)
        slicer.modules.segmentcomparison.logic().SetMRMLScene(slicer.mrmlScene)

        # Loading of the segmentation node and the first segmentation
        self.segCompNode.SetAndObserveReferenceSegmentationNode(self.segment1)
        self.segCompNode.SetReferenceSegmentID(self.segment1.GetName())

        # Loading of the segmentation node and the segmentation of comparison
        self.segCompNode.SetAndObserveCompareSegmentationNode(self.segment2)
        self.segCompNode.SetCompareSegmentID(self.segment2.GetName())

        # Creation and configuration of a table node where the results will be shown
        self.tableD = slicer.vtkMRMLTableNode()
        self.tableD.SetName("Sorensen-Dice Coefficient")
        slicer.mrmlScene.AddNode(self.tableD)
        self.segCompNode.SetAndObserveDiceTableNode(self.tableD)

        # Display Dice Coefficient Table (3D Table View)
        slicer.app.layoutManager().setLayout(
            slicer.vtkMRMLLayoutNode.SlicerLayout3DTableView)
        slicer.app.applicationLogic().GetSelectionNode(
        ).SetReferenceActiveTableID(self.tableD.GetID())
        slicer.app.applicationLogic().PropagateTableSelection()

        # Calculation of the Dice Index
        slicer.modules.segmentcomparison.logic().ComputeDiceStatistics(
            self.segCompNode)

        # Save table in a CSV file
        storagenode = self.tableD.CreateDefaultStorageNode()
        storagenode.SetFileName("dice.csv")
        storagenode.WriteData(self.tableD)
  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 setup(self):
    ScriptedLoadableModuleWidget.setup(self)

    self.logic = ExtensionStatsLogic()
    self.logic.setStatusCallback(self.setStatusText)

    self.queryInProgress = False

    # Instantiate and connect widgets ...

    #
    # Parameters Area
    #
    parametersCollapsibleButton = ctk.ctkCollapsibleButton()
    parametersCollapsibleButton.text = "Parameters"
    self.layout.addWidget(parametersCollapsibleButton)

    parametersFormLayout = qt.QFormLayout(parametersCollapsibleButton)

    extensionNameBox = qt.QHBoxLayout()

    self.extensionNameEdit = qt.QLineEdit()
    self.extensionNameEdit.setText('')
    extensionNameBox.addWidget(self.extensionNameEdit)

    self.extensionNameAllButton = qt.QPushButton()
    self.extensionNameAllButton.text = "all"
    self.extensionNameAllButton.toolTip = "Get statistics for all extensions"
    extensionNameBox.addWidget(self.extensionNameAllButton)
    self.populateExtensionNameEdit()

    parametersFormLayout.addRow("Extension name: ", extensionNameBox)

    self.applyButton = qt.QPushButton("Get download statistics")
    self.applyButton.toolTip = "Get download statistics"
    parametersFormLayout.addRow(self.applyButton)

    self.statusText = qt.QLabel()
    parametersFormLayout.addRow("Status:", self.statusText)

    # Stats table
    self.statsTableWidget = slicer.qMRMLTableView()
    self.statsTableWidget.setMRMLScene(slicer.mrmlScene)
    parametersFormLayout.addRow("Statistics:", self.statsTableWidget)
    policy = qt.QSizePolicy()
    policy.setVerticalStretch(1)
    policy.setHorizontalPolicy(qt.QSizePolicy.Expanding)
    policy.setVerticalPolicy(qt.QSizePolicy.Expanding)
    self.statsTableWidget.setSizePolicy(policy)

    self.statsTableNode = slicer.vtkMRMLTableNode()
    self.statsTableNode.SetName('ExtensionStats')
    self.statsTableNode.SetUseColumnNameAsColumnHeader(True)
    self.statsTableNode.SetUseFirstColumnAsRowHeader(True)
    slicer.mrmlScene.AddNode(self.statsTableNode)
    self.statsTableWidget.setMRMLTableNode(self.statsTableNode)

    # Copy to clipboard button
    self.copyToClipboardButton = qt.QPushButton("Copy table to clipboard")
    parametersFormLayout.addRow('', self.copyToClipboardButton)

    # connections
    self.extensionNameAllButton.connect('clicked()', self.populateExtensionNameEdit)
    self.applyButton.connect('clicked(bool)', self.onApplyButton)
    self.copyToClipboardButton.connect('clicked()', self.copyTableToClipboard)
Beispiel #29
0
    def onApplyButton(self):
        self.applyButton.setText("Aguarde...")
        self.applyButton.setEnabled(False)
        self.progressBar.setVisible(True)
        inputVolume = self.baseSelector.currentNode()
        cropLogic = slicer.modules.cropvolume.logic()
        volumesLogic = slicer.modules.volumes.logic()
        label = 1
        perc = 0.75
        hasROI = False

        logging.info('Processing started')

        # Criar tabela para os dados
        logging.info('Criando a tabela')
        table = slicer.vtkMRMLTableNode()
        tableWasModified = table.StartModify()
        table.SetName("Export Table")
        table.SetUseColumnNameAsColumnHeader(True)
        col = table.AddColumn()
        col.SetName("Volume")
        col = table.AddColumn()
        col.SetName("Qtde")
        col = table.AddColumn()
        col.SetName("Min-Max")
        col = table.AddColumn()
        col.SetName("Range")

        # Hierarquia para modelos 3D
        modelHNode = slicer.mrmlScene.CreateNodeByClass(
            'vtkMRMLModelHierarchyNode')
        modelHNode.SetName('Models')
        modelHNode = slicer.mrmlScene.AddNode(modelHNode)

        # Atualiza tela
        slicer.app.processEvents()

        # Criando a ROI
        logging.info('Criar ROI a partir do Fiducial')
        for node in slicer.util.getNodesByClass('vtkMRMLAnnotationROINode'):
            ROI = node
            hasROI = True

        if not hasROI:
            ROI = self.createROI()

        # Calculando media do volume inicial
        logging.info('Calcular media volume inicial: ' + inputVolume.GetName())
        arrayInputVolume = slicer.util.array(inputVolume.GetName())
        meanInputVolume = arrayInputVolume.mean()

        # Realizar o crop no primeiro volume
        logging.info('Crop do volume inicial')
        outputVolume = slicer.mrmlScene.AddNewNodeByClass(
            "vtkMRMLScalarVolumeNode",
            inputVolume.GetName() + ' cropped')
        cropLogic.CropInterpolated(ROI, inputVolume, outputVolume, False, 1.0,
                                   2, 0)

        # Calculo dos pontos mais intensos do primeiro volume
        logging.info("Calculando pontos mais intensos do volume inicial")
        arrayNode = slicer.util.array(outputVolume.GetName())
        min = arrayNode.min()
        max = arrayNode.max()
        minValue = max - ((max - min) * perc)
        arrayValue = arrayNode[arrayNode >= minValue]
        meanValue = arrayValue.mean()
        countValue = len(arrayValue)

        # Atualiza tela
        slicer.app.processEvents()

        #segmentando o primeiro volume
        logging.info('Segmentando volume inicial')
        labelMap = volumesLogic.CreateAndAddLabelVolume(
            slicer.mrmlScene, outputVolume,
            outputVolume.GetName() + '-label')
        labelArray = slicer.util.array(labelMap.GetName())
        labelArray[arrayNode > minValue] = label
        labelMap.GetImageData().Modified()
        inputLabelMap = labelMap

        # Apagando o volume cropped
        slicer.mrmlScene.RemoveNode(outputVolume)

        # Criar modelo 3D
        logging.info('Criar modelo 3D do volume inicial')
        parameters = {}
        parameters["InputVolume"] = labelMap.GetID()
        parameters["Name"] = labelMap.GetName() + '-model'
        parameters['ModelSceneFile'] = modelHNode.GetID()
        modelMaker = slicer.modules.modelmaker
        slicer.cli.run(modelMaker, None, parameters, True)

        # Atualiza tela
        slicer.app.processEvents()

        # Popular tabela com os dados do primeiro volume
        logging.info('Popular tabela')
        rowIndex = table.AddEmptyRow()
        table.SetCellText(rowIndex, 0, inputVolume.GetName())
        table.SetCellText(rowIndex, 1, str(countValue))
        table.SetCellText(rowIndex, 2, str(int(min)) + " - " + str(int(max)))
        table.SetCellText(rowIndex, 3,
                          str(int(minValue)) + " - " + str(int(max)))

        # Atualiza tela
        slicer.app.processEvents()

        # Identificar todos os volumes e processar
        for node in slicer.util.getNodesByClass('vtkMRMLScalarVolumeNode'):
            logging.info('\nProcessando ' + node.GetName())
            if node.GetName() == inputVolume.GetName():
                logging.info('Ignorando volume: ' + node.GetName())
                continue
            if node.GetClassName() == "vtkMRMLLabelMapVolumeNode":
                logging.info('Ignorando label: ' + node.GetName())
                continue

            # Executar BrainsFit para corresgistro dos exames mais novos com o mais antigo
            logging.info('Registrando o volume')
            fixedVolume = inputVolume
            movingVolume = node
            registeredVolume = slicer.mrmlScene.AddNewNodeByClass(
                "vtkMRMLScalarVolumeNode",
                node.GetName() + ' Reg')
            brainsfitParameters = {
                'fixedVolume': fixedVolume.GetID(),
                'movingVolume': movingVolume.GetID(),
                'outputVolume': registeredVolume.GetID(),
                'useRigid': True
            }
            self.cliNode = slicer.cli.run(slicer.modules.brainsfit, None,
                                          brainsfitParameters)

            while (self.cliNode.IsBusy()):
                slicer.app.processEvents()

            # Normalizar volumes
            logging.info('Normalizando o volume')
            arrayRegisteredVolume = slicer.util.array(
                registeredVolume.GetName())
            meanRegisteredVolume = arrayRegisteredVolume.mean()
            factor = meanRegisteredVolume / meanInputVolume
            arrayRegisteredVolume[:] = arrayRegisteredVolume / factor
            arrayRegisteredVolume[:] = numpy.around(arrayRegisteredVolume, 0)

            # Crop Interpolated
            logging.info('Crop do volume')
            outputVolume = slicer.mrmlScene.AddNewNodeByClass(
                "vtkMRMLScalarVolumeNode",
                registeredVolume.GetName() + ' cropped')
            cropLogic.CropInterpolated(ROI, registeredVolume, outputVolume,
                                       False, 1.0, 2, 0)

            # Calculo dos pontos mais intensos do volume corregistrado
            print("Calculando")
            arrayNode = slicer.util.array(outputVolume.GetName())
            arrayNode[:] = numpy.around(arrayNode, 0)
            min = arrayNode.min()
            max = arrayNode.max()
            minValue = max - ((max - min) * perc)
            arrayValue = arrayNode[arrayNode >= minValue]
            meanValue = arrayValue.mean()
            countValue = len(arrayValue)

            # Atualiza tela
            slicer.app.processEvents()

            #segmentando o volume
            logging.info('Segmentando Volume')
            label = label + 1
            labelMap = volumesLogic.CreateAndAddLabelVolume(
                slicer.mrmlScene, outputVolume,
                outputVolume.GetName() + '-label')
            labelArray = slicer.util.array(labelMap.GetName())
            labelArray[arrayNode > minValue] = label
            labelMap.GetImageData().Modified()

            # Apagando o volume cropped
            slicer.mrmlScene.RemoveNode(outputVolume)

            # Criar modelo 3D
            logging.info('Criar Modelo 3D')
            parameters = {}
            parameters["InputVolume"] = labelMap.GetID()
            parameters["Name"] = labelMap.GetName() + '-model'
            parameters['ModelSceneFile'] = modelHNode.GetID()
            modelMaker = slicer.modules.modelmaker
            slicer.cli.run(modelMaker, None, parameters, True)

            # Atualiza tela
            slicer.app.processEvents()

            # Popular tabela com os dados
            logging.info('Popular tabela')
            rowIndex = table.AddEmptyRow()
            table.SetCellText(rowIndex, 0, node.GetName())
            table.SetCellText(rowIndex, 1, str(countValue))
            table.SetCellText(rowIndex, 2,
                              str(int(min)) + " - " + str(int(max)))
            table.SetCellText(rowIndex, 3,
                              str(int(minValue)) + " - " + str(int(max)))
            rowIndex += 1

        # Exibir o resultado
        logging.info('Exibir resultado')
        for color in ['Red', 'Yellow', 'Green']:
            slicer.app.layoutManager().sliceWidget(color).sliceLogic(
            ).GetSliceCompositeNode().SetBackgroundVolumeID(
                inputVolume.GetID())
            slicer.app.layoutManager().sliceWidget(
                color).sliceLogic().GetSliceCompositeNode().SetLabelVolumeID(
                    inputLabelMap.GetID())

        # Add table to the scene and show it
        logging.info('Adicionar tabela e exibir')
        slicer.mrmlScene.AddNode(table)
        slicer.app.layoutManager().setLayout(
            slicer.vtkMRMLLayoutNode.SlicerLayoutFourUpTableView)
        slicer.app.applicationLogic().GetSelectionNode(
        ).SetReferenceActiveTableID(table.GetID())
        slicer.app.applicationLogic().PropagateTableSelection()
        table.EndModify(tableWasModified)

        # Atualiza tela
        slicer.app.processEvents()

        logging.info('Processing completed')

        self.applyButton.setText("Iniciar")
        self.applyButton.setEnabled(True)
        self.progressBar.setVisible(False)

        return
    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_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 test_SlicerRadiomics1(self):
    """ Ideally you should have several levels of tests.  At the lowest level
    tests should exercise the functionality of the logic with different inputs
    (both valid and invalid).  At higher levels your tests should emulate the
    way the user would interact with your code and confirm that it still works
    the way you intended.
    One of the most important features of the tests is that it should alert other
    developers when their changes will have an impact on the behavior of your
    module.  For example, if a developer removes a feature that you depend on,
    your test should break so they know that the feature is needed.
    """

    self.delayDisplay('Starting the test')
    #
    # first, get some data
    # https://github.com/Radiomics/SlicerRadiomics/releases/download/TestData-v1.0.0/lung1_binary.seg.nrrd
    import urllib
    dataRelease = 'v1.0.0'
    dataURLPrefix = 'https://github.com/Radiomics/SlicerRadiomics/releases/download/TestData'
    dataItems = (('lung1_image.nrrd', slicer.util.loadVolume),
                 ('lung1_label.nrrd', slicer.util.loadLabelVolume),
                 ('lung1_binary.seg.nrrd', slicer.util.loadSegmentation),
                 ('lung1.seg_0.vtp', None),
                 ('lung1.seg_1.vtp', None),
                 ('lung1_surface.seg.vtm', slicer.util.loadSegmentation),
                 ('Params.yaml', None))

    for item, loader in dataItems:
      url = dataURLPrefix + '-' + dataRelease + '/' + item
      filePath = os.path.join(slicer.app.temporaryPath, item)
      if not os.path.exists(filePath) or os.stat(filePath).st_size == 0:
        self.logger.info('Requesting download %s from %s...\n' % (item, url))
        self.assertTrue(urllib.urlretrieve(url, filePath), 'Failed to download from ' + url)
      if loader:
        self.logger.info('Loading %s from %s...' % (item, filePath))
        self.assertTrue(loader(filePath), 'Failed to load ' + item)

    self.delayDisplay(
      'Finished with download and loading %d volumes' % (slicer.mrmlScene.GetNumberOfNodesByClass('vtkMRMLVolumeNode')))

    grayscaleNode = slicer.util.getNode(pattern='lung1_image')
    labelmapNode = slicer.util.getNode(pattern='lung1_label')
    binaryNode = slicer.util.getNode(pattern='lung1_binary')
    surfaceNode = slicer.util.getNode(pattern='lung1_surface')

    parameterFile = os.path.join(slicer.app.temporaryPath, 'Params.yaml')

    logic = SlicerRadiomicsLogic()
    logic.runSync = True  # Block Thread until each extraction is done (i.e. run synchronously)
    self.assertIsNotNone(logic.hasImageData(grayscaleNode))
    self.assertIsNotNone(logic.hasImageData(labelmapNode))

    featureClasses = ['firstorder']
    settings = {}
    settings['binWidth'] = 25
    settings['symmetricalGLCM'] = False
    settings['label'] = 1
    settings['correctMask'] = True

    enabledImageTypes = {"Original": {}}

    for maskNode in [labelmapNode, binaryNode, surfaceNode]:
      tableNode = slicer.vtkMRMLTableNode()
      tableNode.SetName('lung1_label and ' + maskNode.GetName())
      slicer.mrmlScene.AddNode(tableNode)
      # No callback needed as tests are run synchronously
      logic.runCLI(grayscaleNode, maskNode, tableNode, featureClasses, settings, enabledImageTypes)
      logic.showTable(tableNode)

    for maskNode in [labelmapNode, binaryNode, surfaceNode]:
      tableNode = slicer.vtkMRMLTableNode()
      tableNode.SetName('lung1_label and ' + maskNode.GetName() + ' customized with Params.yaml')
      slicer.mrmlScene.AddNode(tableNode)
      # No callback needed as tests are run synchronously
      logic.runCLIWithParameterFile(grayscaleNode, maskNode, tableNode, parameterFile)
      logic.showTable(tableNode)

    self.delayDisplay('Test passed!')
  def onApplyButton(self):
    if not self.outputTableSelector.currentNode():
      tableNode = slicer.vtkMRMLTableNode()
      slicer.mrmlScene.AddNode(tableNode)
      self.outputTableSelector.setCurrentNode(tableNode)

    logic = SlicerRadiomicsLogic()

    # Lock GUI
    self.applyButton.text = 'Working...'
    self.applyButton.setEnabled(False)
    slicer.app.processEvents()

    imageNode = self.inputVolumeSelector.currentNode()
    maskNode = self.inputMaskSelector.currentNode()

    if self.manualCustomizationRadioButton.checked:
      # Set up customization
      featureClasses = self.getCheckedFeatureClasses()
      settings = {}
      settings['binWidth'] = self.binWidthSliderWidget.value
      settings['symmetricalGLCM'] = self.symmetricalGLCMCheckBox.checked

      enabledImageTypes = {'Original': {}}

      logKernelSizesValue = self.logKernelSizes.text
      if logKernelSizesValue:
        try:
          enabledImageTypes['LoG'] = {'sigma': [float(i) for i in logKernelSizesValue.split(',')]}
        except:
          self.logger.error('Failed to parse LoG sigma value from string \"' + logKernelSizesValue + '\"')
          traceback.print_exc()
          return

      resampledVoxelSizeValue = self.resampledVoxelSize.text
      if resampledVoxelSizeValue:
        try:
          settings['resampledPixelSpacing'] = [float(i) for i in resampledVoxelSizeValue.split(',')]
        except:
          self.logger.error('Failed to parse resampled voxel spacing from string \"' + resampledVoxelSizeValue + '\"')
          settings['resampledPixelSpacing'] = None
          traceback.print_exc()
          return

      if self.waveletCheckBox.checked:
        enabledImageTypes['Wavelet'] = {}

      # Compute features
      try:
        logic.runCLI(imageNode,
                     maskNode,
                     self.outputTableSelector.currentNode(),
                     featureClasses,
                     settings,
                     enabledImageTypes,
                     self.onFinished)
      except:
        self.logger.error("Feature calculation failed.")
        traceback.print_exc()

    else:
      # Compute Features
      try:
        parameterFile = self.parameterFilePathLineEdit.currentPath
        logic.runCLIWithParameterFile(imageNode,
                                      maskNode,
                                      self.outputTableSelector.currentNode(),
                                      parameterFile,
                                      self.onFinished)
      except:
        self.logger.error("Feature calculation failed.")
        traceback.print_exc()

    logic.showTable(self.outputTableSelector.currentNode())
Beispiel #34
0
    def onApplyButton(self):
        if self.verboseCheckBox.checked:
            # Setup debug logging for the pyradiomics toolbox
            # PyRadiomics logs to stderr by default, which is picked up by slicer and added to the slicer log.
            setVerbosity(logging.DEBUG)
        else:
            setVerbosity(logging.WARNING)

        if not self.outputTableSelector.currentNode():
            tableNode = slicer.vtkMRMLTableNode()
            slicer.mrmlScene.AddNode(tableNode)
            self.outputTableSelector.setCurrentNode(tableNode)

        logic = SlicerRadiomicsLogic()

        # Lock GUI
        self.applyButton.text = 'Working...'
        self.applyButton.setEnabled(False)
        slicer.app.processEvents()

        imageNode = self.inputVolumeSelector.currentNode()
        labelNode = self.inputMaskSelector.currentNode()
        segmentationNode = self.inputSegmentationSelector.currentNode()

        if self.manualCustomizationRadioButton.checked:
            # Set up customization
            featureClasses = self.getCheckedFeatureClasses()
            settings = {}
            settings['binWidth'] = self.binWidthSliderWidget.value
            settings['symmetricalGLCM'] = self.symmetricalGLCMCheckBox.checked

            enabledImageTypes = {'Original': {}}

            logKernelSizesValue = self.logKernelSizes.text
            if logKernelSizesValue:
                try:
                    enabledImageTypes['LoG'] = {
                        'sigma':
                        [float(i) for i in logKernelSizesValue.split(',')]
                    }
                except:
                    self.logger.error(
                        'Failed to parse LoG sigma value from string \"' +
                        logKernelSizesValue + '\"')
                    traceback.print_exc()
                    return

            resampledVoxelSizeValue = self.resampledVoxelSize.text
            if resampledVoxelSizeValue:
                try:
                    settings['resampledPixelSpacing'] = [
                        float(i) for i in resampledVoxelSizeValue.split(',')
                    ]
                except:
                    self.logger.error(
                        'Failed to parse resampled voxel spacing from string \"'
                        + resampledVoxelSizeValue + '\"')
                    settings['resampledPixelSpacing'] = None
                    traceback.print_exc()
                    return

            if self.waveletCheckBox.checked:
                enabledImageTypes['Wavelet'] = {}

            # Compute features
            try:
                featuresDict = logic.run(imageNode, labelNode,
                                         segmentationNode, featureClasses,
                                         settings, enabledImageTypes)
                logic.exportToTable(featuresDict,
                                    self.outputTableSelector.currentNode())
            except:
                self.logger.error("Feature calculation failed.")
                traceback.print_exc()

        else:
            # Compute Features
            try:
                parameterFile = self.parameterFilePathLineEdit.currentPath
                featuresDict = logic.runWithParameterFile(
                    imageNode, labelNode, segmentationNode, parameterFile)
                logic.exportToTable(featuresDict,
                                    self.outputTableSelector.currentNode())
            except:
                self.logger.error("Feature calculation failed.")
                traceback.print_exc()

        # Unlock GUI
        self.applyButton.setEnabled(True)
        self.applyButton.text = 'Apply'

        # Show results
        logic.showTable(self.outputTableSelector.currentNode())
  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')
Beispiel #36
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!')
Beispiel #37
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 compareToManualSeg(self, tip, tail, manSegPoints, insertAngle):
        # get manually selected point
        manualTip = [0.0, 0.0, 0.0]
        manSegPoints.GetNthFiducialPosition(0, manualTip)
        # manualTipString = "{0:.10} {1:.10} {2:.10}".format(manualTip[0], manualTip[1], manualTip[2])
        # print("manual tip: " + manualTipString)

        # calculate the distance between needle tips
        tipError = numpy.sqrt((tip[0] - manualTip[0])**2 +
                              (tip[1] - manualTip[1])**2 +
                              (tip[2] - manualTip[2])**2)
        tipErrorString = "{0:.10}".format(tipError)
        print("Tip error is " + tipErrorString + " mm.")

        # calculate the directional vectors for the algorithm and manual segmentations
        algoVector = [a - b for a, b in zip(tip, tail)]
        manualVector = [a - b for a, b in zip(manualTip, tail)]

        # normalize the vectors
        algoLength = numpy.sqrt(algoVector[0]**2 + algoVector[1]**2 +
                                algoVector[2]**2)
        manualLength = numpy.sqrt(manualVector[0]**2 + manualVector[1]**2 +
                                  manualVector[2]**2)
        algoVector = [a / algoLength for a in algoVector]
        manualVector = [a / manualLength for a in manualVector]

        # calculate the dot product and compute the trajectory difference
        dotProduct = numpy.dot(algoVector, manualVector)
        trajError = numpy.arccos(dotProduct)
        trajError = numpy.degrees(trajError)
        trajErrorString = "{0:.10}".format(trajError)
        print("Trajectory error is " + trajErrorString + " degrees.")

        # calculate the active tip error
        algoActTip = [a * 10 for a in algoVector]
        algoActTip = [a - b for a, b in zip(tip, algoActTip)]
        manualActTip = [a * 10 for a in manualVector]
        manualActTip = [a - b for a, b in zip(manualTip, manualActTip)]
        actTipError = numpy.sqrt((algoActTip[0] - manualActTip[0])**2 +
                                 (algoActTip[1] - manualActTip[1])**2 +
                                 (algoActTip[2] - manualActTip[2])**2)
        actTipErrorString = "{0:.10}".format(actTipError)
        print("Active tip error is " + actTipErrorString + " mm.")

        # calculate the difference from expected insertion angle
        insertString = "{0:.10}".format(insertAngle)
        print("Expected insertion angle is " + insertString + " degrees.")

        # calculate insertion angle of algorithmically segmented needle
        dotProduct = -1 * algoVector[1]
        algoAngle = numpy.arccos(dotProduct)
        algoAngle = numpy.degrees(algoAngle)
        algoAngleString = "{0:.10}".format(algoAngle)
        print("Segmented insertion angle is " + algoAngleString + " degrees.")

        # calculate insertion angle error
        angleDiff = numpy.absolute(insertAngle - algoAngle)
        angleDiffString = "{0:.10}".format(angleDiff)
        print("Insertion angle difference is " + angleDiffString + " degrees.")

        # check if a metrics table has already been created
        if not slicer.util.getNode('Metrics'):
            tableNode = slicer.vtkMRMLTableNode()
            tableNode.SetName('Metrics')
            col = tableNode.AddColumn()
            col.SetName('Tip Difference (mm)')
            col = tableNode.AddColumn()
            col.SetName('Active Tip Difference (mm)')
            col = tableNode.AddColumn()
            col.SetName('Trajectory Difference (deg)')
            col = tableNode.AddColumn()
            col.SetName('Segmented Insertion Angle (deg)')
            col = tableNode.AddColumn()
            col.SetName('Insertion Angle Difference (deg)')
            slicer.mrmlScene.AddNode(tableNode)
        else:
            tableNode = slicer.util.getNode('Metrics')

        # populates a table with the metrics values
        tableNode.AddEmptyRow()
        row = tableNode.GetNumberOfRows() - 1
        tableNode.SetCellText(row, 0, tipErrorString)
        tableNode.SetCellText(row, 1, actTipErrorString)
        tableNode.SetCellText(row, 2, trajErrorString)
        tableNode.SetCellText(row, 3, algoAngleString)
        tableNode.SetCellText(row, 4, angleDiffString)