Пример #1
0
class HelperBox(VTKObservationMixin):

    mergeValidCommand = _map_property(lambda self: self.structureListWidget, "mergeValidCommand")

    # Backward compatibility
    structures = _map_property(lambda self: self.structureListWidget, "structures")

    def __init__(self, parent=None):
        VTKObservationMixin.__init__(self)

        self.editUtil = EditUtil()  # Kept for backward compatibility

        # mrml volume node instances
        self.master = None
        self.masterWhenMergeWasSet = None
        # Editor color LUT
        self.colorNodeID = None
        # string
        self.createMergeOptions = ""
        self.mergeVolumePostfix = "-label"
        # slicer helper class
        self.volumesLogic = slicer.modules.volumes.logic()
        # widgets that are dynamically created on demand
        # pseudo signals
        # - python callable that gets True or False
        self.selectCommand = None

        if not parent:
            self.parent = slicer.qMRMLWidget()
            self.parent.setLayout(qt.QVBoxLayout())
            self.parent.setMRMLScene(slicer.mrmlScene)
            self.create()
            self.parent.show()
        else:
            self.parent = parent
            self.create()

    def onEnter(self):

        self.addObserver(
            slicer.mrmlScene, slicer.vtkMRMLScene.NodeAddedEvent, self.structureListWidget.updateStructures
        )

        self.addObserver(
            slicer.mrmlScene, slicer.vtkMRMLScene.NodeRemovedEvent, self.structureListWidget.updateStructures
        )

    def onExit(self):
        self.removeObservers(method=self.structureListWidget.updateStructures)

    def cleanup(self):
        self.onExit()
        self.structureListWidget.cleanup()

    @property
    def merge(self):
        return self.mergeSelector.currentNode()

    @merge.setter
    def merge(self, node):
        self.mergeSelector.setCurrentNode(node)

    def newMerge(self):
        """create a merge volume for the current master even if one exists"""
        self.createMergeOptions = "new"
        self.labelCreateDialog()

    def createMerge(self):
        """create a merge volume for the current master"""
        if not self.master:
            # should never happen
            slicer.util.errorDisplay("Cannot create merge volume without master")

        masterName = self.master.GetName()
        mergeName = masterName + self.mergeVolumePostfix
        if self.createMergeOptions.find("new") >= 0:
            merge = None
        else:
            merge = self.mergeVolume()
        self.createMergeOptions = ""

        if not merge:
            merge = self.volumesLogic.CreateAndAddLabelVolume(slicer.mrmlScene, self.master, mergeName)
            merge.GetDisplayNode().SetAndObserveColorNodeID(self.colorNodeID)
            self.setMergeVolume(merge)
        self.select(mergeVolume=merge)

    def select(self, masterVolume=None, mergeVolume=None):
        """select master volume - load merge volume if one with the correct name exists"""

        if masterVolume == None:
            masterVolume = self.masterSelector.currentNode()
        self.master = masterVolume

        self.masterSelector.blockSignals(True)
        self.masterSelector.setCurrentNode(self.master)
        self.masterSelector.blockSignals(False)

        self.mergeSelector.setCurrentNode(mergeVolume)

        if self.master and not self.mergeVolume():
            # the master exists, but there is no merge volume yet
            # bring up dialog to create a merge with a user-selected color node
            self.labelCreateDialog()

        merge = self.mergeVolume()
        if merge:
            if not merge.IsA("vtkMRMLLabelMapVolumeNode"):
                slicer.util.errorDisplay("Error: selected merge label volume is not a label volume")
            else:
                EditUtil.setActiveVolumes(self.master, merge)
                self.mergeSelector.setCurrentNode(merge)

        self.structureListWidget.master = self.master
        self.structureListWidget.merge = merge
        self.structureListWidget.updateStructures()

        if self.master and merge:
            warnings = self.volumesLogic.CheckForLabelVolumeValidity(self.master, merge)
            if warnings != "":
                warnings = "Geometry of master and merge volumes do not match.\n\n" + warnings
                slicer.util.errorDisplay("Warning: %s" % warnings)

        # trigger a modified event on the parameter node so that other parts of the GUI
        # (such as the EditColor) will know to update and enable themselves
        EditUtil.getParameterNode().Modified()

        if self.selectCommand:
            self.selectCommand()

    def setVolumes(self, masterVolume, mergeVolume):
        """set both volumes at the same time - trick the callback into
    thinking that the merge volume is already set so it won't prompt for a new one"""
        self.masterWhenMergeWasSet = masterVolume
        self.select(masterVolume=masterVolume, mergeVolume=mergeVolume)

    def setMasterVolume(self, masterVolume):
        """select merge volume"""
        if isinstance(masterVolume, basestring):
            masterVolume = slicer.mrmlScene.GetNodeByID(masterVolume)
        self.masterSelector.setCurrentNode(masterVolume)

    def setMergeVolume(self, mergeVolume=None):
        """select merge volume"""
        if isinstance(mergeVolume, basestring):
            mergeVolume = slicer.mrmlScene.GetNodeByID(mergeVolume)
        if self.master:
            self.masterWhenMergeWasSet = self.master
            self.select(masterVolume=self.master, mergeVolume=mergeVolume)

    def mergeVolume(self):
        """select merge volume"""
        if not self.master:
            return None

        # if we already have a merge and the master hasn't changed, use it
        if self.mergeSelector.currentNode() and self.master == self.masterWhenMergeWasSet:
            return self.mergeSelector.currentNode()

        self.masterWhenMergeWasSet = None

        # otherwise pick the merge based on the master name
        # - either return the merge volume or empty string
        masterName = self.master.GetName()
        mergeName = masterName + self.mergeVolumePostfix
        merge = slicer.util.getFirstNodeByName(mergeName, className=self.master.GetClassName())
        self.mergeSelector.setCurrentNode(merge)
        return self.mergeSelector.currentNode()

    #
    # callback helpers (slots)
    #
    def onSelect(self, node):
        self.select()

    def onMergeSelect(self, node):
        self.select(mergeVolume=node)

    def create(self):
        """create the segmentation helper box"""

        #
        # Master Frame
        #
        self.masterFrame = qt.QFrame(self.parent)
        self.masterFrame.setLayout(qt.QVBoxLayout())
        self.parent.layout().addWidget(self.masterFrame)

        #
        # the master volume selector
        #
        self.masterSelectorFrame = qt.QFrame(self.parent)
        self.masterSelectorFrame.objectName = "MasterVolumeFrame"
        self.masterSelectorFrame.setLayout(qt.QHBoxLayout())
        self.masterFrame.layout().addWidget(self.masterSelectorFrame)

        self.masterSelectorLabel = qt.QLabel("Master Volume: ", self.masterSelectorFrame)
        self.masterSelectorLabel.setToolTip("Select the master volume (background grayscale scalar volume node)")
        self.masterSelectorFrame.layout().addWidget(self.masterSelectorLabel)

        self.masterSelector = slicer.qMRMLNodeComboBox(self.masterSelectorFrame)
        self.masterSelector.objectName = "MasterVolumeNodeSelector"
        # TODO
        self.masterSelector.nodeTypes = (("vtkMRMLScalarVolumeNode"), "")
        self.masterSelector.selectNodeUponCreation = False
        self.masterSelector.addEnabled = False
        self.masterSelector.removeEnabled = False
        self.masterSelector.noneEnabled = True
        self.masterSelector.showHidden = False
        self.masterSelector.showChildNodeTypes = False
        self.masterSelector.setMRMLScene(slicer.mrmlScene)
        # TODO: need to add a QLabel
        # self.masterSelector.SetLabelText( "Master Volume:" )
        self.masterSelector.setToolTip(
            'Pick the master structural volume to define the segmentation.  A label volume with the with "%s" appended to the name will be created if it doesn\'t already exist.'
            % self.mergeVolumePostfix
        )
        self.masterSelectorFrame.layout().addWidget(self.masterSelector)

        #
        # merge label name and set button
        #
        self.mergeSelectorFrame = qt.QFrame(self.masterFrame)
        self.mergeSelectorFrame.objectName = "MergeVolumeFrame"
        self.mergeSelectorFrame.setLayout(qt.QHBoxLayout())
        self.masterFrame.layout().addWidget(self.mergeSelectorFrame)

        mergeNameToolTip = "Composite label map containing the merged structures (be aware that merge operations will overwrite any edits applied to this volume)"
        self.mergeNameLabel = qt.QLabel("Merge Volume: ", self.mergeSelectorFrame)
        self.mergeNameLabel.setToolTip(mergeNameToolTip)
        self.mergeSelectorFrame.layout().addWidget(self.mergeNameLabel)

        self.mergeSelector = slicer.qMRMLNodeComboBox(self.mergeSelectorFrame)
        self.mergeSelector.objectName = "MergeVolumeNodeSelector"
        self.mergeSelector.setToolTip(mergeNameToolTip)
        self.mergeSelector.nodeTypes = (("vtkMRMLLabelMapVolumeNode"), "")
        self.mergeSelector.addEnabled = False
        self.mergeSelector.removeEnabled = False
        self.mergeSelector.noneEnabled = False
        self.mergeSelector.showHidden = False
        self.mergeSelector.showChildNodeTypes = False
        self.mergeSelector.setMRMLScene(slicer.mrmlScene)
        self.mergeSelectorFrame.layout().addWidget(self.mergeSelector)

        self.newMergeVolumeAction = qt.QAction("Create new LabelMapVolume", self.mergeSelector)
        self.newMergeVolumeAction.connect("triggered()", self.newMerge)
        self.mergeSelector.addMenuAction(self.newMergeVolumeAction)

        #
        # Structures Frame
        #
        self.structuresFrame = ctk.ctkCollapsibleGroupBox(self.masterFrame)
        self.structuresFrame.objectName = "PerStructureVolumesFrame"
        self.structuresFrame.title = "Per-Structure Volumes"
        self.structuresFrame.collapsed = True
        self.structuresFrame.setLayout(qt.QVBoxLayout())
        self.masterFrame.layout().addWidget(self.structuresFrame)

        self.structureListWidget = LabelStructureListWidget()
        self.structureListWidget.mergeVolumePostfix = self.mergeVolumePostfix
        self.structuresFrame.layout().addWidget(self.structureListWidget)

        #
        # signals, slots, and observers
        #

        # signals/slots on qt widgets are automatically when
        # this class destructs, but observers of the scene must be explicitly
        # removed in the destuctor

        # node selected
        self.masterSelector.connect("currentNodeChanged(vtkMRMLNode*)", self.onSelect)
        self.mergeSelector.connect("currentNodeChanged(vtkMRMLNode*)", self.onMergeSelect)

        # so buttons will initially be disabled
        self.master = None
        self.structureListWidget.updateStructures()

    def selectStructure(self, idx):
        """backward compatibility"""
        self.structureListWidget.selectStructure(idx)

    def labelCreateDialog(self):
        """label create dialog"""
        dlg = LabelCreateDialog(slicer.util.mainWindow(), self.master, self.mergeVolumePostfix)
        colorLogic = slicer.modules.colors.logic()
        dlg.colorNodeID = colorLogic.GetDefaultEditorColorNodeID()

        if dlg.exec_() == qt.QDialog.Accepted:
            self.colorNodeID = dlg.colorNodeID
            self.createMerge()
Пример #2
0
    def create(self):
        """create the segmentation helper box"""

        #
        # Master Frame
        #
        self.masterFrame = qt.QFrame(self.parent)
        self.masterFrame.setLayout(qt.QVBoxLayout())
        self.parent.layout().addWidget(self.masterFrame)

        #
        # the master volume selector
        #
        self.masterSelectorFrame = qt.QFrame(self.parent)
        self.masterSelectorFrame.objectName = "MasterVolumeFrame"
        self.masterSelectorFrame.setLayout(qt.QHBoxLayout())
        self.masterFrame.layout().addWidget(self.masterSelectorFrame)

        self.masterSelectorLabel = qt.QLabel("Master Volume: ", self.masterSelectorFrame)
        self.masterSelectorLabel.setToolTip("Select the master volume (background grayscale scalar volume node)")
        self.masterSelectorFrame.layout().addWidget(self.masterSelectorLabel)

        self.masterSelector = slicer.qMRMLNodeComboBox(self.masterSelectorFrame)
        self.masterSelector.objectName = "MasterVolumeNodeSelector"
        # TODO
        self.masterSelector.nodeTypes = (("vtkMRMLScalarVolumeNode"), "")
        self.masterSelector.selectNodeUponCreation = False
        self.masterSelector.addEnabled = False
        self.masterSelector.removeEnabled = False
        self.masterSelector.noneEnabled = True
        self.masterSelector.showHidden = False
        self.masterSelector.showChildNodeTypes = False
        self.masterSelector.setMRMLScene(slicer.mrmlScene)
        # TODO: need to add a QLabel
        # self.masterSelector.SetLabelText( "Master Volume:" )
        self.masterSelector.setToolTip(
            'Pick the master structural volume to define the segmentation.  A label volume with the with "%s" appended to the name will be created if it doesn\'t already exist.'
            % self.mergeVolumePostfix
        )
        self.masterSelectorFrame.layout().addWidget(self.masterSelector)

        #
        # merge label name and set button
        #
        self.mergeSelectorFrame = qt.QFrame(self.masterFrame)
        self.mergeSelectorFrame.objectName = "MergeVolumeFrame"
        self.mergeSelectorFrame.setLayout(qt.QHBoxLayout())
        self.masterFrame.layout().addWidget(self.mergeSelectorFrame)

        mergeNameToolTip = "Composite label map containing the merged structures (be aware that merge operations will overwrite any edits applied to this volume)"
        self.mergeNameLabel = qt.QLabel("Merge Volume: ", self.mergeSelectorFrame)
        self.mergeNameLabel.setToolTip(mergeNameToolTip)
        self.mergeSelectorFrame.layout().addWidget(self.mergeNameLabel)

        self.mergeSelector = slicer.qMRMLNodeComboBox(self.mergeSelectorFrame)
        self.mergeSelector.objectName = "MergeVolumeNodeSelector"
        self.mergeSelector.setToolTip(mergeNameToolTip)
        self.mergeSelector.nodeTypes = (("vtkMRMLLabelMapVolumeNode"), "")
        self.mergeSelector.addEnabled = False
        self.mergeSelector.removeEnabled = False
        self.mergeSelector.noneEnabled = False
        self.mergeSelector.showHidden = False
        self.mergeSelector.showChildNodeTypes = False
        self.mergeSelector.setMRMLScene(slicer.mrmlScene)
        self.mergeSelectorFrame.layout().addWidget(self.mergeSelector)

        self.newMergeVolumeAction = qt.QAction("Create new LabelMapVolume", self.mergeSelector)
        self.newMergeVolumeAction.connect("triggered()", self.newMerge)
        self.mergeSelector.addMenuAction(self.newMergeVolumeAction)

        #
        # Structures Frame
        #
        self.structuresFrame = ctk.ctkCollapsibleGroupBox(self.masterFrame)
        self.structuresFrame.objectName = "PerStructureVolumesFrame"
        self.structuresFrame.title = "Per-Structure Volumes"
        self.structuresFrame.collapsed = True
        self.structuresFrame.setLayout(qt.QVBoxLayout())
        self.masterFrame.layout().addWidget(self.structuresFrame)

        self.structureListWidget = LabelStructureListWidget()
        self.structureListWidget.mergeVolumePostfix = self.mergeVolumePostfix
        self.structuresFrame.layout().addWidget(self.structureListWidget)

        #
        # signals, slots, and observers
        #

        # signals/slots on qt widgets are automatically when
        # this class destructs, but observers of the scene must be explicitly
        # removed in the destuctor

        # node selected
        self.masterSelector.connect("currentNodeChanged(vtkMRMLNode*)", self.onSelect)
        self.mergeSelector.connect("currentNodeChanged(vtkMRMLNode*)", self.onMergeSelect)

        # so buttons will initially be disabled
        self.master = None
        self.structureListWidget.updateStructures()