Displaying Segments of a Specific Segmentation in the qMRMLSegmentsTableView

Hello Dear Developers and Users,

I used the answers given to a question titled Input segments in new module to help me write the following lines of code.

import os
import unittest
from __main__ import vtk, qt, ctk, slicer
from slicer.ScriptedLoadableModule import *

#
# SegmentationSelector
#

class SegmentationSelector(ScriptedLoadableModule):
  
  def __init__(self, parent):
    ScriptedLoadableModule.__init__(self, parent)
    self.parent.title = "SegmentationSelector" # TODO make this more human readable by adding spaces
    self.parent.categories = ["Examples"]
    self.parent.dependencies = []
    self.parent.contributors = ["John Doe (AnyWare Corp.)"] # replace with "Firstname Lastname (Organization)"

#
# SegmentationSelectorWidget
#

class SegmentationSelectorWidget(ScriptedLoadableModuleWidget):

  def setup(self):
    ScriptedLoadableModuleWidget.setup(self)
    # Instantiate and connect widgets ...

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

    # Layout within the dummy collapsible button
    parametersFormLayout = qt.QFormLayout(parametersCollapsibleButton)

    ### Start (Segment node selection)
    # Create a qMRMLSegmentSelectorWidget for selecting the Segmentation node
    self.inputSelector1 = slicer.qMRMLSegmentSelectorWidget()
    self.inputSelector1.setMRMLScene(slicer.mrmlScene)
    self.inputSelector1.setToolTip("Pick the input to the algorithm.")
    parametersFormLayout.addRow("Segmentation: ", self.inputSelector1)
    
    # Segment table view setup
    self.inputSelector2 = slicer.qMRMLSegmentsTableView()
    self.inputSelector2.setMRMLScene(slicer.mrmlScene)
    self.inputSelector2.setToolTip("Pick the segments to view.")
    # Add the table view to the layout
    parametersFormLayout.addRow("Segments Table: ", self.inputSelector2)    
    self.inputSelector2.show()

As you can see in the image below,

after selecting my desired Segmentation, in the Segment list I can see the list of Segments that are in the Segmentation node, but the Segments Table is empty.
How can I create this connection? It seems like there should be a connection between the qMRMLSegmentSelectorWidget and qMRMLSegmentsTableView.

Please guide me.
Best regards.
Shahrokh

Sorry… my problem is solved. The lines I added are these:

    # Segment table view setup
...
    self.inputSelector2.setSegmentationNode(self.inputSelector1.currentNode())
    self.inputSelector2.show()
    ...

As seen in the image below, I can observe the list of Segments in the Segmentation.

Next, I want to select one of these Segments from the table to perform some further processing on it.

Shahrokh

As shown in the image above, I can now see the table containing the Segments in a Segmentation within a module called SegmentationSelector.

Next, I was able to select one of the Segments from the visible table and retrieve its ID using the selectedSegmentIDs function for further processing. I was able to accomplish this in the 3D Slicer Python Interactor with the following commands.

seg=slicer.qMRMLSegmentSelectorWidget()
seg.setMRMLScene(slicer.mrmlScene)
seg.setToolTip("Pick the input to the algorithm.")
table=slicer.qMRMLSegmentsTableView()
table.setMRMLScene(slicer.mrmlScene)
table.setToolTip("Pick the segments to view.")
table.setSegmentationNode(seg.currentNode())
table.show()
table.selectedSegmentIDs()

Screenshot of the result of the above commands:

Now, I would like to have the same functionality in my module, SegmentationSelector. In other words, as shown in the image below, I want to select one of the segments from the Segments Table. Can you guide me on how to do this?

Please guide me.
Best regards.
Shahrokh.

I saw something similar to what I want in the Segment Comparison module. Perhaps there is no need for qMRMLSegmentsTableView. But how can I be sure that when selecting one of the segments from the Segment Table, that segment is actually selected? I modified my module’s code as follows:

    ### Start (Segment node selection)
    # Create a qMRMLSegmentSelectorWidget for selecting the Segmentation node
    self.inputSelector1 = slicer.qMRMLSegmentSelectorWidget()
    #self.inputSelector1.nodeTypes = (("vtkSegmentation"), "")
    #self.inputSelector1.selectNodeUponCreation = True
    #self.inputSelector1.addEnabled = False
    #self.inputSelector1.removeEnabled = False
    #self.inputSelector1.noneEnabled = False
    #self.inputSelector1.showHidden = False
    #self.inputSelector1.showChildNodeTypes = False
    self.inputSelector1.setMRMLScene(slicer.mrmlScene)
    self.inputSelector1.setToolTip("Pick the input to the algorithm.")
    parametersFormLayout.addRow("Segmentation: ", self.inputSelector1)
    # Print sement selected
    self.inputSelector1.selectedSegmentIDs()
    print("Segment selected: ", self.inputSelector1.selectedSegmentIDs())

However, as shown in the following figure, the output of the print statement is empty.

I expected the output of the print statement to be PTV1. In other words, when I select a segment from the list, for example PTV1, I want to use its ID for subsequent processing in the next widgets.
Please guide me.
Best regards.
Shahrokh

I must apologize for asking my question again. I tried to select one of the Segments available in a node of the type Segmentation. It is like the Segment Comparison module, but unfortunately, I couldn’t succeed. The code I have written so far includes the following lines:

import os
import unittest
from __main__ import vtk, qt, ctk, slicer
from slicer.ScriptedLoadableModule import *
import logging

#
# SegmentationSelector
#

class SegmentationSelector(ScriptedLoadableModule):
  
  def __init__(self, parent):
    ScriptedLoadableModule.__init__(self, parent)
    self.parent.title = "SegmentationSelector" # TODO make this more human readable by adding spaces
    self.parent.categories = ["Examples"]
    self.parent.dependencies = []
    self.parent.contributors = ["John Doe (AnyWare Corp.)"] # replace with "Firstname Lastname (Organization)"

#
# SegmentationSelectorWidget
#

class SegmentationSelectorWidget(ScriptedLoadableModuleWidget):

  def setup(self):
    ScriptedLoadableModuleWidget.setup(self)
    # Instantiate and connect widgets ...

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

    # Layout within the dummy collapsible button
    parametersFormLayout = qt.QFormLayout(parametersCollapsibleButton)

    #
    # input volume selector
    #
    self.inputSelector0 = slicer.qMRMLNodeComboBox()
    self.inputSelector0.nodeTypes = ["vtkMRMLScalarVolumeNode"]
    self.inputSelector0.selectNodeUponCreation = True
    self.inputSelector0.addEnabled = False
    self.inputSelector0.removeEnabled = False
    self.inputSelector0.noneEnabled = False
    self.inputSelector0.showHidden = False
    self.inputSelector0.showChildNodeTypes = False
    self.inputSelector0.setMRMLScene( slicer.mrmlScene )
    self.inputSelector0.setToolTip( "Pick the input to the algorithm." )
    parametersFormLayout.addRow("Input Volume: ", self.inputSelector0)

    #
    # Select Segment node
    #
    self.inputSelector1 = slicer.qMRMLSegmentSelectorWidget()
    self.inputSelector1.setMRMLScene(slicer.mrmlScene)
    self.inputSelector1.setToolTip("Pick the input to the algorithm.")
    parametersFormLayout.addRow("Segmentation: ", self.inputSelector1)
    self.inputSelector1.selectedSegmentIDs()
    
    #
    # Apply Button
    #
    self.applyButton = qt.QPushButton("Apply")
    self.applyButton.toolTip = "Run the algorithm."
    self.applyButton.enabled = True
    parametersFormLayout.addRow(self.applyButton)

    # connections
    self.applyButton.connect('clicked(bool)', self.onApplyButton)
    self.inputSelector1.connect("currentNodeChanged(vtkMRMLNode*)", self.onSelect)

    # Refresh Apply button state
    self.onSelect()

  def cleanup(self):
    pass

  def onSelect(self):
    self.applyButton.enabled = self.inputSelector1.currentNode()

  def onApplyButton(self):
    logic = SegmentationSelectorLogic()
    logic.run(self.inputSelector1.currentNode())

#
# SegmentationSelectorLogic
#

class SegmentationSelectorLogic(ScriptedLoadableModuleLogic):
  def run(self, inputVolume):
    """
    Run the actual algorithm
    """
    print("Segment selected: ", type(inputVolume))
    return True

I referred to the Slicer: qMRMLSegmentSelectorWidget Class Reference, but unfortunately, I couldn’t find a method that allows me to connect a segment selected from the combobox of the qMRMLSegmentSelectorWidget to the Apply pushbutton. Also, I couldn’t find the Python code for the Segment Comparison module, which I could use as a base for my code. I also read the PDF file titled Programming tutorial for 3D Slicer, which was very useful, and I was able to implement the code up to this point. If possible, could you guide me on how I can complete this code?

Please guide me.
Best regards.
Shahrokh

It’s good that you keep working on this and I’m sure you will get it sorted out.

Regarding qMRMLSegmentSelectorWidget, here’s a snippet showing how it’s supposed to work. If it’s not working this way in your module, then experimenting in the python console like this can help.

>>> w = slicer.qMRMLSegmentSelectorWidget()
>>> w.setMRMLScene(slicer.mrmlScene)
>>> w.show()
>>> w.currentNode()
<MRMLCorePython.vtkMRMLSegmentationNode(0x7fb7b2b5c660) at 0x1b0dccb80>
>>>w.currentSegmentID()
'Segment_1_3'

If you run into behavior that doesn’t make sense to you, post small, easy to replicate snippets like this so it’s easy for people to answer without reading through all your code.

Thank you very much for your suggestion. I will follow the suggestion you mentioned and post small, easy-to-replicate snippets like this to make it easier to answer without having to read through all of my code.

Thank you so much for your guidance. I realized that my mistake was in the onSelect function. The return value of this function should be of type vtkMRMLSegmentationNode.

Based on this, the corrected code will be as follows:


def onSelect(self):
self.inputSelector1.currentNode()
print("Output onSelect fun: ", type(self.inputSelector1.currentNode()))

By selecting any of the segments from the ComboBox Segment list and then clicking Apply, I can see the result in the Python Interactor.

‌Best regards.
Shahrokh