def __init__(self, parent): parent.title = "Editor" parent.category = "" parent.contributor = "Steve Pieper" parent.helpText = """ The Editor allows label maps to be created and edited. The active label map will be modified by the Editor. See <a>http://www.slicer.org/slicerWiki/index.php/Modules:Editor-Documentation-4.0</a>.\n\nThe Master Volume refers to the background grayscale volume to be edited (used, for example, when thresholding). The Merge Volume refers to a volume that contains several different label values corresponding to different structures.\n\nBasic usage: selecting the Master and Merge Volume give access to the editor tools. Each tool has a help icon to bring up a dialog with additional information. Hover your mouse pointer over buttons and options to view Balloon Help (tool tips). Use these to define the Label Map.\n\nAdvanced usage: open the Per-Structure Volumes tab to create independent Label Maps for each color you wish to edit. Since many editor tools (such as threshold) will operate on the entire volume, you can use the Per-Structure Volumes feature to isolate these operations on a structure-by-structure basis. Use the Split Merge Volume button to create a set of volumes with independent labels. Use the Add Structure button to add a new volume. Delete Structures will remove all the independent structure volumes. Merge All will assemble the current structures into the Merge Volume. Merge And Build will invoke the Model Maker module on the Merge Volume. """ parent.acknowledgementText = """ This work is supported by NA-MIC, NAC, BIRN, NCIGT, and the Slicer Community. See <a>http://www.slicer.org</a> for details. Module implemented by Steve Pieper. This work is partially supported by PAR-07-249: R01CA131718 NA-MIC Virtual Colonoscopy (See <a>http://www.na-mic.org/Wiki/index.php/NA-MIC_NCBC_Collaboration:NA-MIC_virtual_colonoscopy</a>). """ self.parent = parent if slicer.mrmlScene.GetTagByClassName( "vtkMRMLScriptedModuleNode" ) != 'ScriptedModule': slicer.mrmlScene.RegisterNodeClass(vtkMRMLScriptedModuleNode()) if tcl('info exists ::Editor(singleton)') != '': # TODO: cannot call dialog.exec from pythonqt... This is just a warning anyway #dialog = qt.QErrorMessage() #dialog.showMessage("Error: editor singleton already created - Editor initialized twice.") pass tcl('set ::Editor(singleton) this') tcl('set ::Editor(checkPointsEnabled) 1') iconDir = slicer.app.slicerHome + '/' + os.environ['SLICER_SHARE_DIR'] + '/Tcl/ImageData' parent.icon = qt.QIcon("%s/ToolbarEditorToolbox.png" % iconDir)
def __init__(self, parent): parent.title = "Editor" parent.category = "" parent.contributor = "Steve Pieper" parent.helpText = """ The Editor allows label maps to be created and edited. The active label map will be modified by the Editor. See <a>http://www.slicer.org/slicerWiki/index.php/Modules:Editor-Documentation-4.0</a>.\n\nThe Master Volume refers to the background grayscale volume to be edited (used, for example, when thresholding). The Merge Volume refers to a volume that contains several different label values corresponding to different structures.\n\nBasic usage: selecting the Master and Merge Volume give access to the editor tools. Each tool has a help icon to bring up a dialog with additional information. Hover your mouse pointer over buttons and options to view Balloon Help (tool tips). Use these to define the Label Map.\n\nAdvanced usage: open the Per-Structure Volumes tab to create independent Label Maps for each color you wish to edit. Since many editor tools (such as threshold) will operate on the entire volume, you can use the Per-Structure Volumes feature to isolate these operations on a structure-by-structure basis. Use the Split Merge Volume button to create a set of volumes with independent labels. Use the Add Structure button to add a new volume. Delete Structures will remove all the independent structure volumes. Merge All will assemble the current structures into the Merge Volume. Merge And Build will invoke the Model Maker module on the Merge Volume. """ parent.acknowledgementText = """ This work is supported by NA-MIC, NAC, BIRN, NCIGT, and the Slicer Community. See <a>http://www.slicer.org</a> for details. Module implemented by Steve Pieper. This work is partially supported by PAR-07-249: R01CA131718 NA-MIC Virtual Colonoscopy (See <a>http://www.na-mic.org/Wiki/index.php/NA-MIC_NCBC_Collaboration:NA-MIC_virtual_colonoscopy</a>). """ self.parent = parent if slicer.mrmlScene.GetTagByClassName( "vtkMRMLScriptedModuleNode") != 'ScriptedModule': slicer.mrmlScene.RegisterNodeClass(vtkMRMLScriptedModuleNode()) if tcl('info exists ::Editor(singleton)') != '': # TODO: cannot call dialog.exec from pythonqt... This is just a warning anyway #dialog = qt.QErrorMessage() #dialog.showMessage("Error: editor singleton already created - Editor initialized twice.") pass tcl('set ::Editor(singleton) this') tcl('set ::Editor(checkPointsEnabled) 1') iconDir = slicer.app.slicerHome + '/' + os.environ[ 'SLICER_SHARE_DIR'] + '/Tcl/ImageData' parent.icon = qt.QIcon("%s/ToolbarEditorToolbox.png" % iconDir)
def select(self): """select master volume - load merge volume if one with the correct name exists""" self.master = self.masterSelector.currentNode() merge = self.mergeVolume() mergeText = "None" if merge: if merge.GetClassName() != "vtkMRMLScalarVolumeNode" or not merge.GetLabelMap(): self.errorDialog( "Error: selected merge label volume is not a label volume" ) else: # make the source node the active background, and the label node the active label selectionNode = self.applicationLogic.GetSelectionNode() selectionNode.SetReferenceActiveVolumeID( self.master.GetID() ) selectionNode.SetReferenceActiveLabelVolumeID( merge.GetID() ) self.applicationLogic.PropagateVolumeSelection() mergeText = merge.GetName() self.merge = merge else: # the master exists, but there is no merge volume yet # bring up dialog to create a merge with a user-selected color node if self.master: self.colorSelectDialog() tcl('EffectSWidget::RotateToVolumePlanes') # make sure slices are aligned to volumes self.mergeName.setText( mergeText ) self.updateStructures() # remove all active effects (so that when selected again slice rotation and snap to IJK will happen if needed tcl('::EffectSWidget::RemoveAll') # 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 nodeID = tcl('[EditorGetParameterNode] GetID') pNode = slicer.mrmlScene.GetNodeByID(nodeID) if pNode: pNode.Modified()
def onEntry(self, comingFrom, transitionType): ''' ''' super(EMSegmentQuickStep1, self).onEntry(comingFrom, transitionType) # Remove everything if needed - did not work properly -however when running it without it then it resets pipeline but leaves nodes in scend ! # self.logic().RemoveTaskAndTempFiles() # self.reset() slicer.modules.emsegmentAdvancedDynamicFrame = self.dynamicFrame() if not self.__initialized: # use default taskfile taskFileShort = slicer.modulelogic.vtkMRMLEMSGlobalParametersNode.GetDefaultTaskTclFileName( ) self.mrmlManager().CreateAndObserveNewParameterSet() templateNodes = slicer.mrmlScene.GetNodesByClass( 'vtkMRMLEMSTemplateNode') self.mrmlManager().SetNthParameterName( templateNodes.GetNumberOfItems() - 1, 'EMEasy') self.mrmlManager().SetTclTaskFilename(taskFileShort) self.logic().SourceTaskFiles() loadResult = self.mrmlManager().SetLoadedParameterSetIndex( templateNodes.GetItemAsObject( templateNodes.GetNumberOfItems() - 1)) if int(loadResult) != 0: Helper.Info( "EMS node is corrupted - the manager could not be updated with new task: EMQuick" ) #return False else: Helper.Info("Loading completed.") self.logic().DefineTclTaskFileFromMRML() # use anatomy label colors self.mrmlManager().GetGlobalParametersNode().SetColormap( 'vtkMRMLColorTableNodeFileGenericAnatomyColors.txt') # clear the dynamic panel self.dynamicFrame().setMRMLManager(self.mrmlManager()) self.dynamicFrame().clearElements() logicTclName = self.logic().GetSlicerCommonInterface( ).GetTclNameFromPointer(self.logic()) tcl('::EMSegmenterPreProcessingTcl::ShowUserInterface ' + str(logicTclName)) self.__initialized = True self.loadFromMRML()
def updateCheckPointButtons(self): previousImagesExist = nextImagesExist = False if bool(int(tcl('info exists ::Editor(previousCheckPointImages)'))): previousImagesExist = bool(int(tcl('llength $::Editor(previousCheckPointImages)'))) if bool(int(tcl('info exists ::Editor(nextCheckPointImages)'))): nextImagesExist = bool(int(tcl('llength $::Editor(nextCheckPointImages)'))) if not self.embedded: self.effectButtons["PreviousCheckPoint"].setDisabled( not previousImagesExist ) self.effectButtons["NextCheckPoint"].setDisabled( not nextImagesExist )
def RotateToVolumePlanes(): # AF TODO: check with Steve if this has any undesired consequences # Volumes slicenode has a method for this, no need for tcl tcl('EffectSWidget::RotateToVolumePlanes') # snap to IJK to try and avoid rounding errors sliceLogics = slicer.app.layoutManager().mrmlSliceLogics() numLogics = sliceLogics.GetNumberOfItems() for n in range(numLogics): l = sliceLogics.GetItemAsObject(n) l.SnapSliceOffsetToIJK()
def updateCheckPointButtons(self): previousImagesExist = nextImagesExist = False if bool(int(tcl('info exists ::Editor(previousCheckPointImages)'))): previousImagesExist = bool( int(tcl('llength $::Editor(previousCheckPointImages)'))) if bool(int(tcl('info exists ::Editor(nextCheckPointImages)'))): nextImagesExist = bool( int(tcl('llength $::Editor(nextCheckPointImages)'))) if not self.embedded: self.effectButtons["PreviousCheckPoint"].setDisabled( not previousImagesExist) self.effectButtons["NextCheckPoint"].setDisabled( not nextImagesExist)
def onEntry( self, comingFrom, transitionType ): ''' ''' super( EMSegmentQuickStep1, self ).onEntry( comingFrom, transitionType ) # Remove everything if needed - did not work properly -however when running it without it then it resets pipeline but leaves nodes in scend ! # self.logic().RemoveTaskAndTempFiles() # self.reset() slicer.modules.emsegmentAdvancedDynamicFrame = self.dynamicFrame() if not self.__initialized: # use default taskfile taskFileShort = slicer.vtkMRMLEMSGlobalParametersNode.GetDefaultTaskTclFileName() self.mrmlManager().CreateAndObserveNewParameterSet() templateNodes = slicer.mrmlScene.GetNodesByClass( 'vtkMRMLEMSTemplateNode' ) self.mrmlManager().SetNthParameterName( templateNodes.GetNumberOfItems() - 1, 'EMEasy' ) self.mrmlManager().SetTclTaskFilename( taskFileShort ) self.logic().SourceTaskFiles() loadResult = self.mrmlManager().SetLoadedParameterSetIndex( templateNodes.GetItemAsObject( templateNodes.GetNumberOfItems() - 1 ) ) if int( loadResult ) != 0: Helper.Info( "EMS node is corrupted - the manager could not be updated with new task: EMQuick" ) #return False else: Helper.Info( "Loading completed." ) self.logic().DefineTclTaskFileFromMRML() # use anatomy label colors self.mrmlManager().GetGlobalParametersNode().SetColormap( 'vtkMRMLColorTableNodeFileGenericAnatomyColors.txt' ) # clear the dynamic panel self.dynamicFrame().setMRMLManager( self.mrmlManager() ) self.dynamicFrame().clearElements() logicTclName = self.logic().GetSlicerCommonInterface().GetTclNameFromPointer( self.logic() ) tcl( '::EMSegmenterPreProcessingTcl::ShowUserInterface ' + str( logicTclName ) ) self.__initialized = True self.loadFromMRML()
def onExit(self, goingTo, transitionType): ''' ''' self.propagateToMRML() if self.isSimpleMode(): returnValue = tcl("::EMSegmenterSimpleTcl::ValidateCheckList") if int(returnValue) != 0: # error messageBox = qt.QMessageBox.warning( self, "Error", "Could not validate the Checklist. Please double check your settings!" ) return self.mrmlManager().GetWorkingDataNode( ).SetAlignedTargetNodeIsValid(0) self.mrmlManager().GetWorkingDataNode().SetAlignedAtlasNodeIsValid( 0) # disable questions at the pre-processing step preProcessingStep = slicer.modules.emsegmentPreprocessingStep if preProcessingStep: preProcessingStep.disableQuestions() else: # disable questions at the pre-processing step preProcessingStep = slicer.modules.emsegmentPreprocessingStep if preProcessingStep: preProcessingStep.enableQuestions() self.__parent.onExit(goingTo, transitionType)
def create(self): self.frame = qt.QFrame(self.parent) self.frame.setLayout(qt.QHBoxLayout()) self.parent.layout().addWidget(self.frame) self.label = qt.QLabel(self.frame) self.label.setText("Label: ") self.frame.layout().addWidget(self.label) self.labelName = qt.QLabel(self.frame) self.labelName.setText("") self.frame.layout().addWidget(self.labelName) self.colorSpin = qt.QSpinBox(self.frame) self.colorSpin.setValue( int(tcl('EditorGetPaintLabel')) ) self.colorSpin.setToolTip( "Click colored patch at right to bring up color selection pop up window. Use the 'c' key to bring up color popup menu." ) self.frame.layout().addWidget(self.colorSpin) self.colorPatch = qt.QPushButton(self.frame) self.frame.layout().addWidget(self.colorPatch) self.updateParameterNode(slicer.mrmlScene, "ModifiedEvent") self.updateGUIFromMRML(self.parameterNode, "ModifiedEvent") self.frame.connect( 'destroyed(QObject)', self.cleanup) self.colorSpin.connect( 'valueChanged(int)', self.updateMRMLFromGUI) self.colorPatch.connect( 'clicked()', self.showColorBox ) # TODO: change this to look for specfic events (added, removed...) # but this requires being able to access events by number from wrapped code tag = slicer.mrmlScene.AddObserver("ModifiedEvent", self.updateParameterNode) self.observerTags.append( (slicer.mrmlScene, tag) )
def onExit(self, goingTo, transitionType): """ """ self.propagateToMRML() if self.isSimpleMode(): returnValue = tcl("::EMSegmenterSimpleTcl::ValidateCheckList") if int(returnValue) != 0: # error messageBox = qt.QMessageBox.warning( self, "Error", "Could not validate the Checklist. Please double check your settings!" ) return self.mrmlManager().GetWorkingDataNode().SetAlignedTargetNodeIsValid(0) self.mrmlManager().GetWorkingDataNode().SetAlignedAtlasNodeIsValid(0) # disable questions at the pre-processing step preProcessingStep = slicer.modules.emsegmentPreprocessingStep if preProcessingStep: preProcessingStep.disableQuestions() else: # disable questions at the pre-processing step preProcessingStep = slicer.modules.emsegmentPreprocessingStep if preProcessingStep: preProcessingStep.enableQuestions() super(EMSegmentDefineInputChannelsStep, self).onExit(goingTo, transitionType)
def enter(self): # get the master and merge nodes from the composite node associated # with the red slice, but only if showing volumes if self.showVolumesFrame: # get the slice composite node for the Red slice view (we'll assume it exists # since we are in the editor) to get the current background and label compositeNode = self.editUtil.getCompositeNode() masterNode = slicer.mrmlScene.GetNodeByID( compositeNode.GetBackgroundVolumeID() ) mergeNode = slicer.mrmlScene.GetNodeByID( compositeNode.GetLabelVolumeID() ) self.setMasterNode(masterNode) self.setMergeNode(mergeNode) # if not showing volumes, the caller is responsible for setting the master and # merge nodes, most likely according to a widget within the caller # Observe the parameter node in order to make changes to # button states as needed nodeID = tcl('[EditorGetParameterNode] GetID') self.parameterNode = slicer.mrmlScene.GetNodeByID(nodeID) self.parameterNodeTag = self.parameterNode.AddObserver("ModifiedEvent", self.updateGUIFromMRML) # get access to the magnifier window and turn it off while using # the Editor to improve performance (TODO: this should probably be # a setting on the app) mainWindow = slicer.util.mainWindow() viewsController = slicer.util.findChildren(mainWindow, 'MRMLThreeDViewsControllerWidget')[0] viewsController.disableMagnification = True # resume the current effect, if we left the editor and re-entered self.resumeEffect()
def create(self): self.frame = qt.QFrame(self.parent) self.frame.setLayout(qt.QHBoxLayout()) self.parent.layout().addWidget(self.frame) self.label = qt.QLabel(self.frame) self.label.setText("Label: ") self.frame.layout().addWidget(self.label) self.labelName = qt.QLabel(self.frame) self.labelName.setText("") self.frame.layout().addWidget(self.labelName) self.colorSpin = qt.QSpinBox(self.frame) self.colorSpin.setValue(int(tcl('EditorGetPaintLabel'))) self.colorSpin.setToolTip( "Click colored patch at right to bring up color selection pop up window. Use the 'c' key to bring up color popup menu." ) self.frame.layout().addWidget(self.colorSpin) self.colorPatch = qt.QPushButton(self.frame) self.frame.layout().addWidget(self.colorPatch) self.updateParameterNode(slicer.mrmlScene, "ModifiedEvent") self.updateGUIFromMRML(self.parameterNode, "ModifiedEvent") self.frame.connect('destroyed(QObject)', self.cleanup) self.colorSpin.connect('valueChanged(int)', self.updateMRMLFromGUI) self.colorPatch.connect('clicked()', self.showColorBox) # TODO: change this to look for specfic events (added, removed...) # but this requires being able to access events by number from wrapped code tag = slicer.mrmlScene.AddObserver("ModifiedEvent", self.updateParameterNode) self.observerTags.append((slicer.mrmlScene, tag))
def onEntry(self, comingFrom, transitionType): """ """ super(EMSegmentDefineInputChannelsStep, self).onEntry(comingFrom, transitionType) if self.isSimpleMode(): self.logic().SourceTaskFiles() # clear the dynamic panel self.dynamicFrame().setMRMLManager(self.mrmlManager()) self.dynamicFrame().clearElements() logicTclName = self.logic().GetSlicerCommonInterface().GetTclNameFromPointer(self.logic()) tcl("::EMSegmenterSimpleTcl::ShowCheckList " + str(logicTclName)) self.loadFromMRML()
def onEntry( self, comingFrom, transitionType ): ''' ''' super( EMSegmentDefineInputChannelsStep, self ).onEntry( comingFrom, transitionType ) if self.isSimpleMode(): self.logic().SourceTaskFiles() # clear the dynamic panel self.dynamicFrame().setMRMLManager( self.mrmlManager() ) self.dynamicFrame().clearElements() logicTclName = self.logic().GetSlicerCommonInterface().GetTclNameFromPointer( self.logic() ) tcl( '::EMSegmenterSimpleTcl::ShowCheckList ' + str( logicTclName ) ) self.loadFromMRML()
def onEntry( self, comingFrom, transitionType ): ''' ''' self.__parent.onEntry( comingFrom, transitionType ) # we are always in advanced mode, so let's fill the dynamic frame self.logic().SourceTaskFiles() self.logic().SourcePreprocessingTclFiles() # clear the dynamic panel self.dynamicFrame().setMRMLManager( self.mrmlManager() ) self.dynamicFrame().clearElements() logicTclName = self.logic().GetSlicerCommonInterface().GetTclNameFromPointer( self.logic() ) tcl( '::EMSegmenterPreProcessingTcl::ShowUserInterface ' + str( logicTclName ) ) self.loadFromMRML()
def edit(self,label): """select the picked label for editing""" merge = self.mergeVolume() if not merge: return colorNode = merge.GetDisplayNode().GetColorNode() structureName = colorNode.GetColorName( label ) structureVolume = self.structureVolume( structureName ) # make the master node the active background, and the structure label node the active label selectionNode = self.applicationLogic.GetSelectionNode() selectionNode.SetReferenceActiveVolumeID(self.master.GetID()) if structureVolume: selectionNode.SetReferenceActiveLabelVolumeID( structureVolume.GetID() ) self.applicationLogic.PropagateVolumeSelection() tcl('EditorSetPaintLabel %s' % label)
def edit(self, label): """select the picked label for editing""" merge = self.mergeVolume() if not merge: return colorNode = merge.GetDisplayNode().GetColorNode() structureName = colorNode.GetColorName(label) structureVolume = self.structureVolume(structureName) # make the master node the active background, and the structure label node the active label selectionNode = self.applicationLogic.GetSelectionNode() selectionNode.SetReferenceActiveVolumeID(self.master.GetID()) if structureVolume: selectionNode.SetReferenceActiveLabelVolumeID( structureVolume.GetID()) self.applicationLogic.PropagateVolumeSelection(0) tcl('EditorSetPaintLabel %s' % label)
def updateParameterNode(self, caller, event): # # observe the scene to know when to get the parameter node # nodeID = tcl('[EditorGetParameterNode] GetID') node = slicer.mrmlScene.GetNodeByID(nodeID) if node != self.parameterNode: if self.parameterNode: self.parameterNode.RemoveObserver(self.parameterNodeTag) self.parameterNodeTag = node.AddObserver("ModifiedEvent", self.updateGUIFromMRML) self.parameterNode = node
def onEntry(self, comingFrom, transitionType): ''' ''' self.__parent.onEntry(comingFrom, transitionType) # we are always in advanced mode, so let's fill the dynamic frame self.logic().SourceTaskFiles() self.logic().SourcePreprocessingTclFiles() # clear the dynamic panel self.dynamicFrame().setMRMLManager(self.mrmlManager()) self.dynamicFrame().clearElements() logicTclName = self.logic().GetSlicerCommonInterface( ).GetTclNameFromPointer(self.logic()) tcl('::EMSegmenterPreProcessingTcl::ShowUserInterface ' + str(logicTclName)) self.loadFromMRML()
def select(self): """select master volume - load merge volume if one with the correct name exists""" self.master = self.masterSelector.currentNode() merge = self.mergeVolume() mergeText = "None" if merge: if merge.GetClassName( ) != "vtkMRMLScalarVolumeNode" or not merge.GetLabelMap(): self.errorDialog( "Error: selected merge label volume is not a label volume") else: # make the source node the active background, and the label node the active label selectionNode = self.applicationLogic.GetSelectionNode() selectionNode.SetReferenceActiveVolumeID(self.master.GetID()) selectionNode.SetReferenceActiveLabelVolumeID(merge.GetID()) self.applicationLogic.PropagateVolumeSelection(0) mergeText = merge.GetName() self.merge = merge else: # the master exists, but there is no merge volume yet # bring up dialog to create a merge with a user-selected color node if self.master: self.colorSelectDialog() tcl('EffectSWidget::RotateToVolumePlanes' ) # make sure slices are aligned to volumes self.mergeName.setText(mergeText) self.updateStructures() # remove all active effects (so that when selected again slice rotation and snap to IJK will happen if needed tcl('::EffectSWidget::RemoveAll') # 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 nodeID = tcl('[EditorGetParameterNode] GetID') pNode = slicer.mrmlScene.GetNodeByID(nodeID) if pNode: pNode.Modified() if self.selectCommand: self.selectCommand()
def runPreProcessing(self): ''' ''' # notify user dialog = qt.QMessageBox() dialog.setWindowTitle("Please wait") dialog.setText("Please wait while pre-processing runs..") dialog.setModal(False) dialog.show() # message = qt.QMessageBox( qt.QMessageBox.NoIcon, "Please wait", "Please wait while pre-processing runs..", qt.QMessageBox.Ignore ) # message.setModal( False ) # message.show() slicer.app.processEvents() # run preprocessing returnValue = tcl("::EMSegmenterPreProcessingTcl::Run") # message.hide() dialog.hide() slicer.app.processEvents() if not returnValue or int(returnValue) != 0: # something went wrong! # error message! messageBox = qt.QMessageBox.warning( self, "Error", "Pre-processing did not execute correctly!") return workingDataNode = self.mrmlManager().GetWorkingDataNode() if workingDataNode: # set flags in the mrml nodes workingDataNode.SetAlignedTargetNodeIsValid(1) workingDataNode.SetAlignedAtlasNodeIsValid(1) # show preprocessing output in sliceViews volumeCollection = workingDataNode.GetInputTargetNode() if volumeCollection: outputNode = volumeCollection.GetNthVolumeNode(0) # propagate to sliceViews selectionNode = slicer.app.applicationLogic().GetSelectionNode( ) selectionNode.SetReferenceActiveVolumeID(outputNode.GetID()) #selectionNode.SetReferenceSecondaryVolumeID( outputNode.GetID() ) slicer.app.applicationLogic().PropagateVolumeSelection() Helper.Info('=============================================') Helper.Info('Pre-processing completed successfully') Helper.Info('=============================================')
def enter(self): """ When entering the module, check that the lightbox modes are off and that we have the volumes loaded """ warned = False sliceLogics = slicer.app.layoutManager().mrmlSliceLogics() for i in xrange(sliceLogics.GetNumberOfItems()): sliceLogic = sliceLogics.GetItemAsObject(i) if sliceLogic: sliceNode = sliceLogic.GetSliceNode() if sliceNode.GetLayoutGridRows() != 1 or sliceNode.GetLayoutGridColumns() != 1: if not warned: qt.QMessageBox.warning(slicer.util.mainWindow(), 'Editor', 'The Editor Module is not compatible with slice viewers in light box mode.\nViews are being reset.') warned = True sliceNode.SetLayoutGrid(1,1) # get the master and merge nodes from the composite node associated # with the red slice, but only if showing volumes if self.showVolumesFrame: # get the slice composite node for the Red slice view (we'll assume it exists # since we are in the editor) to get the current background and label # - set the foreground layer as the active ID # in the selection node for later calls to PropagateVolumeSelection compositeNode = self.editUtil.getCompositeNode() selectionNode = slicer.app.applicationLogic().GetSelectionNode() selectionNode.SetReferenceSecondaryVolumeID( compositeNode.GetForegroundVolumeID() ) print( 'setting selection node to ', compositeNode.GetForegroundVolumeID() ) bgID = lbID = "" if compositeNode.GetBackgroundVolumeID(): bgID = compositeNode.GetBackgroundVolumeID() if compositeNode.GetLabelVolumeID(): lbID = compositeNode.GetLabelVolumeID() masterNode = slicer.mrmlScene.GetNodeByID( bgID ) mergeNode = slicer.mrmlScene.GetNodeByID( lbID ) self.setMasterNode(masterNode) self.setMergeNode(mergeNode) # if not showing volumes, the caller is responsible for setting the master and # merge nodes, most likely according to a widget within the caller # Observe the parameter node in order to make changes to # button states as needed nodeID = tcl('[EditorGetParameterNode] GetID') self.parameterNode = slicer.mrmlScene.GetNodeByID(nodeID) self.parameterNodeTag = self.parameterNode.AddObserver(vtk.vtkCommand.ModifiedEvent, self.updateGUIFromMRML) # resume the current effect, if we left the editor and re-entered or pick default # TODO: not fully implemented #self.activateEffect() self.helper.onEnter()
def runPreProcessing( self ): ''' ''' # notify user dialog = qt.QMessageBox() dialog.setWindowTitle("Please wait") dialog.setText("Please wait while pre-processing runs..") dialog.setModal( False ) dialog.show() # message = qt.QMessageBox( qt.QMessageBox.NoIcon, "Please wait", "Please wait while pre-processing runs..", qt.QMessageBox.Ignore ) # message.setModal( False ) # message.show() slicer.app.processEvents() # run preprocessing returnValue = tcl( "::EMSegmenterPreProcessingTcl::Run" ) # message.hide() dialog.hide() slicer.app.processEvents() if not returnValue or int( returnValue ) != 0: # something went wrong! # error message! messageBox = qt.QMessageBox.warning( self, "Error", "Pre-processing did not execute correctly!" ) return workingDataNode = self.mrmlManager().GetWorkingDataNode() if workingDataNode: # set flags in the mrml nodes workingDataNode.SetAlignedTargetNodeIsValid( 1 ) workingDataNode.SetAlignedAtlasNodeIsValid( 1 ) # show preprocessing output in sliceViews volumeCollection = workingDataNode.GetInputTargetNode() if volumeCollection: outputNode = volumeCollection.GetNthVolumeNode( 0 ) # propagate to sliceViews selectionNode = slicer.app.applicationLogic().GetSelectionNode() selectionNode.SetReferenceActiveVolumeID( outputNode.GetID() ) #selectionNode.SetReferenceSecondaryVolumeID( outputNode.GetID() ) slicer.app.applicationLogic().PropagateVolumeSelection() Helper.Info( '=============================================' ) Helper.Info( 'Pre-processing completed successfully' ) Helper.Info( '=============================================' )
def editorGetGestureParameterNode(self, id): node = None nNodes = slicer.mrmlScene.GetNumberOfNodesByClass('vtkMRMLScriptedModuleNode') for n in xrange(nNodes): compNode = slicer.mrmlScene.GetNthNodeByClass(n, 'vtkMRMLScriptedModuleNode') nodeid = None if compNode.GetModuleName() == 'Editor': nodeId = compNode.GetParameter('gestureid') if nodeId: val = compNode.SetParameter('gestureid', nodeId) node = val break if node == None: node = tcl('EditorCreateGestureParameterNode %s' % id) return node
def enter(self): """ When entering the module, check that the lightbox modes are off and that we have the volumes loaded """ warned = False sliceLogics = slicer.app.layoutManager().mrmlSliceLogics() for i in xrange(sliceLogics.GetNumberOfItems()): sliceLogic = sliceLogics.GetItemAsObject(i) if sliceLogic: sliceNode = sliceLogic.GetSliceNode() print("checking %s", sliceNode.GetName()) if sliceNode.GetLayoutGridRows( ) != 1 or sliceNode.GetLayoutGridColumns() != 1: if not warned: qt.QMessageBox.warning( slicer.util.mainWindow(), 'Editor', 'The Editor Module is not compatible with slice viewers in light box mode.\nViews are being reset.' ) warned = True sliceNode.SetLayoutGrid(1, 1) # get the master and merge nodes from the composite node associated # with the red slice, but only if showing volumes if self.showVolumesFrame: # get the slice composite node for the Red slice view (we'll assume it exists # since we are in the editor) to get the current background and label compositeNode = self.editUtil.getCompositeNode() bgID = lbID = "" if compositeNode.GetBackgroundVolumeID(): bgID = compositeNode.GetBackgroundVolumeID() if compositeNode.GetLabelVolumeID(): lbID = compositeNode.GetLabelVolumeID() masterNode = slicer.mrmlScene.GetNodeByID(bgID) mergeNode = slicer.mrmlScene.GetNodeByID(lbID) self.setMasterNode(masterNode) self.setMergeNode(mergeNode) # if not showing volumes, the caller is responsible for setting the master and # merge nodes, most likely according to a widget within the caller # Observe the parameter node in order to make changes to # button states as needed nodeID = tcl('[EditorGetParameterNode] GetID') self.parameterNode = slicer.mrmlScene.GetNodeByID(nodeID) self.parameterNodeTag = self.parameterNode.AddObserver( "ModifiedEvent", self.updateGUIFromMRML)
def editorGetGestureParameterNode(self, id): node = None nNodes = slicer.mrmlScene.GetNumberOfNodesByClass( 'vtkMRMLScriptedModuleNode') for n in xrange(nNodes): compNode = slicer.mrmlScene.GetNthNodeByClass( n, 'vtkMRMLScriptedModuleNode') nodeid = None if compNode.GetModuleName() == 'Editor': nodeId = compNode.GetParameter('gestureid') if nodeId: val = compNode.SetParameter('gestureid', nodeId) node = val break if node == None: node = tcl('EditorCreateGestureParameterNode %s' % id) return node
def enter(self): # get the master and merge nodes from the composite node associated # with the red slice, but only if showing volumes if self.showVolumesFrame: # get the slice composite node for the Red slice view (we'll assume it exists # since we are in the editor) to get the current background and label compositeNode = self.editUtil.getCompositeNode() masterNode = slicer.mrmlScene.GetNodeByID( compositeNode.GetBackgroundVolumeID() ) mergeNode = slicer.mrmlScene.GetNodeByID( compositeNode.GetLabelVolumeID() ) self.setMasterNode(masterNode) self.setMergeNode(mergeNode) # if not showing volumes, the caller is responsible for setting the master and # merge nodes, most likely according to a widget within the caller # Observe the parameter node in order to make changes to # button states as needed nodeID = tcl('[EditorGetParameterNode] GetID') self.parameterNode = slicer.mrmlScene.GetNodeByID(nodeID) self.parameterNodeTag = self.parameterNode.AddObserver("ModifiedEvent", self.updateGUIFromMRML)
def enter(self): """ When entering the module, check that the lightbox modes are off and that we have the volumes loaded """ warned = False sliceLogics = slicer.app.layoutManager().mrmlSliceLogics() for i in xrange(sliceLogics.GetNumberOfItems()): sliceLogic = sliceLogics.GetItemAsObject(i) if sliceLogic: sliceNode = sliceLogic.GetSliceNode() print("checking %s", sliceNode.GetName()) if sliceNode.GetLayoutGridRows() != 1 or sliceNode.GetLayoutGridColumns() != 1: if not warned: qt.QMessageBox.warning(slicer.util.mainWindow(), 'Editor', 'The Editor Module is not compatible with slice viewers in light box mode.\nViews are being reset.') warned = True sliceNode.SetLayoutGrid(1,1) # get the master and merge nodes from the composite node associated # with the red slice, but only if showing volumes if self.showVolumesFrame: # get the slice composite node for the Red slice view (we'll assume it exists # since we are in the editor) to get the current background and label compositeNode = self.editUtil.getCompositeNode() bgID = lbID = "" if compositeNode.GetBackgroundVolumeID(): bgID = compositeNode.GetBackgroundVolumeID() if compositeNode.GetLabelVolumeID(): lbID = compositeNode.GetLabelVolumeID() masterNode = slicer.mrmlScene.GetNodeByID( bgID ) mergeNode = slicer.mrmlScene.GetNodeByID( lbID ) self.setMasterNode(masterNode) self.setMergeNode(mergeNode) # if not showing volumes, the caller is responsible for setting the master and # merge nodes, most likely according to a widget within the caller # Observe the parameter node in order to make changes to # button states as needed nodeID = tcl('[EditorGetParameterNode] GetID') self.parameterNode = slicer.mrmlScene.GetNodeByID(nodeID) self.parameterNodeTag = self.parameterNode.AddObserver("ModifiedEvent", self.updateGUIFromMRML)
def validate( self, desiredBranchId ): ''' ''' super( EMSegmentDefinePreprocessingStep, self ).validate( desiredBranchId ) # check if CMTK should be used, # then try to find it # if this fails, ask if we should use BRAINSFit if self.mrmlManager().GetRegistrationPackageType() == self.mrmlManager().GetPackageTypeFromString( 'CMTK' ): # cmtk was selected cmtkPath = tcl( "::EMSegmenterPreProcessingTcl::Get_CMTK_Installation_Path" ) if cmtkPath == "": # cmtk was not found, ask if we want BRAINSFit instead answer = qt.QMessageBox.question( self, "CMTK is not installed", "CMTK is not installed. Do you want to proceed with BRAINSTools instead?", qt.QMessageBox.Yes | qt.QMessageBox.No ) if answer == qt.QMessageBox.No: # if no, exit here and stay at this step self.validationFailed( desiredBranchId, '', '', False ) return # same for plastimatch if self.mrmlManager().GetRegistrationPackageType() == self.mrmlManager().GetPackageTypeFromString( 'PLASTIMATCH' ): # plastimatch was selected plastimatchPath = tcl( "::EMSegmenterPreProcessingTcl::Get_PLASTIMATCH_Installation_Path" ) if plastimatchPath == "": # plastimatch was not found, ask if we want BRAINSFit instead answer = qt.QMessageBox.question( self, "PLASTIMATCH is not installed", "PLASTIMATCH is not installed. Do you want to proceed with BRAINSTools instead?", qt.QMessageBox.Yes | qt.QMessageBox.No ) if answer == qt.QMessageBox.No: # if no, exit here and stay at this step self.validationFailed( desiredBranchId, '', '', False ) return # same for DEMONS if self.mrmlManager().GetRegistrationPackageType() == self.mrmlManager().GetPackageTypeFromString( 'DEMONS' ): # DEMONS was selected demonsPath = tcl( "::EMSegmenterPreProcessingTcl::Get_DEMONS_Installation_Path" ) if demonsPath == "": # demons was not found, ask if we want BRAINSFit instead answer = qt.QMessageBox.question( self, "DEMONS is not installed", "DEMONS is not installed. Do you want to proceed with BRAINSTools instead?", qt.QMessageBox.Yes | qt.QMessageBox.No ) if answer == qt.QMessageBox.No: # if no, exit here and stay at this step self.validationFailed( desiredBranchId, '', '', False ) return # same for DRAMMS if self.mrmlManager().GetRegistrationPackageType() == self.mrmlManager().GetPackageTypeFromString( 'DRAMMS' ): # dramms was selected drammsPath = tcl( "::EMSegmenterPreProcessingTcl::Get_DRAMMS_Installation_Path" ) if drammsPath == "": # dramms was not found, ask if we want BRAINSFit instead answer = qt.QMessageBox.question( self, "DRAMMS is not installed", "DRAMMS is not installed. Do you want to proceed with BRAINSTools instead?", qt.QMessageBox.Yes | qt.QMessageBox.No ) if answer == qt.QMessageBox.No: # if no, exit here and stay at this step self.validationFailed( desiredBranchId, '', '', False ) return # same for ANTS if self.mrmlManager().GetRegistrationPackageType() == self.mrmlManager().GetPackageTypeFromString( 'ANTS' ): # ANTS was selected antsPath = tcl( "::EMSegmenterPreProcessingTcl::Get_ANTS_Installation_Path" ) if antsPath == "": # ANTS was not found, ask if we want BRAINSFit instead answer = qt.QMessageBox.question( self, "ANTS is not installed", "ANTS is not installed. Do you want to proceed with BRAINSTools instead?", qt.QMessageBox.Yes | qt.QMessageBox.No ) if answer == qt.QMessageBox.No: # if no, exit here and stay at this step self.validationFailed( desiredBranchId, '', '', False ) return # # check if we should ask questions before running preprocessing and if yes do so! # if not self.__askQuestionsBeforeRunningPreprocessing: # no questions, just run it self.validationSucceeded( desiredBranchId ) return # check if preprocessing already ran # if yes, ask for redo # if no, ask for start (which takes some time) workingDataNode = self.mrmlManager().GetWorkingDataNode() preprocessingAlreadyDone = ( workingDataNode.GetAlignedTargetNodeIsValid() and workingDataNode.GetAlignedAtlasNodeIsValid() ) if preprocessingAlreadyDone: # ask if we should do it again answer = qt.QMessageBox.question( self, "Redo Pre-processing of images?", "Do you want to redo pre-processing of input images?", qt.QMessageBox.Yes | qt.QMessageBox.No ) if answer == qt.QMessageBox.No: # no calculation self.__performCalculation = False else: # calculation self.__performCalculation = True else: # ask if we should run preprocessing # if not, stay at this step answer = qt.QMessageBox.question( self, "Start Pre-processing of images?", "Pre-processing of images might take a while. Do you want to proceed?", qt.QMessageBox.Yes | qt.QMessageBox.No ) if answer == qt.QMessageBox.No: # if no, exit here and stay at this step self.validationFailed( desiredBranchId, '', '', False ) return else: # perform the calculation! self.__performCalculation = True self.validationSucceeded( desiredBranchId )
def findEffects(self, path=""): # for now, the built in effects are hard-coded to facilitate # the icons and layout self.effects = [] # if a list of effects was supplied, then use that list instead of all of the effects # don't forget to check that the supplied effects are valid: ensure they exist in the lists of available effects if (self.suppliedEffects): self.mouseTools = tuple( self.listIntersection(self.suppliedEffects, EditBox.availableMouseTools)) self.operations = tuple( self.listIntersection(self.suppliedEffects, EditBox.availableOperations)) self.nonmodal = tuple( self.listIntersection(self.suppliedEffects, EditBox.availableNonmodal)) self.disabled = tuple( self.listIntersection(self.suppliedEffects, EditBox.availableDisabled)) # if a list of effects is not supplied, then provide all effects else: self.mouseTools = EditBox.availableMouseTools self.operations = EditBox.availableOperations self.nonmodal = EditBox.availableNonmodal self.disabled = EditBox.availableDisabled ''' for key in slicer.modules.editorExtensions.keys(): e = slicer.modules.editorExtensions[key]() if 'MouseTool' in e.attributes: self.mouseTools.append(key) if 'Nonmodal' in e.attributes: self.operations.append(key) if 'Disabled' in e.attributes: self.disabled.append(key) ''' # combined list of all effects self.effects = self.mouseTools + self.operations # add any extensions that have been registered self.effects = self.effects + tuple( slicer.modules.editorExtensions.keys()) # for each effect # - look for implementation class of pattern *Effect # - get an icon name for the pushbutton iconDir = os.environ['SLICER_HOME'] + '/' + os.environ[ 'SLICER_SHARE_DIR'] + '/Tcl/ImageData/' self.effectClasses = {} self.effectIconFiles = {} self.effectModes = {} self.icons = {} for effect in self.effects: tclclass = tcl('info command %sEffect' % effect) if tclclass != '': self.effectClasses[effect] = tclclass else: self.effectClasses[effect] = "EffectSWidget" for iconType in ("", "Selected", "Disabled"): self.effectIconFiles[ effect, iconType] = iconDir + effect + iconType + '.png' iconMode = "" if self.disabled.__contains__(effect): # - don't use the disabled icon for now - Qt's setEnabled method works fine #iconMode = "Disabled" pass self.effectModes[effect] = iconMode
def RotateToVolumePlanes(): # AF TODO: check with Steve if this has any undesired consequences tcl('EffectSWidget::RotateToVolumePlanes')
def createUserInterface(self): ''' ''' slicer.modules.emsegmentinitialdistance = 4 # just call to copy the emsegmenter task to a temp dir self.logic().GetTasks() self.__layout = super(EMSegmentQuickStep1, self).createUserInterface() infoLabel = qt.QLabel( 'This module provides EM segmentation without an atlas.\nIt is possible to segment different structures by manual sampling.\n\n' ) infoLabel.setFont(self.getBoldFont()) self.__layout.addWidget(infoLabel) # the input channels inputChannelGroupBox = qt.QGroupBox() inputChannelGroupBox.setTitle('Input Datasets') inputChannelGroupBox.toolTip = 'Please configure the datasets which should be segmented.' self.__layout.addWidget(inputChannelGroupBox) inputChannelGroupBoxLayout = qt.QFormLayout(inputChannelGroupBox) self.__inputChannelList = slicer.modulewidget.qSlicerEMSegmentInputChannelListWidget( ) self.__inputChannelList.setMRMLManager(self.mrmlManager()) inputChannelGroupBoxLayout.addWidget(self.__inputChannelList) # add empty row self.__layout.addRow("", qt.QWidget()) # # dynamic frame # dynamicFrame = qt.QGroupBox() dynamicFrame.setTitle('Check List') dynamicFrame.toolTip = 'Please check anything applicable.' self.__layout.addWidget(dynamicFrame) dynamicFrameLayout = qt.QVBoxLayout(dynamicFrame) # .. now pass the layout to the dynamicFrame self.dynamicFrame().setLayout(dynamicFrameLayout) # # end of dynamic frame # # check if we have a valid EMEasy MRML Node templateNodes = slicer.mrmlScene.GetNodesByClassByName( 'vtkMRMLEMSTemplateNode', 'EMEasy') if templateNodes.GetNumberOfItems() > 0: # we load the last template node which fits the taskname templateNode = templateNodes.GetItemAsObject( templateNodes.GetNumberOfItems() - 1) loadResult = self.mrmlManager().SetLoadedParameterSetIndex( templateNode) if int(loadResult) != 0: Helper.Info( "EMS node is corrupted - the manager could not be updated with new task: " + taskName) #return False else: Helper.Info("Loading completed.") self.logic().DefineTclTaskFileFromMRML() # clear the dynamic panel self.dynamicFrame().setMRMLManager(self.mrmlManager()) self.dynamicFrame().clearElements() self.logic().SourceTaskFiles() slicer.modules.emsegmentAdvancedDynamicFrame = self.dynamicFrame() logicTclName = self.logic().GetSlicerCommonInterface( ).GetTclNameFromPointer(self.logic()) tcl('::EMSegmenterPreProcessingTcl::ShowUserInterface ' + str(logicTclName)) slicer.modules.emsegmenteasystep2.disableNumberOfStructures() self.__initialized = True
class EditBox(object): def __init__(self, parent=0, optionsFrame=None, embedded=False, suppliedEffects=[]): self.effects = [] self.effectButtons = {} self.effectMapper = qt.QSignalMapper() self.effectMapper.connect('mapped(const QString&)', self.selectEffect) self.editUtil = EditUtil.EditUtil() # check for extensions - if none have been registered, just create the empty dictionary try: slicer.modules.editorExtensions except AttributeError: slicer.modules.editorExtensions = {} # embedded boolean specifies whether or not this edit box is to be embedded # into another moduleWidget # - if it is, all effect buttons will be displayed in a single row self.embedded = embedded # save the list of supplied effects that the caller wants to use # (should be a subset of EditBox.availableMouseTools + EditBox.availableOperations) self.suppliedEffects = suppliedEffects if parent == 0: self.parent = qt.QFrame() self.parent.setLayout(qt.QVBoxLayout()) self.create() self.parent.show() else: self.parent = parent self.create() # frame that holds widgets specific for each effect if not optionsFrame: self.optionsFrame = qt.QFrame(self.parent) else: self.optionsFrame = optionsFrame # state variables for selected effect in the box # - currentOption is an instance of an option GUI # - currentTools is a list of EffectTool instances self.currentOption = None self.currentTools = [] # # Public lists of the available effects provided by the editor # # effects that change the mouse cursor availableMouseTools = ( "ChangeIsland", "ChooseColor", "ImplicitCube", "ImplicitEllipse", "ImplicitRectangle", "Draw", "RemoveIslands", "ConnectedComponents", "ThresholdBucket", "ThresholdPaintLabel", "SaveIsland", "SlurpColor", "Paint", "DefaultTool", "LevelTracing", "MakeModel", "Wand", "GrowCutSegment", ) # effects that operate from the menu availableOperations = ( "ErodeLabel", "DilateLabel", "DeleteFiducials", "LabelOpacity", "ChangeLabel", "FiducialVisibilityOff", "FiducialVisibilityOn", "GoToEditorModule", "IdentifyIslands", "LabelVisibilityOff", "LabelVisibilityOn", "NextFiducial", "SnapToGridOff", "SnapToGridOn", "EraseLabel", "Threshold", "PinOpen", "PreviousFiducial", "InterpolateLabels", "LabelOpacity", "ToggleLabelOutline", "Watershed", "PreviousCheckPoint", "NextCheckPoint", ) # these buttons do not switch you out of the current tool availableNonmodal = ("FiducialVisibilityOn", "LabelVisibilityOff", "LabelVisibilityOn", "NextFiducial", "PreviousFiducial", "DeleteFiducials", "SnapToGridOn", "SnapToGridOff", "EraseLabel", "PreviousCheckPoint", "NextCheckPoint", "ToggleLabelOutline", "SnapToGridOff", "SnapToGridOn", "LabelOpacity") # these buttons start disabled (check points will re-enable when circumstances are right) availableDisabled = ( "ChooseColor", "ImplicitCube", "ImplicitEllipse", "ConnectedComponents", "SlurpColor", "ThresholdPaintLabel", "ThresholdBucket", "DeleteFiducials", "LabelOpacity", "FiducialVisibilityOff", "FiducialVisibilityOn", "LabelVisibilityOff", "LabelVisibilityOn", "SnapToGridOff", "SnapToGridOn", "InterpolateLabels", "LabelOpacity", "ToggleLabelOutline", "Watershed", "Wand", ) # allow overriding the developers name of the tool for a more user-friendly label name displayNames = {} displayNames["PreviousCheckPoint"] = "Undo" displayNames["NextCheckPoint"] = "Redo" # calculates the intersection of two flat lists @classmethod def listIntersection(cls, inList1, inList2): outList = [val for val in inList1 if val in inList2] return outList # fill the _effects array bases on what you find in the interpreter # if a list of effects was supplied, then use that list instead of all of the effects def findEffects(self, path=""): # for now, the built in effects are hard-coded to facilitate # the icons and layout self.effects = [] # if a list of effects was supplied, then use that list instead of all of the effects # don't forget to check that the supplied effects are valid: ensure they exist in the lists of available effects if (self.suppliedEffects): self.mouseTools = tuple( self.listIntersection(self.suppliedEffects, EditBox.availableMouseTools)) self.operations = tuple( self.listIntersection(self.suppliedEffects, EditBox.availableOperations)) self.nonmodal = tuple( self.listIntersection(self.suppliedEffects, EditBox.availableNonmodal)) self.disabled = tuple( self.listIntersection(self.suppliedEffects, EditBox.availableDisabled)) # if a list of effects is not supplied, then provide all effects else: self.mouseTools = EditBox.availableMouseTools self.operations = EditBox.availableOperations self.nonmodal = EditBox.availableNonmodal self.disabled = EditBox.availableDisabled ''' for key in slicer.modules.editorExtensions.keys(): e = slicer.modules.editorExtensions[key]() if 'MouseTool' in e.attributes: self.mouseTools.append(key) if 'Nonmodal' in e.attributes: self.operations.append(key) if 'Disabled' in e.attributes: self.disabled.append(key) ''' # combined list of all effects self.effects = self.mouseTools + self.operations # add any extensions that have been registered self.effects = self.effects + tuple( slicer.modules.editorExtensions.keys()) # for each effect # - look for implementation class of pattern *Effect # - get an icon name for the pushbutton iconDir = os.environ['SLICER_HOME'] + '/' + os.environ[ 'SLICER_SHARE_DIR'] + '/Tcl/ImageData/' self.effectClasses = {} self.effectIconFiles = {} self.effectModes = {} self.icons = {} for effect in self.effects: tclclass = tcl('info command %sEffect' % effect) if tclclass != '': self.effectClasses[effect] = tclclass else: self.effectClasses[effect] = "EffectSWidget" for iconType in ("", "Selected", "Disabled"): self.effectIconFiles[ effect, iconType] = iconDir + effect + iconType + '.png' iconMode = "" if self.disabled.__contains__(effect): # - don't use the disabled icon for now - Qt's setEnabled method works fine #iconMode = "Disabled" pass self.effectModes[effect] = iconMode # # create a row of the edit box given a list of # effect names (items in _effects(list) # def createButtonRow(self, effects, rowLabel=""): f = qt.QFrame(self.parent) self.parent.layout().addWidget(f) self.rowFrames.append(f) hbox = qt.QHBoxLayout() f.setLayout(hbox) if rowLabel: label = qt.QLabel(rowLabel) hbox.addWidget(label) for effect in effects: # check that the effect belongs in our list of effects before including # (handles non-embedded widgets where the caller has supplied a custom list of effects) if (effect in self.effects): i = self.icons[effect] = qt.QIcon( self.effectIconFiles[effect, self.effectModes[effect]]) a = self.actions[effect] = qt.QAction(i, '', f) self.effectButtons[effect] = b = self.buttons[ effect] = qt.QToolButton() b.setDefaultAction(a) b.setToolTip(effect) if EditBox.displayNames.has_key(effect): b.setToolTip(EditBox.displayNames[effect]) hbox.addWidget(b) if self.disabled.__contains__(effect): b.setDisabled(1) # Setup the mapping between button and its associated effect name self.effectMapper.setMapping(self.buttons[effect], effect) # Connect button with signal mapper self.buttons[effect].connect('clicked()', self.effectMapper, 'map()') hbox.addStretch(1) # create the edit box def create(self): self.findEffects() # # the buttons # self.rowFrames = [] self.actions = {} self.buttons = {} self.icons = {} self.callbacks = {} # if not using embedded format: create all of the buttons # createButtonRow() ensures that only effects in self.effects are exposed, # so if the user supplied a list of effects only those in that list will be exposed if (not self.embedded): self.createButtonRow( ("DefaultTool", "EraseLabel", "Paint", "Draw", "LevelTracing", "ImplicitRectangle", "IdentifyIslands", "ChangeIsland", "RemoveIslands", "SaveIsland")) self.createButtonRow( ("ErodeLabel", "DilateLabel", "Threshold", "ChangeLabel", "MakeModel", "GrowCutSegment")) extensions = [] for k in slicer.modules.editorExtensions: extensions.append(k) self.createButtonRow(extensions) # TODO: add back prev/next fiducial #self.createButtonRow( ("PreviousFiducial", "NextFiducial") ) self.createButtonRow(("PreviousCheckPoint", "NextCheckPoint"), rowLabel="Undo/Redo: ") # if using embedded format: create all of the buttons in the effects list in a single row else: self.createButtonRow(self.effects) # # the labels (not shown in embedded format) # self.toolsActiveToolFrame = qt.QFrame(self.parent) self.toolsActiveToolFrame.setLayout(qt.QHBoxLayout()) self.parent.layout().addWidget(self.toolsActiveToolFrame) self.toolsActiveTool = qt.QLabel(self.toolsActiveToolFrame) self.toolsActiveTool.setText('Active Tool:') self.toolsActiveTool.setStyleSheet( "background-color: rgb(232,230,235)") self.toolsActiveToolFrame.layout().addWidget(self.toolsActiveTool) self.toolsActiveToolName = qt.QLabel(self.toolsActiveToolFrame) self.toolsActiveToolName.setText('') self.toolsActiveToolName.setStyleSheet( "background-color: rgb(232,230,235)") self.toolsActiveToolFrame.layout().addWidget(self.toolsActiveToolName) self.updateCheckPointButtons() def setActiveToolLabel(self, name): if EditBox.displayNames.has_key(name): name = EditBox.displayNames[name] self.toolsActiveToolName.setText(name) # needs to be a valid effect name and state of "", Disabled, or Selected TODO = """ itcl::body EditBox::setButtonState {effect state} { $::slicer3::ApplicationGUI SetIconImage \ $_effects($effect,icon) $_effects($effect,imageData$state) $o($effect,button) SetImageToIcon $_effects($effect,icon) switch $state { Selected - "" { $o($effect,button) SetState 1 } "Disabled" { $o($effect,button) SetState 0 } } } """ # # Pause running the current effect, reverting to the default tool # def pauseEffect(self): self.selectEffect("DefaultTool") # # Resume running the effect that was being used before a pause (TODO) # def resumeEffect(self): pass # # manage the editor effects # def selectEffect(self, effect): from slicer import app # # if a modal effect was selected, build an options GUI # - check to see if it is an extension effect, # if not, try to create it, else ignore it # For extensions, look for 'effect'Options and 'effect'Tool # in the editorExtensions map and use those to create the # effect # if not self.nonmodal.__contains__(effect): if self.currentOption: self.currentOption.__del__() self.currentOption = None for tool in self.currentTools: tool.cleanup() self.currentTools = [] if effect in slicer.modules.editorExtensions.keys(): extensionEffect = slicer.modules.editorExtensions[effect]() self.currentOption = extensionEffect.options(self.optionsFrame) layoutManager = slicer.app.layoutManager() sliceNodeCount = slicer.mrmlScene.GetNumberOfNodesByClass( 'vtkMRMLSliceNode') for nodeIndex in xrange(sliceNodeCount): # find the widget for each node in scene sliceNode = slicer.mrmlScene.GetNthNodeByClass( nodeIndex, 'vtkMRMLSliceNode') sliceWidget = layoutManager.sliceWidget( sliceNode.GetLayoutName()) if sliceWidget: tool = extensionEffect.tool(sliceWidget) self.currentTools.append(tool) else: try: options = eval("%sOptions" % effect) self.currentOption = options(self.optionsFrame) except NameError, AttributeError: # No options for this effect, skip it pass # # If there is no background volume or label map, do nothing # # TODO should do this regardless of whether or not there is an option if not self.editUtil.getBackgroundVolume(): return if not self.editUtil.getLabelVolume(): return app.restoreOverrideCursor() self.setActiveToolLabel(effect) if not self.nonmodal.__contains__(effect): tcl('EffectSWidget::RemoveAll') tcl('EditorSetActiveToolLabel %s' % effect) # mouse tool changes cursor, and dismisses popup/menu mouseTool = False if self.mouseTools.__contains__(effect): mouseTool = True if effect == "DefaultTool": # do nothing - this will reset cursor mode tcl('EditorSetActiveToolLabel DefaultTool') elif effect == "GoToEditorModule": tcl('EditorSelectModule') tcl('EditorSetActiveToolLabel DefaultTool') elif effect == "LabelCheckPoint": # save a copy of the current label layer into the scene tcl('EditorLabelCheckPoint') tcl('EditorSetActiveToolLabel DefaultTool') elif effect == "PreviousFiducial": tcl('::FiducialsSWidget::JumpAllToNextFiducial -1') tcl('EditorSetActiveToolLabel DefaultTool') elif effect == "NextFiducial": tcl('::FiducialsSWidget::JumpAllToNextFiducial 1') tcl('EditorSetActiveToolLabel DefaultTool') elif effect == "EraseLabel": tcl('EditorToggleErasePaintLabel') elif effect == "PreviousCheckPoint": tcl('EditorPerformPreviousCheckPoint') elif effect == "NextCheckPoint": tcl('EditorPerformNextCheckPoint') else: if effect == "GrowCutSegment": self.editorGestureCheckPoint() #volumesLogic = slicer.modules.volumes.logic() #print ("VolumesLogic is %s " % volumesLogic) #tcl('EditorGestureCheckPoint $%s' % volumesLogic) if mouseTool: # TODO: make some nice custom cursor shapes # - for now use the built in override cursor #pix = qt.QPixmap() #pix.load(self.effectIconFiles[effect,""]) #cursor = qt.QCursor(pix) #app.setOverrideCursor(cursor, 0, 0) cursor = qt.QCursor(1) app.setOverrideCursor(cursor) else: app.restoreOverrideCursor() # # create an instance of the effect for each of the active sliceGUIs # - have the effect reset the tool label when completed # ret = tcl('catch "EffectSWidget::Add %s" res' % self.effectClasses[effect]) if ret != '0': dialog = qt.QErrorMessage(self.parent) dialog.showMessage( "Could not select effect.\n\nError was:\n%s" % tcl('set res')) else: tcl('EffectSWidget::ConfigureAll %s -exitCommand "EditorSetActiveToolLabel DefaultTool"' % self.effectClasses[effect])
def createUserInterface( self ): ''' ''' slicer.modules.emsegmentinitialdistance = 4 # just call to copy the emsegmenter task to a temp dir self.logic().GetTasks() self.__layout = super( EMSegmentQuickStep1, self ).createUserInterface() infoLabel = qt.QLabel( 'This module provides EM segmentation without an atlas.\nIt is possible to segment different structures by manual sampling.\n\n' ) infoLabel.setFont( self.getBoldFont() ) self.__layout.addWidget( infoLabel ) # the input channels inputChannelGroupBox = qt.QGroupBox() inputChannelGroupBox.setTitle( 'Input Datasets' ) inputChannelGroupBox.toolTip = 'Please configure the datasets which should be segmented.' self.__layout.addWidget( inputChannelGroupBox ) inputChannelGroupBoxLayout = qt.QFormLayout( inputChannelGroupBox ) self.__inputChannelList = slicer.qSlicerEMSegmentInputChannelListWidget() self.__inputChannelList.setMRMLManager( self.mrmlManager() ) inputChannelGroupBoxLayout.addWidget( self.__inputChannelList ) # add empty row self.__layout.addRow( "", qt.QWidget() ) # # dynamic frame # dynamicFrame = qt.QGroupBox() dynamicFrame.setTitle( 'Check List' ) dynamicFrame.toolTip = 'Please check anything applicable.' self.__layout.addWidget( dynamicFrame ) dynamicFrameLayout = qt.QVBoxLayout( dynamicFrame ) # .. now pass the layout to the dynamicFrame self.dynamicFrame().setLayout( dynamicFrameLayout ) # # end of dynamic frame # # check if we have a valid EMEasy MRML Node templateNodes = slicer.mrmlScene.GetNodesByClassByName( 'vtkMRMLEMSTemplateNode', 'EMEasy' ) if templateNodes.GetNumberOfItems() > 0: # we load the last template node which fits the taskname templateNode = templateNodes.GetItemAsObject( templateNodes.GetNumberOfItems() - 1 ) loadResult = self.mrmlManager().SetLoadedParameterSetIndex( templateNode ) if int( loadResult ) != 0: Helper.Info( "EMS node is corrupted - the manager could not be updated with new task: " + taskName ) #return False else: Helper.Info( "Loading completed." ) self.logic().DefineTclTaskFileFromMRML() # clear the dynamic panel self.dynamicFrame().setMRMLManager( self.mrmlManager() ) self.dynamicFrame().clearElements() self.logic().SourceTaskFiles() slicer.modules.emsegmentAdvancedDynamicFrame = self.dynamicFrame() logicTclName = self.logic().GetSlicerCommonInterface().GetTclNameFromPointer( self.logic() ) tcl( '::EMSegmenterPreProcessingTcl::ShowUserInterface ' + str( logicTclName ) ) slicer.modules.emsegmenteasystep2.disableNumberOfStructures() self.__initialized = True
def validate(self, desiredBranchId): ''' ''' super(EMSegmentDefinePreprocessingStep, self).validate(desiredBranchId) # check if CMTK should be used, # then try to find it # if this fails, ask if we should use BRAINSFit if self.mrmlManager().GetRegistrationPackageType() == self.mrmlManager( ).GetPackageTypeFromString('CMTK'): # cmtk was selected cmtkPath = tcl( "::EMSegmenterPreProcessingTcl::Get_CMTK_Installation_Path") if cmtkPath == "": # cmtk was not found, ask if we want BRAINSFit instead answer = qt.QMessageBox.question( self, "CMTK is not installed", "CMTK is not installed. Do you want to proceed with BRAINSTools instead?", qt.QMessageBox.Yes | qt.QMessageBox.No) if answer == qt.QMessageBox.No: # if no, exit here and stay at this step self.validationFailed(desiredBranchId, '', '', False) return # same for plastimatch if self.mrmlManager().GetRegistrationPackageType() == self.mrmlManager( ).GetPackageTypeFromString('PLASTIMATCH'): # plastimatch was selected plastimatchPath = tcl( "::EMSegmenterPreProcessingTcl::Get_PLASTIMATCH_Installation_Path" ) if plastimatchPath == "": # plastimatch was not found, ask if we want BRAINSFit instead answer = qt.QMessageBox.question( self, "PLASTIMATCH is not installed", "PLASTIMATCH is not installed. Do you want to proceed with BRAINSTools instead?", qt.QMessageBox.Yes | qt.QMessageBox.No) if answer == qt.QMessageBox.No: # if no, exit here and stay at this step self.validationFailed(desiredBranchId, '', '', False) return # same for DEMONS if self.mrmlManager().GetRegistrationPackageType() == self.mrmlManager( ).GetPackageTypeFromString('DEMONS'): # DEMONS was selected demonsPath = tcl( "::EMSegmenterPreProcessingTcl::Get_DEMONS_Installation_Path") if demonsPath == "": # demons was not found, ask if we want BRAINSFit instead answer = qt.QMessageBox.question( self, "DEMONS is not installed", "DEMONS is not installed. Do you want to proceed with BRAINSTools instead?", qt.QMessageBox.Yes | qt.QMessageBox.No) if answer == qt.QMessageBox.No: # if no, exit here and stay at this step self.validationFailed(desiredBranchId, '', '', False) return # same for DRAMMS if self.mrmlManager().GetRegistrationPackageType() == self.mrmlManager( ).GetPackageTypeFromString('DRAMMS'): # dramms was selected drammsPath = tcl( "::EMSegmenterPreProcessingTcl::Get_DRAMMS_Installation_Path") if drammsPath == "": # dramms was not found, ask if we want BRAINSFit instead answer = qt.QMessageBox.question( self, "DRAMMS is not installed", "DRAMMS is not installed. Do you want to proceed with BRAINSTools instead?", qt.QMessageBox.Yes | qt.QMessageBox.No) if answer == qt.QMessageBox.No: # if no, exit here and stay at this step self.validationFailed(desiredBranchId, '', '', False) return # same for ANTS if self.mrmlManager().GetRegistrationPackageType() == self.mrmlManager( ).GetPackageTypeFromString('ANTS'): # ANTS was selected antsPath = tcl( "::EMSegmenterPreProcessingTcl::Get_ANTS_Installation_Path") if antsPath == "": # ANTS was not found, ask if we want BRAINSFit instead answer = qt.QMessageBox.question( self, "ANTS is not installed", "ANTS is not installed. Do you want to proceed with BRAINSTools instead?", qt.QMessageBox.Yes | qt.QMessageBox.No) if answer == qt.QMessageBox.No: # if no, exit here and stay at this step self.validationFailed(desiredBranchId, '', '', False) return # # check if we should ask questions before running preprocessing and if yes do so! # if not self.__askQuestionsBeforeRunningPreprocessing: # no questions, just run it self.validationSucceeded(desiredBranchId) return # check if preprocessing already ran # if yes, ask for redo # if no, ask for start (which takes some time) workingDataNode = self.mrmlManager().GetWorkingDataNode() preprocessingAlreadyDone = ( workingDataNode.GetAlignedTargetNodeIsValid() and workingDataNode.GetAlignedAtlasNodeIsValid()) if preprocessingAlreadyDone: # ask if we should do it again answer = qt.QMessageBox.question( self, "Redo Pre-processing of images?", "Do you want to redo pre-processing of input images?", qt.QMessageBox.Yes | qt.QMessageBox.No) if answer == qt.QMessageBox.No: # no calculation self.__performCalculation = False else: # calculation self.__performCalculation = True else: # ask if we should run preprocessing # if not, stay at this step answer = qt.QMessageBox.question( self, "Start Pre-processing of images?", "Pre-processing of images might take a while. Do you want to proceed?", qt.QMessageBox.Yes | qt.QMessageBox.No) if answer == qt.QMessageBox.No: # if no, exit here and stay at this step self.validationFailed(desiredBranchId, '', '', False) return else: # perform the calculation! self.__performCalculation = True self.validationSucceeded(desiredBranchId)
def findEffects(self, path=""): # for now, the built in effects are hard-coded to facilitate # the icons and layout self.effects = [] # if a list of effects was supplied, then use that list instead of all of the effects # don't forget to check that the supplied effects are valid: ensure they exist in the lists of available effects if (self.suppliedEffects): self.mouseTools = tuple(self.listIntersection(self.suppliedEffects, EditBox.availableMouseTools)) self.operations = tuple(self.listIntersection(self.suppliedEffects, EditBox.availableOperations)) self.nonmodal = tuple(self.listIntersection(self.suppliedEffects, EditBox.availableNonmodal)) self.disabled = tuple(self.listIntersection(self.suppliedEffects, EditBox.availableDisabled)) # if a list of effects is not supplied, then provide all effects else: self.mouseTools = EditBox.availableMouseTools self.operations = EditBox.availableOperations self.nonmodal = EditBox.availableNonmodal self.disabled = EditBox.availableDisabled ''' for key in slicer.modules.editorExtensions.keys(): e = slicer.modules.editorExtensions[key]() if 'MouseTool' in e.attributes: self.mouseTools.append(key) if 'Nonmodal' in e.attributes: self.operations.append(key) if 'Disabled' in e.attributes: self.disabled.append(key) ''' # combined list of all effects self.effects = self.mouseTools + self.operations # add any extensions that have been registered self.effects = self.effects + tuple(slicer.modules.editorExtensions.keys()) # for each effect # - look for implementation class of pattern *Effect # - get an icon name for the pushbutton iconDir = os.environ['SLICER_HOME'] + '/' + os.environ['SLICER_SHARE_DIR'] + '/Tcl/ImageData/' self.effectClasses = {} self.effectIconFiles = {} self.effectModes = {} self.icons = {} for effect in self.effects: tclclass = tcl('info command %sEffect' % effect) if tclclass != '': self.effectClasses[effect] = tclclass else: self.effectClasses[effect] = "EffectSWidget" for iconType in ( "", "Selected", "Disabled" ): self.effectIconFiles[effect,iconType] = iconDir + effect + iconType + '.png' iconMode = "" if self.disabled.__contains__(effect): # - don't use the disabled icon for now - Qt's setEnabled method works fine #iconMode = "Disabled" pass self.effectModes[effect] = iconMode