def createUserInterface(self):
        """ This step is mostly empty. A volume rendering threshold is added to be useful.
		"""

        self.__layout = self.__parent.createUserInterface()

        self.__threshRange = slicer.qMRMLRangeWidget()
        self.__threshRange.decimals = 0
        self.__threshRange.singleStep = 1
        self.__threshRange.connect('valuesChanged(double,double)',
                                   self.onThresholdChanged)
        qt.QTimer.singleShot(0, self.killButton)

        ThreshGroupBox = qt.QGroupBox()
        ThreshGroupBox.setTitle('3D Visualization Intensity Threshold')
        ThreshGroupBoxLayout = qt.QFormLayout(ThreshGroupBox)
        ThreshGroupBoxLayout.addRow(self.__threshRange)
        self.__layout.addRow(ThreshGroupBox)

        editorWidgetParent = slicer.qMRMLWidget()
        editorWidgetParent.setLayout(qt.QVBoxLayout())
        editorWidgetParent.setMRMLScene(slicer.mrmlScene)
        self.__editorWidget = EditorWidget(parent=editorWidgetParent)
        self.__editorWidget.setup()
        self.__layout.addRow(editorWidgetParent)
        self.hideUnwantedEditorUIElements()

        RestartGroupBox = qt.QGroupBox()
        RestartGroupBox.setTitle('Restart')
        RestartGroupBoxLayout = qt.QFormLayout(RestartGroupBox)

        self.__RestartButton = qt.QPushButton('Return to Step 1')
        RestartGroupBoxLayout.addRow(self.__RestartButton)

        self.__RemoveCroppedSubtractionMap = qt.QCheckBox()
        self.__RemoveCroppedSubtractionMap.checked = True
        self.__RemoveCroppedSubtractionMap.setToolTip(
            "Delete the cropped version of your subtaction map.")
        RestartGroupBoxLayout.addRow("Delete cropped subtraction map: ",
                                     self.__RemoveCroppedSubtractionMap)

        self.__RemoveFullSubtracitonMap = qt.QCheckBox()
        self.__RemoveFullSubtracitonMap.checked = True
        self.__RemoveFullSubtracitonMap.setToolTip(
            "Delete the full version of your subtaction map.")
        RestartGroupBoxLayout.addRow("Delete full subtraction map: ",
                                     self.__RemoveFullSubtracitonMap)

        self.__RemoveROI = qt.QCheckBox()
        self.__RemoveROI.checked = False
        self.__RemoveROI.setToolTip(
            "Delete the ROI resulting from your subtaction map.")
        RestartGroupBoxLayout.addRow("Delete ROI: ", self.__RemoveROI)

        # self.__RestartButton.setEnabled(0)

        self.__RestartButton.connect('clicked()', self.Restart)
        self.__RestartActivated = True

        self.__layout.addRow(RestartGroupBox)
Exemple #2
0
 def setupEditorWidget(self):
     editorWidgetParent = slicer.qMRMLWidget()
     editorWidgetParent.setLayout(qt.QVBoxLayout())
     editorWidgetParent.setMRMLScene(slicer.mrmlScene)
     self.editorWidget = EditorWidget(parent=editorWidgetParent)
     self.editorWidget.setup()
     self.segmentationGroupBoxLayout.addWidget(self.editorWidget.parent)
 def __init__(self, parent=None, showVolumesFrame=False,
              activeTools=("DefaultTool", "DrawEffect", "RectangleEffect", "EraseLabel",
                           "PreviousCheckPoint", "NextCheckPoint")):
     """Constructor. Just invokes the parent's constructor"""         
     self.activeTools = activeTools
     # self.__masterVolume__ = scalarNode
     # self.__labelmapVolume__ = labelmapNode
     EditorWidget.__init__(self, parent, showVolumesFrame)
Exemple #4
0
 def __init__(self,
              parent=None,
              showVolumesFrame=True,
              activeTools=("DefaultTool", "PaintEffect", "DrawEffect",
                           "LevelTracingEffect", "RectangleEffect",
                           "EraseLabel", "PreviousCheckPoint",
                           "NextCheckPoint")):
     """Constructor. Just invokes the parent's constructor"""
     self.activeTools = activeTools
     EditorWidget.__init__(self, parent, showVolumesFrame)
 def __init__(self,
              parent=None,
              showVolumesFrame=False,
              activeTools=("DefaultTool", "DrawEffect", "RectangleEffect",
                           "EraseLabel", "PreviousCheckPoint",
                           "NextCheckPoint")):
     """Constructor. Just invokes the parent's constructor"""
     self.activeTools = activeTools
     # self.__masterVolume__ = scalarNode
     # self.__labelmapVolume__ = labelmapNode
     EditorWidget.__init__(self, parent, showVolumesFrame)
Exemple #6
0
    def createUserInterface(self):
        from Editor import EditorWidget

        self.__layout = self.__parent.createUserInterface()

        #endoSegmentButton = qt.QPushButton('Open Slicer Editor tool')
        #self.__layout.addRow(endoSegmentButton)
        #endoSegmentButton.connect('clicked()', self.startEditor)

        #TODO: Create label map and set it for editing by user?
        #volumesLogic = slicer.modules.volumes.logic()
        #headLabel = volumesLogic.CreateLabelVolume( slicer.mrmlScene, head, head.GetName() + '-segmentation' )

        #selectionNode = slicer.app.applicationLogic().GetSelectionNode()
        #selectionNode.SetReferenceActiveVolumeID( head.GetID() )
        #selectionNode.SetReferenceActiveLabelVolumeID( headLabel.GetID() )
        #slicer.app.applicationLogic().PropagateVolumeSelection(0)

        self.updateParameters(self.parameterNode())

        editorFrame = qt.QFrame()
        editorFrame.setLayout(qt.QVBoxLayout())
        palette = editorFrame.palette
        bgColor = 230
        palette.setColor(qt.QPalette.Background,
                         qt.QColor(bgColor, bgColor, bgColor))
        editorFrame.setPalette(palette)
        editorFrame.setAutoFillBackground(True)
        self.__layout.addRow(editorFrame)
        self.editorFrame = editorFrame
        global editorWidget
        self.editorWidget = EditorWidget(parent=self.editorFrame,
                                         showVolumesFrame=True)
        self.editorWidget.setup()
        self.editorWidget.enter()
        ##TODO: How to set the required merge node?

        wallCleanupSegLabel = qt.QLabel('Final Wall Segmentation Image:')
        self.__wallCleanupSegSelector = slicer.qMRMLNodeComboBox()
        self.__wallCleanupSegSelector.toolTip = "Choose the final wall segmentation label image."
        self.__wallCleanupSegSelector.nodeTypes = ['vtkMRMLScalarVolumeNode']
        self.__wallCleanupSegSelector.setMRMLScene(slicer.mrmlScene)
        self.__wallCleanupSegSelector.addEnabled = 0
        self.__layout.addRow(wallCleanupSegLabel,
                             self.__wallCleanupSegSelector)

        # Hide unnecessary button
        findChildren(text='AutomaticLeft*')[0].hide()
 def createUserInterface( self ):
   from Editor import EditorWidget
   
   self.__layout = self.__parent.createUserInterface()
      
   #TODO: Create label map and set it for editing by user?
   #volumesLogic = slicer.modules.volumes.logic()
   #headLabel = volumesLogic.CreateLabelVolume( slicer.mrmlScene, head, head.GetName() + '-segmentation' )
   
   #selectionNode = slicer.app.applicationLogic().GetSelectionNode()
   #selectionNode.SetReferenceActiveVolumeID( head.GetID() )
   #selectionNode.SetReferenceActiveLabelVolumeID( headLabel.GetID() )
   #slicer.app.applicationLogic().PropagateVolumeSelection(0)
   
   editorFrame = qt.QFrame()
   editorFrame.setLayout(qt.QVBoxLayout())
   palette = editorFrame.palette
   bgColor = 230
   palette.setColor(qt.QPalette.Background, qt.QColor(bgColor, bgColor, bgColor))
   editorFrame.setPalette(palette)
   editorFrame.setAutoFillBackground(True);
   self.__layout.addRow(editorFrame)
   self.editorFrame = editorFrame
   global editorWidget 
   self.editorWidget = EditorWidget(parent=self.editorFrame, showVolumesFrame=True)
   self.editorWidget.setup()
   self.editorWidget.enter()
 def setupEditorWidget(self):
   editorWidgetParent = slicer.qMRMLWidget()
   editorWidgetParent.setLayout(qt.QVBoxLayout())
   editorWidgetParent.setMRMLScene(slicer.mrmlScene)
   self.editorWidget = EditorWidget(parent=editorWidgetParent)
   self.editorWidget.setup()
   self.segmentationGroupBoxLayout.addWidget(self.editorWidget.parent)
 def createUserInterface( self ):
   from Editor import EditorWidget
   
   self.__layout = self.__parent.createUserInterface()
      
   #TODO: Create label map and set it for editing by user?
   #volumesLogic = slicer.modules.volumes.logic()
   #headLabel = volumesLogic.CreateLabelVolume( slicer.mrmlScene, head, head.GetName() + '-segmentation' )
   
   #selectionNode = slicer.app.applicationLogic().GetSelectionNode()
   #selectionNode.SetReferenceActiveVolumeID( head.GetID() )
   #selectionNode.SetReferenceActiveLabelVolumeID( headLabel.GetID() )
   #slicer.app.applicationLogic().PropagateVolumeSelection(0)
   
   editorFrame = qt.QFrame()
   editorFrame.setLayout(qt.QVBoxLayout())
   palette = editorFrame.palette
   bgColor = 230
   palette.setColor(qt.QPalette.Background, qt.QColor(bgColor, bgColor, bgColor))
   editorFrame.setPalette(palette)
   editorFrame.setAutoFillBackground(True);
   self.__layout.addRow(editorFrame)
   self.editorFrame = editorFrame
   global editorWidget 
   self.editorWidget = EditorWidget(parent=self.editorFrame, showVolumesFrame=True)
   self.editorWidget.setup()
   self.editorWidget.enter()
   
   endoSegLabel = qt.QLabel( 'Endo Segmentation Image:' )
   self.__endoSegSelector = slicer.qMRMLNodeComboBox()
   self.__endoSegSelector.toolTip = "Choose the endo segmentation label image."
   self.__endoSegSelector.nodeTypes = ['vtkMRMLScalarVolumeNode']
   self.__endoSegSelector.setMRMLScene(slicer.mrmlScene)
   self.__endoSegSelector.addEnabled = 0
   self.__layout.addRow( endoSegLabel, self.__endoSegSelector )
  def test_ThresholdThreading(self):
    """
    Test for issue 2329, using the slicer EditorLib components
    in outside of the editor.
    """

    #
    # first, get some sample data
    #
    import SampleData
    sampleDataLogic = SampleData.SampleDataLogic()
    head = sampleDataLogic.downloadMRHead()

    #
    # create a label map and set it for editing
    #
    volumesLogic = slicer.modules.volumes.logic()
    # AF: intentionally use the naming convention that does not match the one
    # used by Editor
    headLabel = volumesLogic.CreateAndAddLabelVolume( slicer.mrmlScene, head, head.GetName() + '-segmentation' )

    selectionNode = slicer.app.applicationLogic().GetSelectionNode()
    selectionNode.SetActiveVolumeID( head.GetID() )
    selectionNode.SetActiveLabelVolumeID( headLabel.GetID() )
    slicer.app.applicationLogic().PropagateVolumeSelection(0)

    #
    # Instantiate a new widget, and add Editor widget to it
    #
    from Editor import EditorWidget
    editorWidget = EditorWidget(showVolumesFrame=False)
 def setupEditorWidget(self):
   self.editorWidgetParent = slicer.qMRMLWidget()
   self.editorWidgetParent.setLayout(qt.QVBoxLayout())
   self.editorWidgetParent.setMRMLScene(slicer.mrmlScene)
   self.editUtil = EditorLib.EditUtil.EditUtil()
   self.editorWidget = EditorWidget(parent=self.editorWidgetParent, showVolumesFrame=False)
   self.editorWidget.setup()
   self.editorParameterNode = self.editUtil.getParameterNode()
    def createUserInterface(self):
        """ This UI takes advantage of a pre-built slicer thresholding widget.
        """

        self.__layout = self.__parent.createUserInterface()

        step_label = qt.QLabel(
            """Automatic segmentation with deep learning is not available in this demo, due to lack of computing resources. You may however create a segmentation using 3D Slicer's editor module in this step."""
        )
        step_label.setWordWrap(True)
        self.__informationGroupBox = qt.QGroupBox()
        self.__informationGroupBox.setTitle('Information')
        self.__informationGroupBoxLayout = qt.QFormLayout(
            self.__informationGroupBox)
        self.__informationGroupBoxLayout.addRow(step_label)
        self.__layout.addRow(self.__informationGroupBox)

        editorWidgetParent = slicer.qMRMLWidget()
        editorWidgetParent.setLayout(qt.QVBoxLayout())
        editorWidgetParent.setMRMLScene(slicer.mrmlScene)
        self.EditorWidget = EditorWidget(parent=editorWidgetParent)
        self.EditorWidget.setup()
        self.__layout.addRow(editorWidgetParent)

        # self.__thresholdGroupBox = qt.QGroupBox()
        # self.__thresholdGroupBox.setTitle('Threshold Range')
        # self.__thresholdGroupBoxLayout = qt.QFormLayout(self.__thresholdGroupBox)
        # threshLabel = qt.QLabel('Select Intensity Range:')
        # threshLabel.alignment = 4

        # self.__threshRange = slicer.qMRMLRangeWidget()
        # self.__threshRange.decimals = 0
        # self.__threshRange.singleStep = 1

        # self.__thresholdGroupBoxLayout.addRow(threshLabel)
        # self.__thresholdGroupBoxLayout.addRow(self.__threshRange)
        # self.__layout.addRow(self.__thresholdGroupBox)

        # self.__threshRange.connect('valuesChanged(double,double)', self.onThresholdChanged)
        qt.QTimer.singleShot(0, self.killButton)
Exemple #13
0
    def createUserInterface(self):
        from Editor import EditorWidget

        self.__layout = self.__parent.createUserInterface()

        #TODO: Create label map and set it for editing by user?
        #volumesLogic = slicer.modules.volumes.logic()
        #headLabel = volumesLogic.CreateLabelVolume( slicer.mrmlScene, head, head.GetName() + '-segmentation' )

        #selectionNode = slicer.app.applicationLogic().GetSelectionNode()
        #selectionNode.SetReferenceActiveVolumeID( head.GetID() )
        #selectionNode.SetReferenceActiveLabelVolumeID( headLabel.GetID() )
        #slicer.app.applicationLogic().PropagateVolumeSelection(0)

        editorFrame = qt.QFrame()
        editorFrame.setLayout(qt.QVBoxLayout())
        palette = editorFrame.palette
        bgColor = 230
        palette.setColor(qt.QPalette.Background,
                         qt.QColor(bgColor, bgColor, bgColor))
        editorFrame.setPalette(palette)
        editorFrame.setAutoFillBackground(True)
        self.__layout.addRow(editorFrame)
        self.editorFrame = editorFrame
        global editorWidget
        self.editorWidget = EditorWidget(parent=self.editorFrame,
                                         showVolumesFrame=True)
        self.editorWidget.setup()
        self.editorWidget.enter()

        endoSegLabel = qt.QLabel('Endo Segmentation Image:')
        self.__endoSegSelector = slicer.qMRMLNodeComboBox()
        self.__endoSegSelector.toolTip = "Choose the endo segmentation label image."
        self.__endoSegSelector.nodeTypes = ['vtkMRMLScalarVolumeNode']
        self.__endoSegSelector.setMRMLScene(slicer.mrmlScene)
        self.__endoSegSelector.addEnabled = 0
        self.__layout.addRow(endoSegLabel, self.__endoSegSelector)
  def createUserInterface( self ):
    from Editor import EditorWidget
    
    self.__layout = self.__parent.createUserInterface()
    
    #endoSegmentButton = qt.QPushButton('Open Slicer Editor tool')
    #self.__layout.addRow(endoSegmentButton)
    #endoSegmentButton.connect('clicked()', self.startEditor)
    
    #TODO: Create label map and set it for editing by user?
    #volumesLogic = slicer.modules.volumes.logic()
    #headLabel = volumesLogic.CreateLabelVolume( slicer.mrmlScene, head, head.GetName() + '-segmentation' )
    
    #selectionNode = slicer.app.applicationLogic().GetSelectionNode()
    #selectionNode.SetReferenceActiveVolumeID( head.GetID() )
    #selectionNode.SetReferenceActiveLabelVolumeID( headLabel.GetID() )
    #slicer.app.applicationLogic().PropagateVolumeSelection(0)
    
    self.updateParameters(self.parameterNode())
    
    editorFrame = qt.QFrame()
    editorFrame.setLayout(qt.QVBoxLayout())
    palette = editorFrame.palette
    bgColor = 230
    palette.setColor(qt.QPalette.Background, qt.QColor(bgColor, bgColor, bgColor))
    editorFrame.setPalette(palette)
    editorFrame.setAutoFillBackground(True);
    self.__layout.addRow(editorFrame)
    self.editorFrame = editorFrame
    global editorWidget 
    self.editorWidget = EditorWidget(parent=self.editorFrame, showVolumesFrame=True)
    self.editorWidget.setup()
    self.editorWidget.enter()
    ##TODO: How to set the required merge node?
    
    wallCleanupSegLabel = qt.QLabel( 'Final Wall Segmentation Image:' )
    self.__wallCleanupSegSelector = slicer.qMRMLNodeComboBox()
    self.__wallCleanupSegSelector.toolTip = "Choose the final wall segmentation label image."
    self.__wallCleanupSegSelector.nodeTypes = ['vtkMRMLScalarVolumeNode']
    self.__wallCleanupSegSelector.setMRMLScene(slicer.mrmlScene)
    self.__wallCleanupSegSelector.addEnabled = 0
    self.__layout.addRow( wallCleanupSegLabel, self.__wallCleanupSegSelector )

    # Hide unnecessary button
    findChildren( text = 'AutomaticLeft*')[0].hide()
class LASegmentationWorkflowEndoSegmentationStep( LASegmentationWorkflowStep ) :

  def __init__( self, stepid ):
    self.initialize( stepid )
    self.setName( '3. Segmentation of endocardium' )
    self.setDescription( 'Segment the endocardium using the Editor tools.' )

    self.__parent = super( LASegmentationWorkflowEndoSegmentationStep, self )

  def killButton(self):
    # Hide unneccesary button
    bl = slicer.util.findChildren(text='LAEndo*')
    if len(bl):
      bl[0].hide()

  def createUserInterface( self ):
    from Editor import EditorWidget
    
    self.__layout = self.__parent.createUserInterface()
       
    #TODO: Create label map and set it for editing by user?
    #volumesLogic = slicer.modules.volumes.logic()
    #headLabel = volumesLogic.CreateLabelVolume( slicer.mrmlScene, head, head.GetName() + '-segmentation' )
    
    #selectionNode = slicer.app.applicationLogic().GetSelectionNode()
    #selectionNode.SetReferenceActiveVolumeID( head.GetID() )
    #selectionNode.SetReferenceActiveLabelVolumeID( headLabel.GetID() )
    #slicer.app.applicationLogic().PropagateVolumeSelection(0)
    
    editorFrame = qt.QFrame()
    editorFrame.setLayout(qt.QVBoxLayout())
    palette = editorFrame.palette
    bgColor = 230
    palette.setColor(qt.QPalette.Background, qt.QColor(bgColor, bgColor, bgColor))
    editorFrame.setPalette(palette)
    editorFrame.setAutoFillBackground(True);
    self.__layout.addRow(editorFrame)
    self.editorFrame = editorFrame
    global editorWidget 
    self.editorWidget = EditorWidget(parent=self.editorFrame, showVolumesFrame=True)
    self.editorWidget.setup()
    self.editorWidget.enter()
    
  #def startEditor(self):
  #  from Editor import EditorWidget
  #  editorWidget = EditorWidget(showVolumesFrame=True)
    
  def validate( self, desiredBranchId ):
    self.__parent.validate( desiredBranchId )
    
    if endoSegVolume != None :
      self.__parent.validationSucceeded(desiredBranchId)
    else:
      self.__parent.validationFailed(desiredBranchId, 'Error','Endo segmentation step did not complete successfully.')
    
  def onEntry(self, comingFrom, transitionType):
    super(LASegmentationWorkflowEndoSegmentationStep, self).onEntry(comingFrom, transitionType)
    pNode = self.parameterNode()
    pNode.SetParameter('currentStep', self.stepid)

    qt.QTimer.singleShot(0, self.killButton)

  def onExit(self, goingTo, transitionType):    
    pNode = self.parameterNode()
    self.editorWidget.exit()
    
    super(LASegmentationWorkflowEndoSegmentationStep, self).onExit(goingTo, transitionType) 
Exemple #16
0
 def setup(self):
     EditorWidget.setup(self)
     self.infoIconLabel.setVisible(False)
     self.segmentEditorLabel.setVisible(False)
Exemple #17
0
class CMRToolkitWizardWallCleanupStep(CMRToolkitWizardStep):
    def __init__(self, stepid):
        self.initialize(stepid)
        self.setName('5. Edit Wall Segmentation')
        self.setDescription(
            'Set the wall segmentation image from the previous step as the merge volume in the Slicer Editor. Remove the pulmonary veins from the wall segmentation using the Slicer Editor erase tool and select the final label image to proceed.'
        )

        self.__parent = super(CMRToolkitWizardWallCleanupStep, self)

    def killButton(self):
        # Hide unneccesary button
        bl = slicer.util.findChildren(text='AutomaticLeft*')
        if len(bl):
            bl[0].hide()

    def createUserInterface(self):
        from Editor import EditorWidget

        self.__layout = self.__parent.createUserInterface()

        #endoSegmentButton = qt.QPushButton('Open Slicer Editor tool')
        #self.__layout.addRow(endoSegmentButton)
        #endoSegmentButton.connect('clicked()', self.startEditor)

        #TODO: Create label map and set it for editing by user?
        #volumesLogic = slicer.modules.volumes.logic()
        #headLabel = volumesLogic.CreateLabelVolume( slicer.mrmlScene, head, head.GetName() + '-segmentation' )

        #selectionNode = slicer.app.applicationLogic().GetSelectionNode()
        #selectionNode.SetReferenceActiveVolumeID( head.GetID() )
        #selectionNode.SetReferenceActiveLabelVolumeID( headLabel.GetID() )
        #slicer.app.applicationLogic().PropagateVolumeSelection(0)

        self.updateParameters(self.parameterNode())

        editorFrame = qt.QFrame()
        editorFrame.setLayout(qt.QVBoxLayout())
        palette = editorFrame.palette
        bgColor = 230
        palette.setColor(qt.QPalette.Background,
                         qt.QColor(bgColor, bgColor, bgColor))
        editorFrame.setPalette(palette)
        editorFrame.setAutoFillBackground(True)
        self.__layout.addRow(editorFrame)
        self.editorFrame = editorFrame
        global editorWidget
        self.editorWidget = EditorWidget(parent=self.editorFrame,
                                         showVolumesFrame=True)
        self.editorWidget.setup()
        self.editorWidget.enter()
        ##TODO: How to set the required merge node?

        wallCleanupSegLabel = qt.QLabel('Final Wall Segmentation Image:')
        self.__wallCleanupSegSelector = slicer.qMRMLNodeComboBox()
        self.__wallCleanupSegSelector.toolTip = "Choose the final wall segmentation label image."
        self.__wallCleanupSegSelector.nodeTypes = ['vtkMRMLScalarVolumeNode']
        self.__wallCleanupSegSelector.setMRMLScene(slicer.mrmlScene)
        self.__wallCleanupSegSelector.addEnabled = 0
        self.__layout.addRow(wallCleanupSegLabel,
                             self.__wallCleanupSegSelector)

        # Hide unnecessary button
        findChildren(text='AutomaticLeft*')[0].hide()

    def validate(self, desiredBranchId):
        self.__parent.validate(desiredBranchId)
        wallCleanupSegVolume = self.__wallCleanupSegSelector.currentNode()

        if wallCleanupSegVolume != None:
            wallCleanupSegID = wallCleanupSegVolume.GetID()
            pNode = self.parameterNode()
            pNode.SetParameter('wallCleanupSegID', wallCleanupSegID)
            Helper.SetLabelVolume(wallCleanupSegVolume.GetID())
            self.__parent.validationSucceeded(desiredBranchId)
        else:
            self.__parent.validationFailed(
                desiredBranchId, 'Error',
                'Please select the wall segmentation image to proceed.')

    def onEntry(self, comingFrom, transitionType):
        super(CMRToolkitWizardWallCleanupStep,
              self).onEntry(comingFrom, transitionType)
        pNode = self.parameterNode()
        pNode.SetParameter('currentStep', self.stepid)

        qt.QTimer.singleShot(0, self.killButton)

    ## TODO: Why does editor effect continue to the next workflow step?
    def onExit(self, goingTo, transitionType):
        pNode = self.parameterNode()

        #if goingTo.id() != 'PVAntrumCut':
        #  return

        self.editorWidget.exit()

        super(CMRToolkitWizardWallCleanupStep,
              self).onExit(goingTo, transitionType)

    def updateParameters(self, parameterNode):
        global wallSegVolume
        wallSegVolume = parameterNode.GetParameter('wallSegVolumeID')
class SegmentationStep(GBMWizardStep):
    def __init__(self, stepid):

        self.initialize(stepid)
        self.setName('5. Threshold')

        self.__vrDisplayNode = None
        self.__threshold = [-1, -1]

        # Initialize volume rendering.
        self.__vrLogic = slicer.modules.volumerendering.logic()
        self.__vrOpacityMap = None
        self.__vrColorMap = None

        self.__thresholdedLabelNode = None
        self.__roiVolume = None
        self.__visualizedVolume = None

        self.__parent = super(SegmentationStep, self)

    def createUserInterface(self):
        """ This UI takes advantage of a pre-built slicer thresholding widget.
        """

        self.__layout = self.__parent.createUserInterface()

        step_label = qt.QLabel(
            """Automatic segmentation with deep learning is not available in this demo, due to lack of computing resources. You may however create a segmentation using 3D Slicer's editor module in this step."""
        )
        step_label.setWordWrap(True)
        self.__informationGroupBox = qt.QGroupBox()
        self.__informationGroupBox.setTitle('Information')
        self.__informationGroupBoxLayout = qt.QFormLayout(
            self.__informationGroupBox)
        self.__informationGroupBoxLayout.addRow(step_label)
        self.__layout.addRow(self.__informationGroupBox)

        editorWidgetParent = slicer.qMRMLWidget()
        editorWidgetParent.setLayout(qt.QVBoxLayout())
        editorWidgetParent.setMRMLScene(slicer.mrmlScene)
        self.EditorWidget = EditorWidget(parent=editorWidgetParent)
        self.EditorWidget.setup()
        self.__layout.addRow(editorWidgetParent)

        # self.__thresholdGroupBox = qt.QGroupBox()
        # self.__thresholdGroupBox.setTitle('Threshold Range')
        # self.__thresholdGroupBoxLayout = qt.QFormLayout(self.__thresholdGroupBox)
        # threshLabel = qt.QLabel('Select Intensity Range:')
        # threshLabel.alignment = 4

        # self.__threshRange = slicer.qMRMLRangeWidget()
        # self.__threshRange.decimals = 0
        # self.__threshRange.singleStep = 1

        # self.__thresholdGroupBoxLayout.addRow(threshLabel)
        # self.__thresholdGroupBoxLayout.addRow(self.__threshRange)
        # self.__layout.addRow(self.__thresholdGroupBox)

        # self.__threshRange.connect('valuesChanged(double,double)', self.onThresholdChanged)
        qt.QTimer.singleShot(0, self.killButton)

    def onThresholdChanged(self):
        """ Upon changing the slider (or intializing this step), this method
            updates the volume rendering node and label volume accordingly.
        """

        range0 = self.__threshRange.minimumValue
        range1 = self.__threshRange.maximumValue

        # Use vtk to threshold the label volume.
        if self.__roiVolume != None:
            thresh = vtk.vtkImageThreshold()
            if vtk.VTK_MAJOR_VERSION <= 5:
                thresh.SetInput(self.__roiVolume.GetImageData())
            else:
                thresh.SetInputData(self.__roiVolume.GetImageData())
            thresh.ThresholdBetween(range0, range1)
            thresh.SetInValue(1)
            thresh.SetOutValue(0)
            thresh.ReplaceOutOn()
            thresh.ReplaceInOn()
            thresh.Update()

            self.__thresholdedLabelNode.SetAndObserveImageData(
                thresh.GetOutput())

    def killButton(self):
        # ctk creates a useless final page button. This method gets rid of it.
        bl = slicer.util.findChildren(text='ReviewStep')
        if len(bl):
            bl[0].hide()

    def validate(self, desiredBranchId):
        # For now, no validation required.
        self.__parent.validationSucceeded(desiredBranchId)

    def onEntry(self, comingFrom, transitionType):
        """ This method removes and adds nodes necessary to for a segementation
            display, intializes color and opacity maps, and calls the main 
            thresholding function for the first time.
        """

        super(SegmentationStep, self).onEntry(comingFrom, transitionType)

        pNode = self.parameterNode()

        self.EditorWidget.setMergeNode(self.__thresholdedLabelNode)
        self.EditorWidget.volumes.collapsed = True
        self.EditorWidget.editLabelMapsFrame.collapsed = False
        try:
            self.EditorWidget.segmentEditorLabel.hide()
            self.EditorWidget.infoIconLabel.hide()
        except:
            pass

        # pNode = self.parameterNode()

        # # What if someone goes to the Volume Rendering module, creates a new VRNode,
        # # and then returns? Need some way to check if self.__vrNode is currently
        # # being viewed.

        # self.__vrDisplayNode = Helper.getNodeByID(pNode.GetParameter('vrDisplayNodeID'))
        # self.updateWidgetFromParameters(pNode)

        # # Retrieves necessary nodes.
        # self.__roiVolume = Helper.getNodeByID(pNode.GetParameter('croppedVolumeID'))
        # self.__thresholdedLabelNode = Helper.getNodeByID(pNode.GetParameter('thresholdedLabelID'))
        # self.__nonThresholdedLabelNode = Helper.getNodeByID(pNode.GetParameter('nonThresholdedLabelID'))

        # # self.InitVRDisplayNode()

        # # Adds segementation label volume.
        # Helper.SetLabelVolume(self.__thresholdedLabelNode.GetID())

        # threshRange = [self.__threshRange.minimumValue, self.__threshRange.maximumValue]

        # # Segments the entire vtk model. I assume there's a more concise way
        # # to do it than thresholding over its entire intensity range, so TODO
        # range0 = self.__threshRange.minimum
        # range1 = self.__threshRange.maximum
        # thresh = vtk.vtkImageThreshold()
        # if vtk.VTK_MAJOR_VERSION <= 5:
        #   thresh.SetInput(self.__roiVolume.GetImageData())
        # else:
        #   thresh.SetInputData(self.__roiVolume.GetImageData())
        # thresh.ThresholdBetween(range0, range1)
        # thresh.SetInValue(1)
        # thresh.SetOutValue(0)
        # thresh.ReplaceOutOn()
        # thresh.ReplaceInOn()
        # thresh.Update()
        # self.__nonThresholdedLabelNode.SetAndObserveImageData(thresh.GetOutput())

        # # Adjusts threshold information.
        # self.onThresholdChanged()

        pNode.SetParameter('currentStep', self.stepid)

        qt.QTimer.singleShot(0, self.killButton)

    def updateWidgetFromParameters(self, pNode):
        """ Intializes the threshold and label volume established in the previous step.
        """

        pass

        # if pNode.GetParameter('followupVolumeID') == None or pNode.GetParameter('followupVolumeID') == '':
        #     Helper.SetBgFgVolumes(pNode.GetParameter('baselineVolumeID'), '')
        #     self.__visualizedVolume = Helper.getNodeByID(pNode.GetParameter('baselineVolumeID'))
        # else:
        #     Helper.SetBgFgVolumes(pNode.GetParameter('subtractVolumeID'), pNode.GetParameter('followupVolumeID'))
        #     self.__visualizedVolume = Helper.getNodeByID(pNode.GetParameter('subtractVolumeID'))

        # thresholdRange = [float(pNode.GetParameter('intensityThreshRangeMin')), float(pNode.GetParameter('intensityThreshRangeMax'))]

        # if thresholdRange != '':
        #     self.__threshRange.maximum = thresholdRange[1]
        #     self.__threshRange.minimum = thresholdRange[0]
        #     self.__threshRange.maximumValue = thresholdRange[1]
        #     self.__threshRange.minimumValue = thresholdRange[0]
        # else:
        #     Helper.Error('Unexpected parameter values! Error code CT-S03-TNA. Please report')

        # labelID = pNode.GetParameter('thresholdedLabelID')
        # self.__thresholdedLabelNode = Helper.getNodeByID(labelID)

    def onExit(self, goingTo, transitionType):
        pNode = self.parameterNode()

        # if self.__vrDisplayNode != None:
        #   # self.__vrDisplayNode.VisibilityOff()
        #   pNode.SetParameter('vrDisplayNodeID', self.__vrDisplayNode.GetID())

        # roiRange = self.__threshRange
        # pNode.SetParameter('intensityThreshRangeMin', str(roiRange.minimumValue))
        # pNode.SetParameter('intensityThreshRangeMax', str(roiRange.maximumValue))
        # pNode.SetParameter('vrThreshRangeMin', str(roiRange.minimumValue))
        # pNode.SetParameter('vrThreshRangeMax', str(roiRange.maximumValue))

        super(GBMWizardStep, self).onExit(goingTo, transitionType)

    def InitVRDisplayNode(self):
        """ This method calls a series of steps necessary to initailizing a volume 
            rendering node with an ROI.
        """
        if self.__vrDisplayNode == None or self.__vrDisplayNode == '':
            pNode = self.parameterNode()
            self.__vrDisplayNode = self.__vrLogic.CreateVolumeRenderingDisplayNode(
            )
            slicer.mrmlScene.AddNode(self.__vrDisplayNode)
            # Documentation on UnRegister is scant so far.
            self.__vrDisplayNode.UnRegister(self.__vrLogic)

            Helper.InitVRDisplayNode(self.__vrDisplayNode,
                                     self.__roiVolume.GetID(), '')
            self.__roiVolume.AddAndObserveDisplayNodeID(
                self.__vrDisplayNode.GetID())
        else:
            self.__vrDisplayNode.SetAndObserveVolumeNodeID(
                self.__roiVolume.GetID())

        # This is a bit messy.
        viewNode = slicer.util.getNode('vtkMRMLViewNode1')

        self.__vrDisplayNode.AddViewNodeID(viewNode.GetID())

        self.__vrLogic.CopyDisplayToVolumeRenderingDisplayNode(
            self.__vrDisplayNode)

        self.__vrOpacityMap = self.__vrDisplayNode.GetVolumePropertyNode(
        ).GetVolumeProperty().GetScalarOpacity()
        self.__vrColorMap = self.__vrDisplayNode.GetVolumePropertyNode(
        ).GetVolumeProperty().GetRGBTransferFunction()

        vrRange = self.__visualizedVolume.GetImageData().GetScalarRange()

        # Renders in yellow, like the label map in the next steps.
        self.__vrColorMap.RemoveAllPoints()
        self.__vrColorMap.AddRGBPoint(vrRange[0], 0.8, 0.8, 0)
        self.__vrColorMap.AddRGBPoint(vrRange[1], 0.8, 0.8, 0)
class CMRToolkitWizardWallCleanupStep( CMRToolkitWizardStep ) :

  def __init__( self, stepid ):
    self.initialize( stepid )
    self.setName( '5. Edit Wall Segmentation' )
    self.setDescription( 'Set the wall segmentation image from the previous step as the merge volume in the Slicer Editor. Remove the pulmonary veins from the wall segmentation using the Slicer Editor erase tool and select the final label image to proceed.' )

    self.__parent = super( CMRToolkitWizardWallCleanupStep, self )

  def killButton(self):
    # Hide unneccesary button
    bl = slicer.util.findChildren(text='AutomaticLeft*')
    if len(bl):
      bl[0].hide()

  def createUserInterface( self ):
    from Editor import EditorWidget
    
    self.__layout = self.__parent.createUserInterface()
    
    #endoSegmentButton = qt.QPushButton('Open Slicer Editor tool')
    #self.__layout.addRow(endoSegmentButton)
    #endoSegmentButton.connect('clicked()', self.startEditor)
    
    #TODO: Create label map and set it for editing by user?
    #volumesLogic = slicer.modules.volumes.logic()
    #headLabel = volumesLogic.CreateLabelVolume( slicer.mrmlScene, head, head.GetName() + '-segmentation' )
    
    #selectionNode = slicer.app.applicationLogic().GetSelectionNode()
    #selectionNode.SetReferenceActiveVolumeID( head.GetID() )
    #selectionNode.SetReferenceActiveLabelVolumeID( headLabel.GetID() )
    #slicer.app.applicationLogic().PropagateVolumeSelection(0)
    
    self.updateParameters(self.parameterNode())
    
    editorFrame = qt.QFrame()
    editorFrame.setLayout(qt.QVBoxLayout())
    palette = editorFrame.palette
    bgColor = 230
    palette.setColor(qt.QPalette.Background, qt.QColor(bgColor, bgColor, bgColor))
    editorFrame.setPalette(palette)
    editorFrame.setAutoFillBackground(True);
    self.__layout.addRow(editorFrame)
    self.editorFrame = editorFrame
    global editorWidget 
    self.editorWidget = EditorWidget(parent=self.editorFrame, showVolumesFrame=True)
    self.editorWidget.setup()
    self.editorWidget.enter()
    ##TODO: How to set the required merge node?
    
    wallCleanupSegLabel = qt.QLabel( 'Final Wall Segmentation Image:' )
    self.__wallCleanupSegSelector = slicer.qMRMLNodeComboBox()
    self.__wallCleanupSegSelector.toolTip = "Choose the final wall segmentation label image."
    self.__wallCleanupSegSelector.nodeTypes = ['vtkMRMLScalarVolumeNode']
    self.__wallCleanupSegSelector.setMRMLScene(slicer.mrmlScene)
    self.__wallCleanupSegSelector.addEnabled = 0
    self.__layout.addRow( wallCleanupSegLabel, self.__wallCleanupSegSelector )

    # Hide unnecessary button
    findChildren( text = 'AutomaticLeft*')[0].hide()

  def validate( self, desiredBranchId ):
    self.__parent.validate( desiredBranchId )
    wallCleanupSegVolume = self.__wallCleanupSegSelector.currentNode()
    
    if wallCleanupSegVolume != None :
      wallCleanupSegID = wallCleanupSegVolume.GetID()
      pNode = self.parameterNode()
      pNode.SetParameter('wallCleanupSegID', wallCleanupSegID)
      Helper.SetLabelVolume(wallCleanupSegVolume.GetID())
      self.__parent.validationSucceeded(desiredBranchId)
    else:
      self.__parent.validationFailed(desiredBranchId, 'Error','Please select the wall segmentation image to proceed.')
    
  def onEntry(self, comingFrom, transitionType):
    super(CMRToolkitWizardWallCleanupStep, self).onEntry(comingFrom, transitionType)
    pNode = self.parameterNode()
    pNode.SetParameter('currentStep', self.stepid)
    
    qt.QTimer.singleShot(0, self.killButton)

  ## TODO: Why does editor effect continue to the next workflow step?
  def onExit(self, goingTo, transitionType):    
    pNode = self.parameterNode()

    #if goingTo.id() != 'PVAntrumCut':
    #  return

    self.editorWidget.exit()

    super(CMRToolkitWizardWallCleanupStep, self).onExit(goingTo, transitionType) 

  def updateParameters(self, parameterNode):
    global wallSegVolume 
    wallSegVolume = parameterNode.GetParameter('wallSegVolumeID')
class CMRToolkitWizardEndoSegmentationStep( CMRToolkitWizardStep ) :

  def __init__( self, stepid ):
    self.initialize( stepid )
    self.setName( '2. Segmentation of endocardium' )
    self.setDescription( 'Segment the endocardium using the Editor paint tool and select the final label image to proceed.' )

    self.__parent = super( CMRToolkitWizardEndoSegmentationStep, self )

  def killButton(self):
    # Hide unneccesary button
    bl = slicer.util.findChildren(text='AutomaticLeft*')
    if len(bl):
      bl[0].hide()

  def createUserInterface( self ):
    from Editor import EditorWidget
    
    self.__layout = self.__parent.createUserInterface()
       
    #TODO: Create label map and set it for editing by user?
    #volumesLogic = slicer.modules.volumes.logic()
    #headLabel = volumesLogic.CreateLabelVolume( slicer.mrmlScene, head, head.GetName() + '-segmentation' )
    
    #selectionNode = slicer.app.applicationLogic().GetSelectionNode()
    #selectionNode.SetReferenceActiveVolumeID( head.GetID() )
    #selectionNode.SetReferenceActiveLabelVolumeID( headLabel.GetID() )
    #slicer.app.applicationLogic().PropagateVolumeSelection(0)
    
    editorFrame = qt.QFrame()
    editorFrame.setLayout(qt.QVBoxLayout())
    palette = editorFrame.palette
    bgColor = 230
    palette.setColor(qt.QPalette.Background, qt.QColor(bgColor, bgColor, bgColor))
    editorFrame.setPalette(palette)
    editorFrame.setAutoFillBackground(True);
    self.__layout.addRow(editorFrame)
    self.editorFrame = editorFrame
    global editorWidget 
    self.editorWidget = EditorWidget(parent=self.editorFrame, showVolumesFrame=True)
    self.editorWidget.setup()
    self.editorWidget.enter()
    
    endoSegLabel = qt.QLabel( 'Endo Segmentation Image:' )
    self.__endoSegSelector = slicer.qMRMLNodeComboBox()
    self.__endoSegSelector.toolTip = "Choose the endo segmentation label image."
    self.__endoSegSelector.nodeTypes = ['vtkMRMLScalarVolumeNode']
    self.__endoSegSelector.setMRMLScene(slicer.mrmlScene)
    self.__endoSegSelector.addEnabled = 0
    self.__layout.addRow( endoSegLabel, self.__endoSegSelector )
    
  #def startEditor(self):
  #  from Editor import EditorWidget
  #  editorWidget = EditorWidget(showVolumesFrame=True)
    
  def validate( self, desiredBranchId ):
    self.__parent.validate( desiredBranchId )
    endoSegVolume = self.__endoSegSelector.currentNode()
    
    if endoSegVolume != None :
      endoSegID = endoSegVolume.GetID()
      pNode = self.parameterNode()
      pNode.SetParameter('endoSegVolumeID', endoSegID)
      Helper.SetLabelVolume(endoSegVolume.GetID())
      self.__parent.validationSucceeded(desiredBranchId)
    else:
      self.__parent.validationFailed(desiredBranchId, 'Error','Please select an endo segmentation image to proceed.')
    
  def onEntry(self, comingFrom, transitionType):
    super(CMRToolkitWizardEndoSegmentationStep, self).onEntry(comingFrom, transitionType)
    pNode = self.parameterNode()
    pNode.SetParameter('currentStep', self.stepid)

    qt.QTimer.singleShot(0, self.killButton)

  def onExit(self, goingTo, transitionType):    
    pNode = self.parameterNode()
    #if goingTo.id() != 'AxialDilate':
    #  return

    self.editorWidget.exit()
    
    super(CMRToolkitWizardEndoSegmentationStep, self).onExit(goingTo, transitionType) 
class SlicerPathologyWidget(ScriptedLoadableModuleWidget, ModuleWidgetMixin):

  def __init__(self, parent = None):
    ScriptedLoadableModuleWidget.__init__(self, parent)
    self.resourcesPath = os.path.join(slicer.modules.slicerpathology.path.replace(self.moduleName+".py",""), 'Resources')
    self.modulePath = os.path.dirname(slicer.util.modulePath(self.moduleName))
    self.currentStep = 1
  
  def setup(self):
    ScriptedLoadableModuleWidget.setup(self)
    # this section is for custom color box
    infoGroupBox = qt.QWidget()
    hbox = qt.QHBoxLayout()
    hbox.setMargin(0)
    self.studySelectionGroupBoxLayout = qt.QGridLayout()
    infoGroupBox.setLayout(hbox)
    self.studySelectionGroupBoxLayout.addWidget(infoGroupBox, 0, 3, 1, 1)
    infoIcon = qt.QPixmap(os.path.join(self.resourcesPath, 'Icons', 'icon-infoBox.png'))
    self.customLUTInfoIcon = qt.QLabel()
    self.customLUTInfoIcon.setPixmap(infoIcon)
    self.customLUTInfoIcon.setSizePolicy(PythonQt.QtGui.QSizePolicy())
    hbox.addWidget(self.customLUTInfoIcon)
    self.customLUTLabel = qt.QLabel()
    hbox.addWidget(self.customLUTLabel)
    # end of custom color box section  
    self.setupIcons()
    self.setupTabBarNavigation()
    self.setupsetupUI()
    self.setupimageSelectionUI()
    self.setupsegmentationUI()
    self.setupsubmissionUI()
    self.setupEditorWidget()
    editUtil = EditorLib.EditUtil.EditUtil()
    self.parameterNode = editUtil.getParameterNode()
    
    # 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)

    #
    # check box to trigger taking screen shots for later use in tutorials
    #
    self.enableScreenshotsFlagCheckBox = qt.QCheckBox()
    self.enableScreenshotsFlagCheckBox.checked = 0
    self.enableScreenshotsFlagCheckBox.setToolTip("If checked, take screen shots for tutorials. Use Save Data to write them to disk.")
    parametersFormLayout.addRow("Enable Screenshots", self.enableScreenshotsFlagCheckBox)

    #
    # scale factor for screen shots
    #
    self.screenshotScaleFactorSliderWidget = ctk.ctkSliderWidget()
    self.screenshotScaleFactorSliderWidget.singleStep = 1.0
    self.screenshotScaleFactorSliderWidget.minimum = 1.0
    self.screenshotScaleFactorSliderWidget.maximum = 50.0
    self.screenshotScaleFactorSliderWidget.value = 1.0
    self.screenshotScaleFactorSliderWidget.setToolTip("Set scale factor for the screen shots.")
    parametersFormLayout.addRow("Screenshot scale factor", self.screenshotScaleFactorSliderWidget)

    #
    # Apply Button
    #
    #self.applyButton = qt.QPushButton("Apply")
    #self.applyButton.toolTip = "Run the algorithm."
    #self.applyButton.enabled = False
    #parametersFormLayout.addRow(self.applyButton)

    # Add vertical spacer
    self.layout.addStretch(1)
    self.j = {}

  def cleanup(self):
    pass

  def onSelect(self):
    self.applyButton.enabled = self.inputSelector.currentNode() and self.outputSelector.currentNode()

  def onApplyButton(self):
    logic = SlicerPathologyLogic()
    enableScreenshotsFlag = self.enableScreenshotsFlagCheckBox.checked
    screenshotScaleFactor = int(self.screenshotScaleFactorSliderWidget.value)
    print("Run the algorithm")
    logic.run(self.inputSelector.currentNode(), self.outputSelector.currentNode(), enableScreenshotsFlag,screenshotScaleFactor)
    
  def setupIcons(self):
    self.setupIcon = self.createIcon('icon-setup.png')
    self.imageSelectionIcon = self.createIcon('icon-imageselection.png')
    self.segmentationIcon = self.createIcon('icon-segmentation.png')
    self.submissionIcon = self.createIcon('icon-submission.png')

  def setupTabBarNavigation(self):
    self.tabWidget = qt.QTabWidget()
    self.layout.addWidget(self.tabWidget)

    setupGroupBox = qt.QGroupBox()
    imageSelectionGroupBox = qt.QGroupBox()
    segmentationGroupBox = qt.QGroupBox()
    submissionGroupBox = qt.QGroupBox()

    self.setupGroupBoxLayout = qt.QFormLayout()
    self.imageSelectionGroupBoxLayout = qt.QFormLayout()
    self.segmentationGroupBoxLayout = qt.QGridLayout()
    self.submissionGroupBoxLayout = qt.QFormLayout()

    setupGroupBox.setLayout(self.setupGroupBoxLayout)
    imageSelectionGroupBox.setLayout(self.imageSelectionGroupBoxLayout)
    segmentationGroupBox.setLayout(self.segmentationGroupBoxLayout)
    submissionGroupBox.setLayout(self.submissionGroupBoxLayout)

    self.tabWidget.setIconSize(qt.QSize(85, 30))

    self.tabWidget.addTab(setupGroupBox, self.setupIcon, '')
    self.tabWidget.addTab(imageSelectionGroupBox, self.imageSelectionIcon, '')
    self.tabWidget.addTab(segmentationGroupBox, self.segmentationIcon, '')
    self.tabWidget.addTab(submissionGroupBox, self.submissionIcon, '')
    self.tabWidget.connect('currentChanged(int)',self.onTabWidgetClicked)

    self.setTabsEnabled([1,2,3,4], True)

  def onTabWidgetClicked(self, currentIndex):
    if currentIndex == 0:
      self.onStep1Selected()
    if currentIndex == 1:
      print ""
    if currentIndex == 2:
      print ""
    if currentIndex == 3:
      print ""

  def setTabsEnabled(self, indexes, enabled):
    for index in indexes:
      self.tabWidget.childAt(1, 1).setTabEnabled(index, enabled)
     
  def onStep1Selected(self):
#if self.checkStep3or4Leave() is True:
#return
    if self.currentStep == 1:
      return
    self.currentStep = 1
    self.setTabsEnabled([0],True)
    self.setTabsEnabled([1,2,3], False)
    
  def setupsetupUI(self):
    self.setupUserName = qt.QLineEdit()
    self.setupGroupBoxLayout.addRow("Username:"******"Password:"******"Data directory:") )
    self.setupGroupBoxLayout.addWidget(self.dataDirButton)
    self.setupExecutionID = qt.QLineEdit()
    self.setupGroupBoxLayout.addRow("Execution ID:", self.setupExecutionID)
    
  def setupimageSelectionUI(self):
    self.loadDataButton = qt.QPushButton("Load Image from disk")
    self.imageSelectionGroupBoxLayout.addWidget(self.loadDataButton)
    self.loadDataButton.connect('clicked()', self.loadTCGAData)
    self.WIP2 = qt.QPushButton("Select image from web")
    self.WIP2.connect('clicked()', self.onWIP2ButtonClicked)
    self.imageSelectionGroupBoxLayout.addWidget(self.WIP2)
    self.WIP3 = qt.QPushButton("Load image from web")
    self.WIP3.connect('clicked()', self.onWIP3ButtonClicked)
    self.imageSelectionGroupBoxLayout.addWidget(self.WIP3)
    self.RestoreButton = qt.QPushButton("Restore Session")
    self.RestoreButton.connect('clicked()', self.RestoreSession)
    self.imageSelectionGroupBoxLayout.addWidget(self.RestoreButton)

#  def ebCenter(self):
#    r = slicer.app.layoutManager().sliceWidget("Red").sliceController()
#    r.fitSliceToBackground()

  def onWIP2ButtonClicked(self):
    self.openTargetImage0()

  def onWIP3ButtonClicked(self):
    self.openTargetImage()
    r = slicer.app.layoutManager().sliceWidget("Red").sliceController()
    r.fitSliceToBackground()

  def setupsegmentationUI(self):
    print ""
    
  def setupsubmissionUI(self):
    self.SaveButton = qt.QPushButton("Save")
    self.submissionGroupBoxLayout.addWidget(self.SaveButton)
    self.SaveButton.connect('clicked()', self.onSaveButtonClicked)
    self.SaveButton.setEnabled(0)
    #self.WebSaveButton = qt.QPushButton("Submit to web")
    #self.submissionGroupBoxLayout.addWidget(self.WebSaveButton)
    #self.WebSaveButton.connect('clicked()', self.onWebSaveButtonClicked)

  def QImage2vtkImage(self, image):
    i = vtk.vtkImageData().NewInstance()
    i.SetDimensions(image.width(),image.height(),1)
    i.AllocateScalars(vtk.VTK_UNSIGNED_CHAR,3)
    for x in range(0,image.width()):
      for y in range(0,image.height()):
          c = qt.QColor(image.pixel(x,y))
          i.SetScalarComponentFromDouble(x,y,0,0,c.red())
          i.SetScalarComponentFromDouble(x,y,0,1,c.green())
          i.SetScalarComponentFromDouble(x,y,0,2,c.blue())
    return i

  def onWIPButtonClicked(self):
    import urllib2
    reply = urllib2.urlopen('http://www.osa.sunysb.edu/erich.png')
    byte_array = reply.read()
    image = qt.QImage(qt.QImage.Format_RGB888)
    image.loadFromData(byte_array) 
    imageData = self.QImage2vtkImage(image)
    volumeNode = slicer.vtkMRMLVectorVolumeNode()
    volumeNode.SetName("WEB")
    volumeNode.SetAndObserveImageData(imageData)
    displayNode = slicer.vtkMRMLVectorVolumeDisplayNode()
    slicer.mrmlScene.AddNode(volumeNode)
    slicer.mrmlScene.AddNode(displayNode)
    volumeNode.SetAndObserveDisplayNodeID(displayNode.GetID())
    displayNode.SetAndObserveColorNodeID('vtkMRMLColorTableNodeGrey')
    self.mutate() 

  def RestoreSession(self):
    import zipfile
    import os.path
    f = qt.QFileDialog.getOpenFileName()
    zf = zipfile.ZipFile(f)
    for filename in zf.namelist():
      try:
        data = zf.read(filename)
      except KeyError:
        print 'ERROR: Did not find %s in zip file' % filename
      else:
        print filename

  def onSaveButtonClicked(self):
    import zipfile
    import os.path
    import uuid
    bundle = EditUtil.EditUtil().getParameterNode().GetParameter('QuickTCGAEffect,erich')
    tran = json.loads(bundle)
    layers = []
    for key in tran:
      nn = tran[key]
      nn["file"] = key + '.tif'
      layers.append(tran[key])
    self.j['layers'] = layers
    self.j['username'] = self.setupUserName.text
    self.j['sourcetile'] = self.tilename
    self.j['generator'] = slicer.app.applicationVersion
    self.j['timestamp'] = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
    self.j['execution_id'] = self.setupExecutionID.text + "-"+ uuid.uuid4().get_urn()
    labelNodes = slicer.util.getNodes('vtkMRMLLabelMapVolumeNode*')
    savedMessage = 'Segmentations for the following series were saved:\n\n'
    zfname = os.path.join(self.dataDirButton.directory, self.tilename + "_" + datetime.datetime.now().strftime("%Y%m%d%H%M%S") + '.zip')
    print "zipfile name"
    print zfname
    zf = zipfile.ZipFile(zfname, mode='w')
    red_logic = slicer.app.layoutManager().sliceWidget("Red").sliceLogic()
    red_cn = red_logic.GetSliceCompositeNode()
    fg = red_cn.GetForegroundVolumeID()
    ff = slicer.util.getNode(fg)
    sNode = slicer.vtkMRMLVolumeArchetypeStorageNode()
    sNode.SetFileName("original.tif")
    sNode.SetWriteFileFormat('tif')
    sNode.SetURI(None)
    success = sNode.WriteData(ff)
    zf.write("original.tif")
    os.remove("original.tif")
    for label in labelNodes.values():
      labelName = label.GetName()
      labelFileName = os.path.join(self.dataDirButton.directory, labelName + '.tif')
      compFileName = os.path.join(self.dataDirButton.directory, labelName + '-comp.tif')
      sNode.SetFileName(labelFileName)
      success = sNode.WriteData(label)
      if success:
        print "adding "+labelFileName+" to zipfile"
        zf.write(labelFileName,os.path.basename(labelFileName))
        os.remove(labelFileName)
      else:
        print "failed writing "+labelFileName
      comp = self.WriteLonI(label.GetImageData(),ff.GetImageData())
      volumeNode = slicer.vtkMRMLVectorVolumeNode()
      volumeNode.SetName("COMP")
      volumeNode.SetAndObserveImageData(comp)
      sNode.SetFileName(compFileName)
      success = sNode.WriteData(volumeNode)
      if success:
        print "adding "+compFileName+" to zipfile"
        zf.write(compFileName,os.path.basename(compFileName))
        os.remove(compFileName)
      else:
        print "failed writing "+compFileName
    jstr = json.dumps(self.j,sort_keys=True, indent=4, separators=(',', ': '))
    mfname = os.path.join(self.dataDirButton.directory, 'manifest.json')
    f = open(mfname,'w')
    f.write(jstr)
    f.close()
    zf.write(mfname,os.path.basename(mfname))
    zf.close()
    os.remove(mfname)
    #import sys
    #reload(sys)
    #sys.setdefaultencoding('utf8')
    #opener = urllib2.build_opener(MultipartPostHandler)
    #params = { "ss" : "0",            # show source
    #           "doctype" : "Inline",
    #           "uploaded_file" : open(zfname, "rb") }
    #print params
    #print opener.open('http://quip1.bmi.stonybrook.edu:4000/upload', params).read()

  def WriteLonI(self, src, dest):
    dim = src.GetDimensions()
    i = vtk.vtkImageData().NewInstance()
    i.SetDimensions(dim[0],dim[1],1)
    i.AllocateScalars(vtk.VTK_UNSIGNED_CHAR,3)
    for x in range(0,dim[0]):
      for y in range(0,dim[1]):
        if (src.GetScalarComponentAsDouble(x,y,0,0)==0):
          for c in range(0,3):
            i.SetScalarComponentFromDouble(x,y,0,c,dest.GetScalarComponentAsDouble(x,y,0,c))
        else:
          if (
             (src.GetScalarComponentAsDouble(x+1,y-1,0,0)==1) and
             (src.GetScalarComponentAsDouble(x+1,y,0,0)==1) and
             (src.GetScalarComponentAsDouble(x+1,y+1,0,0)==1) and
             (src.GetScalarComponentAsDouble(x,y+1,0,0)==1) and
             (src.GetScalarComponentAsDouble(x,y-1,0,0)==1) and
             (src.GetScalarComponentAsDouble(x-1,y+1,0,0)==1) and
             (src.GetScalarComponentAsDouble(x-1,y,0,0)==1) and
             (src.GetScalarComponentAsDouble(x-1,y-1,0,0)==1)):
            for c in range(0,3):
              i.SetScalarComponentFromDouble(x,y,0,c,dest.GetScalarComponentAsDouble(x,y,0,c))
          else:
            i.SetScalarComponentFromDouble(x,y,0,0,0)
            i.SetScalarComponentFromDouble(x,y,0,1,250)
            i.SetScalarComponentFromDouble(x,y,0,2,0)
    i.Modified()
    return i

  def onWebSaveButtonClicked(self):
    print "Web Save to be implemented...."

  def checkAndSetLUT(self):
    # Default to module color table
    self.resourcesPath = os.path.join(slicer.modules.slicerpathology.path.replace(self.moduleName+".py",""), 'Resources')
    self.colorFile = os.path.join(self.resourcesPath, "Colors/SlicerPathology.csv")
    self.customLUTLabel.setText('Using Default LUT')
    try:
        self.editorWidget.helper.structureListWidget.merge = None
    except AttributeError:
        pass
    # setup the color table, make sure SlicerPathology LUT is a singleton
    allColorTableNodes = slicer.util.getNodes('vtkMRMLColorTableNode*').values()
    for ctn in allColorTableNodes:
        #print "color: "+ctn.GetName()
        if ctn.GetName() == 'SlicerPathologyColor':
            slicer.mrmlScene.RemoveNode(ctn)
            break
    self.SlicerPathologyColorNode = slicer.vtkMRMLColorTableNode()
    colorNode = self.SlicerPathologyColorNode
    colorNode.SetName('SlicerPathologyColor')
    slicer.mrmlScene.AddNode(colorNode)
    colorNode.SetTypeToUser()
    with open(self.colorFile) as f:
        n = sum(1 for line in f)
    colorNode.SetNumberOfColors(n-1)
    colorNode.NamesInitialisedOn()
    import csv
    self.structureNames = []
    with open(self.colorFile, 'rb') as csvfile:
        reader = csv.DictReader(csvfile, delimiter=',')
        for index,row in enumerate(reader):
            success = colorNode.SetColor(index ,row['Label'],float(row['R'])/255,float(row['G'])/255,float(row['B'])/255,float(row['A']))
            if not success:
                print "color %s could not be set" % row['Label']
            self.structureNames.append(row['Label'])

  def setupEditorWidget(self):
    editorWidgetParent = slicer.qMRMLWidget()
    editorWidgetParent.setLayout(qt.QVBoxLayout())
    editorWidgetParent.setMRMLScene(slicer.mrmlScene)
    self.editorWidget = EditorWidget(parent=editorWidgetParent)
    self.editorWidget.setup()
    self.segmentationGroupBoxLayout.addWidget(self.editorWidget.parent)

  def mutate(self):
    red_logic = slicer.app.layoutManager().sliceWidget("Red").sliceLogic()
    red_cn = red_logic.GetSliceCompositeNode()
    fgrdVolID = red_cn.GetBackgroundVolumeID()
    fgrdNode = slicer.util.getNode("WEB")
    fgrdVolID = fgrdNode.GetID()
    fMat=vtk.vtkMatrix4x4()
    fgrdNode.GetIJKToRASDirectionMatrix(fMat)
    bgrdName = fgrdNode.GetName() + '_gray'
    magnitude = vtk.vtkImageMagnitude()
    magnitude.SetInputData(fgrdNode.GetImageData())
    magnitude.Update()  
    bgrdNode = slicer.vtkMRMLScalarVolumeNode()
    bgrdNode.SetImageDataConnection(magnitude.GetOutputPort())
    bgrdNode.SetName(bgrdName)
    bgrdNode.SetIJKToRASDirectionMatrix(fMat)
    slicer.mrmlScene.AddNode(bgrdNode)
    bgrdVolID = bgrdNode.GetID()  
    red_cn.SetForegroundVolumeID(fgrdVolID)
    red_cn.SetBackgroundVolumeID(bgrdVolID)
    red_cn.SetForegroundOpacity(1)   

    resourcesPath = os.path.join(slicer.modules.slicerpathology.path.replace("SlicerPathology.py",""), 'Resources')
    colorFile = os.path.join(resourcesPath, "Colors/SlicerPathology.csv")
    try:
        slicer.modules.EditorWidget.helper.structureListWidget.merge = None
    except AttributeError:
        pass

    allColorTableNodes = slicer.util.getNodes('vtkMRMLColorTableNode*').values()
    for ctn in allColorTableNodes:
        if ctn.GetName() == 'SlicerPathologyColor':
           slicer.mrmlScene.RemoveNode(ctn)
           break

    SlicerPathologyColorNode = slicer.vtkMRMLColorTableNode()
    colorNode = SlicerPathologyColorNode
    colorNode.SetName('SlicerPathologyColor')
    slicer.mrmlScene.AddNode(colorNode)
    colorNode.SetTypeToUser()
    with open(colorFile) as f:
        n = sum(1 for line in f)

    colorNode.SetNumberOfColors(n-1)
    colorNode.NamesInitialisedOn()
    import csv
    structureNames = []
    with open(colorFile, 'rb') as csvfile:
        reader = csv.DictReader(csvfile, delimiter=',')
        for index,row in enumerate(reader):
            success = colorNode.SetColor(index ,row['Label'],float(row['R'])/255,float(row['G'])/255,float(row['B'])/255,float(row['A']))
            if not success:
                print "color %s could not be set" % row['Label']
            structureNames.append(row['Label'])
    volumesLogic = slicer.modules.volumes.logic()
    labelName = bgrdName+'-label'
    refLabel = volumesLogic.CreateAndAddLabelVolume(slicer.mrmlScene,bgrdNode,labelName)
    refLabel.GetDisplayNode().SetAndObserveColorNodeID(SlicerPathologyColorNode.GetID())
    self.editorWidget.helper.setMasterVolume(bgrdNode)

  def openTargetImage0(self):
    self.v = qt.QWebView()
    weburl='http://quip1.bmi.stonybrook.edu:4000/'
    self.v.setUrl(qt.QUrl(weburl))
    self.v.show()

  def openTargetImage(self):
    import string
    p = self.v.page() 
    m = p.mainFrame()
    imageBound=m.evaluateJavaScript('viewer.viewport.viewportToImageRectangle(viewer.viewport.getBounds().x, viewer.viewport.getBounds().y, viewer.viewport.getBounds().width, viewer.viewport.getBounds().height)')
    x=imageBound[u'x']
    y=imageBound[u'y']
    width=imageBound[u'width']
    height=imageBound[u'height']
    self.j['x'] = x
    self.j['y'] = y
    self.j['width'] = width
    self.j['height'] = height
    imagedata = m.evaluateJavaScript('imagedata')
    tmpfilename=  imagedata[u'metaData'][1]
    imageFileName=string.rstrip(tmpfilename,'.dzi')
    self.tilename = imagedata[u'imageId']
    print self.tilename
    self.parameterNode.SetParameter("SlicerPathology,tilename", self.tilename)
    current_weburl ='http://quip1.uhmc.sunysb.edu/fcgi-bin/iipsrv.fcgi?IIIF=' + imageFileName +'/' + str(x) + ','+ str(y) + ',' + str(width) + ',' + str(height) + '/full/0/default.jpg'
    print current_weburl
    self.v.setUrl(qt.QUrl(current_weburl))
    self.v.show()

    reply = urllib2.urlopen(current_weburl)
    byte_array = reply.read()
    image = qt.QImage(qt.QImage.Format_RGB888)
    image.loadFromData(byte_array)
    imageData = self.QImage2vtkImage(image)
    volumeNode = slicer.vtkMRMLVectorVolumeNode()
    volumeNode.SetName("WEB")
    volumeNode.SetAndObserveImageData(imageData)
    displayNode = slicer.vtkMRMLVectorVolumeDisplayNode()
    slicer.mrmlScene.AddNode(volumeNode)
    slicer.mrmlScene.AddNode(displayNode)
    volumeNode.SetAndObserveDisplayNodeID(displayNode.GetID())
    displayNode.SetAndObserveColorNodeID('vtkMRMLColorTableNodeGrey')
    self.mutate()

  def Four2ThreeChannel(self, image):
    dim = image.GetDimensions()
    i = vtk.vtkImageData().NewInstance()
    i.SetDimensions(dim[0],dim[1],1)
    i.AllocateScalars(vtk.VTK_UNSIGNED_CHAR,3)
    for x in range(0,dim[0]):
      for y in range(0,dim[1]):
        for c in range(0,3):
          i.SetScalarComponentFromDouble(x,y,0,c,image.GetScalarComponentAsDouble(x,y,0,c))
    i.Modified()
    return i

  def loadTCGAData(self):
    slicer.util.openAddVolumeDialog()

    import EditorLib
    editUtil = EditorLib.EditUtil.EditUtil()
    imsainode = editUtil.getBackgroundVolume()
    imsai = imsainode.GetImageData()
    print imsai.GetNumberOfScalarComponents()
    if imsai.GetNumberOfScalarComponents() > 3:
      lala = self.Four2ThreeChannel(imsai)
      print lala.GetNumberOfScalarComponents()
      imsainode.SetAndObserveImageData(lala)
      imsainode.Modified()

    red_logic = slicer.app.layoutManager().sliceWidget("Red").sliceLogic()
    red_cn = red_logic.GetSliceCompositeNode()
    fgrdVolID = red_cn.GetBackgroundVolumeID()
    fgrdNode = slicer.util.getNode(fgrdVolID)
    fMat=vtk.vtkMatrix4x4()
    fgrdNode.GetIJKToRASDirectionMatrix(fMat)
    bgrdName = fgrdNode.GetName() + '_gray'
    self.tilename = fgrdNode.GetName() + '_gray'
    self.parameterNode.SetParameter("SlicerPathology,tilename", self.tilename)
    # Create dummy grayscale image
    magnitude = vtk.vtkImageMagnitude()
    magnitude.SetInputData(fgrdNode.GetImageData())
    magnitude.Update()  
    bgrdNode = slicer.vtkMRMLScalarVolumeNode()
    bgrdNode.SetImageDataConnection(magnitude.GetOutputPort())
    bgrdNode.SetName(bgrdName)
    bgrdNode.SetIJKToRASDirectionMatrix(fMat)
    slicer.mrmlScene.AddNode(bgrdNode)
    bgrdVolID = bgrdNode.GetID()  
    red_cn.SetForegroundVolumeID(fgrdVolID)
    red_cn.SetBackgroundVolumeID(bgrdVolID)
    red_cn.SetForegroundOpacity(1)   
    self.checkAndSetLUT() 
    print bgrdName
    cv = slicer.util.getNode(bgrdName)
    self.volumesLogic = slicer.modules.volumes.logic()
    labelName = bgrdName+'-label'
    refLabel = self.volumesLogic.CreateAndAddLabelVolume(slicer.mrmlScene,cv,labelName)
    refLabel.GetDisplayNode().SetAndObserveColorNodeID(self.SlicerPathologyColorNode.GetID())
    self.editorWidget.helper.setMasterVolume(cv)
class SlicerPathologyWidget(ScriptedLoadableModuleWidget, ModuleWidgetMixin):

  def __init__(self, parent = None):
    ScriptedLoadableModuleWidget.__init__(self, parent)
    self.resourcesPath = os.path.join(slicer.modules.slicerpathology.path.replace(self.moduleName+".py",""), 'Resources')
    self.modulePath = os.path.dirname(slicer.util.modulePath(self.moduleName))
    self.currentStep = 1
  
  def setup(self):
    ScriptedLoadableModuleWidget.setup(self)
    # this section is for custom color box
    infoGroupBox = qt.QWidget()
    hbox = qt.QHBoxLayout()
    hbox.setMargin(0)
    self.studySelectionGroupBoxLayout = qt.QGridLayout()
    infoGroupBox.setLayout(hbox)
    self.studySelectionGroupBoxLayout.addWidget(infoGroupBox, 0, 3, 1, 1)
    infoIcon = qt.QPixmap(os.path.join(self.resourcesPath, 'Icons', 'icon-infoBox.png'))
    self.customLUTInfoIcon = qt.QLabel()
    self.customLUTInfoIcon.setPixmap(infoIcon)
    self.customLUTInfoIcon.setSizePolicy(PythonQt.QtGui.QSizePolicy())
    hbox.addWidget(self.customLUTInfoIcon)
    self.customLUTLabel = qt.QLabel()
    hbox.addWidget(self.customLUTLabel)
    # end of custom color box section  
    self.setupIcons()
    self.setupTabBarNavigation()
    self.setupsetupUI()
    self.setupimageSelectionUI()
    self.setupsegmentationUI()
    self.setupsubmissionUI()
    self.setupEditorWidget()
    editUtil = EditorLib.EditUtil.EditUtil()
    self.parameterNode = editUtil.getParameterNode()
    
    # 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)

    #
    # check box to trigger taking screen shots for later use in tutorials
    #
    self.enableScreenshotsFlagCheckBox = qt.QCheckBox()
    self.enableScreenshotsFlagCheckBox.checked = 0
    self.enableScreenshotsFlagCheckBox.setToolTip("If checked, take screen shots for tutorials. Use Save Data to write them to disk.")
    parametersFormLayout.addRow("Enable Screenshots", self.enableScreenshotsFlagCheckBox)

    #
    # scale factor for screen shots
    #
    self.screenshotScaleFactorSliderWidget = ctk.ctkSliderWidget()
    self.screenshotScaleFactorSliderWidget.singleStep = 1.0
    self.screenshotScaleFactorSliderWidget.minimum = 1.0
    self.screenshotScaleFactorSliderWidget.maximum = 50.0
    self.screenshotScaleFactorSliderWidget.value = 1.0
    self.screenshotScaleFactorSliderWidget.setToolTip("Set scale factor for the screen shots.")
    parametersFormLayout.addRow("Screenshot scale factor", self.screenshotScaleFactorSliderWidget)

    #
    # Apply Button
    #
    #self.applyButton = qt.QPushButton("Apply")
    #self.applyButton.toolTip = "Run the algorithm."
    #self.applyButton.enabled = False
    #parametersFormLayout.addRow(self.applyButton)

    # Add vertical spacer
    self.layout.addStretch(1)

  def cleanup(self):
    pass

  def onSelect(self):
    self.applyButton.enabled = self.inputSelector.currentNode() and self.outputSelector.currentNode()

  def onApplyButton(self):
    logic = SlicerPathologyLogic()
    enableScreenshotsFlag = self.enableScreenshotsFlagCheckBox.checked
    screenshotScaleFactor = int(self.screenshotScaleFactorSliderWidget.value)
    print("Run the algorithm")
    logic.run(self.inputSelector.currentNode(), self.outputSelector.currentNode(), enableScreenshotsFlag,screenshotScaleFactor)
    
  def setupIcons(self):
    self.setupIcon = self.createIcon('icon-setup.png')
    self.imageSelectionIcon = self.createIcon('icon-imageselection.png')
    self.segmentationIcon = self.createIcon('icon-segmentation.png')
    self.submissionIcon = self.createIcon('icon-submission.png')

  def setupTabBarNavigation(self):
    self.tabWidget = qt.QTabWidget()
    self.layout.addWidget(self.tabWidget)

    setupGroupBox = qt.QGroupBox()
    imageSelectionGroupBox = qt.QGroupBox()
    segmentationGroupBox = qt.QGroupBox()
    submissionGroupBox = qt.QGroupBox()

    self.setupGroupBoxLayout = qt.QFormLayout()
    self.imageSelectionGroupBoxLayout = qt.QFormLayout()
    self.segmentationGroupBoxLayout = qt.QGridLayout()
    self.submissionGroupBoxLayout = qt.QFormLayout()

    setupGroupBox.setLayout(self.setupGroupBoxLayout)
    imageSelectionGroupBox.setLayout(self.imageSelectionGroupBoxLayout)
    segmentationGroupBox.setLayout(self.segmentationGroupBoxLayout)
    submissionGroupBox.setLayout(self.submissionGroupBoxLayout)

    self.tabWidget.setIconSize(qt.QSize(85, 30))

    self.tabWidget.addTab(setupGroupBox, self.setupIcon, '')
    self.tabWidget.addTab(imageSelectionGroupBox, self.imageSelectionIcon, '')
    self.tabWidget.addTab(segmentationGroupBox, self.segmentationIcon, '')
    self.tabWidget.addTab(submissionGroupBox, self.submissionIcon, '')
    self.tabWidget.connect('currentChanged(int)',self.onTabWidgetClicked)

    self.setTabsEnabled([1,2,3,4], True)

  def onTabWidgetClicked(self, currentIndex):
    if currentIndex == 0:
      self.onStep1Selected()
    if currentIndex == 1:
      print "to be implemented..."
    if currentIndex == 2:
      print "to be implemented..."
    if currentIndex == 3:
      print "to be implemented..."

  def setTabsEnabled(self, indexes, enabled):
    for index in indexes:
      self.tabWidget.childAt(1, 1).setTabEnabled(index, enabled)
     
  def onStep1Selected(self):
#if self.checkStep3or4Leave() is True:
#return
    if self.currentStep == 1:
      return
    self.currentStep = 1
    self.setTabsEnabled([0],True)
    self.setTabsEnabled([1,2,3], False)
    
  def setupsetupUI(self):
    self.setupUserName = qt.QLineEdit()
    self.setupGroupBoxLayout.addRow("Username:"******"Password:"******"Load Data")
    self.imageSelectionGroupBoxLayout.addWidget(self.loadDataButton)
    self.loadDataButton.connect('clicked()', self.loadTCGAData)
    print "Adding WIP Button!"
    self.WIP = qt.QPushButton("WIP")
    self.WIP.connect('clicked()', self.onWIPButtonClicked)
    self.imageSelectionGroupBoxLayout.addWidget(self.WIP)


  def setupsegmentationUI(self):
    print "adding this for now..."
    
  def setupsubmissionUI(self):
    self.dataDirButton = ctk.ctkDirectoryButton()
    self.submissionGroupBoxLayout.addWidget(qt.QLabel("Data directory:") )
    self.submissionGroupBoxLayout.addWidget(self.dataDirButton)
    self.SaveButton = qt.QPushButton("Save")
    self.submissionGroupBoxLayout.addWidget(self.SaveButton)
    self.SaveButton.connect('clicked()', self.onSaveButtonClicked)
    self.WebSaveButton = qt.QPushButton("Submit to web")
    self.submissionGroupBoxLayout.addWidget(self.WebSaveButton)
    self.WebSaveButton.connect('clicked()', self.onWebSaveButtonClicked)

  def onWIPButtonClicked(self):
    print "WIP ME!"
    from EditorLib import EditUtil
    self.editUtil = EditorLib.EditUtil.EditUtil()
    self.labelNode = self.editUtil.getLabelVolume()
    print self.labelNode.GetImageData()
    self.labelNode.GetImageData().Modified() 
    self.labelNode.Modified() 
    self.currentMessage = "WIP Code is done being executed..." 
    slicer.util.showStatusMessage(self.currentMessage) 
    
  def onSaveButtonClicked(self):
    bundle = EditUtil.EditUtil().getParameterNode().GetParameter('QuickTCGAEffect,erich')
    tran = json.loads(bundle)
    layers = []
    for key in tran:
      nn = tran[key]
      nn["file"] = key + '.tif'
      layers.append(tran[key])
    j = {}
    j['layers'] = layers
    j['username'] = self.setupUserName.text
    j['sourcetile'] = self.tilename
    j['generator'] = "3DSlicer-4.5.0 with SlicerPathology v1.0a"
    j['timestamp'] = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
    labelNodes = slicer.util.getNodes('vtkMRMLLabelMapVolumeNode*')
    savedMessage = 'Segmentations for the following series were saved:\n\n'
    for label in labelNodes.values():
      labelName = label.GetName()
      labelFileName = os.path.join(self.dataDirButton.directory, labelName + '.tif')
      print "labelFileName : "+labelFileName
      sNode = slicer.vtkMRMLVolumeArchetypeStorageNode()
      sNode.SetFileName(labelFileName)
      sNode.SetWriteFileFormat('tif')
      sNode.SetURI(None)
      success = sNode.WriteData(label)
      if success:
        print "successful writing "+labelFileName
      else:
        print "failed writing "+labelFileName
    jstr = json.dumps(j,sort_keys=True, indent=4, separators=(',', ': '))
    f = open(os.path.join(self.dataDirButton.directory, self.tilename + '.json'),'w')
    f.write(jstr)
    f.close()

  def onWebSaveButtonClicked(self):
    print "Web Save to be implemented...."

  def checkAndSetLUT(self):
    # Default to module color table
    self.resourcesPath = os.path.join(slicer.modules.slicerpathology.path.replace(self.moduleName+".py",""), 'Resources')
    self.colorFile = os.path.join(self.resourcesPath, "Colors/SlicerPathology.csv")
    self.customLUTLabel.setText('Using Default LUT')
    try:
        self.editorWidget.helper.structureListWidget.merge = None
    except AttributeError:
        pass
    # setup the color table, make sure SlicerPathology LUT is a singleton
    allColorTableNodes = slicer.util.getNodes('vtkMRMLColorTableNode*').values()
    for ctn in allColorTableNodes:
        #print "color: "+ctn.GetName()
        if ctn.GetName() == 'SlicerPathologyColor':
            slicer.mrmlScene.RemoveNode(ctn)
            break
    self.SlicerPathologyColorNode = slicer.vtkMRMLColorTableNode()
    colorNode = self.SlicerPathologyColorNode
    colorNode.SetName('SlicerPathologyColor')
    slicer.mrmlScene.AddNode(colorNode)
    colorNode.SetTypeToUser()
    with open(self.colorFile) as f:
        n = sum(1 for line in f)
    colorNode.SetNumberOfColors(n-1)
    colorNode.NamesInitialisedOn()
    import csv
    self.structureNames = []
    with open(self.colorFile, 'rb') as csvfile:
        reader = csv.DictReader(csvfile, delimiter=',')
        for index,row in enumerate(reader):
            success = colorNode.SetColor(index ,row['Label'],float(row['R'])/255,float(row['G'])/255,float(row['B'])/255,float(row['A']))
            if not success:
                print "color %s could not be set" % row['Label']
            self.structureNames.append(row['Label'])

  def setupEditorWidget(self):
    editorWidgetParent = slicer.qMRMLWidget()
    editorWidgetParent.setLayout(qt.QVBoxLayout())
    editorWidgetParent.setMRMLScene(slicer.mrmlScene)
    self.editorWidget = EditorWidget(parent=editorWidgetParent)
    self.editorWidget.setup()
    self.segmentationGroupBoxLayout.addWidget(self.editorWidget.parent)

  def loadTCGAData(self):
    slicer.util.openAddVolumeDialog()
    red_logic = slicer.app.layoutManager().sliceWidget("Red").sliceLogic()
    red_cn = red_logic.GetSliceCompositeNode()
    fgrdVolID = red_cn.GetBackgroundVolumeID()
    fgrdNode = slicer.util.getNode(fgrdVolID)
    fMat=vtk.vtkMatrix4x4()
    fgrdNode.GetIJKToRASDirectionMatrix(fMat)
    bgrdName = fgrdNode.GetName() + '_gray'
    self.tilename = fgrdNode.GetName() + '_gray'
    self.parameterNode.SetParameter("SlicerPathology,tilename", self.tilename)
    # Get dummy grayscale image
    magnitude = vtk.vtkImageMagnitude()
    magnitude.SetInputData(fgrdNode.GetImageData())
    magnitude.Update()  
    bgrdNode = slicer.vtkMRMLScalarVolumeNode()
    bgrdNode.SetImageDataConnection(magnitude.GetOutputPort())
    bgrdNode.SetName(bgrdName)
    bgrdNode.SetIJKToRASDirectionMatrix(fMat)
    slicer.mrmlScene.AddNode(bgrdNode)
    bgrdVolID = bgrdNode.GetID()  
    # Reset slice configuration
    red_cn.SetForegroundVolumeID(fgrdVolID)
    red_cn.SetBackgroundVolumeID(bgrdVolID)
    red_cn.SetForegroundOpacity(1)   
    self.checkAndSetLUT() 
    print bgrdName
    cv = slicer.util.getNode(bgrdName)
    self.volumesLogic = slicer.modules.volumes.logic()
    labelName = bgrdName+'-label'
    refLabel = self.volumesLogic.CreateAndAddLabelVolume(slicer.mrmlScene,cv,labelName)
    refLabel.GetDisplayNode().SetAndObserveColorNodeID(self.SlicerPathologyColorNode.GetID())
    self.editorWidget.helper.setMasterVolume(cv)
Exemple #23
0
    def createUserInterface(self):

        self.__layout = self.__parent.createUserInterface()

        step_label = qt.QLabel(
            """Review your segmentation. Use the 3D Visualization slider to see your segmentation in context with your image. Use the Editor panel to apply spot edits to your segmentation. If you would like to start over, see the Restart box below"""
        )
        step_label.setWordWrap(True)
        self.__primaryGroupBox = qt.QGroupBox()
        self.__primaryGroupBox.setTitle('Information')
        self.__primaryGroupBoxLayout = qt.QFormLayout(self.__primaryGroupBox)
        self.__primaryGroupBoxLayout.addRow(step_label)
        self.__layout.addRow(self.__primaryGroupBox)

        # self.__threshRange = slicer.qMRMLRangeWidget()
        # self.__threshRange.decimals = 0
        # self.__threshRange.singleStep = 1
        # self.__threshRange.connect('valuesChanged(double,double)', self.onThresholdChanged)
        # qt.QTimer.singleShot(0, self.killButton)

        # ThreshGroupBox = qt.QGroupBox()
        # ThreshGroupBox.setTitle('3D Visualization Intensity Threshold')
        # ThreshGroupBoxLayout = qt.QFormLayout(ThreshGroupBox)
        # ThreshGroupBoxLayout.addRow(self.__threshRange)
        # self.__layout.addRow(ThreshGroupBox)

        editorWidgetParent = slicer.qMRMLWidget()
        editorWidgetParent.setLayout(qt.QVBoxLayout())
        editorWidgetParent.setMRMLScene(slicer.mrmlScene)
        self.EditorWidget = EditorWidget(parent=editorWidgetParent)
        self.EditorWidget.setup()
        self.__layout.addRow(editorWidgetParent)

        RestartGroupBox = qt.QGroupBox()
        RestartGroupBox.setTitle('Restart')
        RestartGroupBoxLayout = qt.QFormLayout(RestartGroupBox)

        self.__RestartButton = qt.QPushButton('Return to Step 1')
        RestartGroupBoxLayout.addRow(self.__RestartButton)

        self.__RemoveRegisteredImage = qt.QCheckBox()
        self.__RemoveRegisteredImage.checked = True
        self.__RemoveRegisteredImage.setToolTip(
            "Delete your registered images.")
        RestartGroupBoxLayout.addRow("Delete Registered images: ",
                                     self.__RemoveRegisteredImage)

        self.__RemoveNormalizedImages = qt.QCheckBox()
        self.__RemoveNormalizedImages.checked = True
        self.__RemoveNormalizedImages.setToolTip(
            "Delete your normalized images.")
        RestartGroupBoxLayout.addRow("Delete Normalized images: ",
                                     self.__RemoveNormalizedImages)

        self.__RemoveSubtractionMap = qt.QCheckBox()
        self.__RemoveSubtractionMap.checked = True
        self.__RemoveSubtractionMap.setToolTip("Delete your subtraction map.")
        RestartGroupBoxLayout.addRow("Delete Subtraction map: ",
                                     self.__RemoveSubtractionMap)

        self.__RemoveCroppedMap = qt.QCheckBox()
        self.__RemoveCroppedMap.checked = True
        self.__RemoveCroppedMap.setToolTip(
            "Delete the cropped version of your input volume.")
        RestartGroupBoxLayout.addRow("Delete Cropped Volume: ",
                                     self.__RemoveCroppedMap)

        self.__RemoveROI = qt.QCheckBox()
        self.__RemoveROI.checked = False
        self.__RemoveROI.setToolTip(
            "Delete the ROI you made with your markup points.")
        RestartGroupBoxLayout.addRow("Delete Full ROI: ", self.__RemoveROI)

        self.__RemoveThresholdedROI = qt.QCheckBox()
        self.__RemoveThresholdedROI.checked = False
        self.__RemoveThresholdedROI.setToolTip(
            "Delete the intensity-thresholded version of your ROI.")
        RestartGroupBoxLayout.addRow("Delete Thresholded ROI: ",
                                     self.__RemoveThresholdedROI)

        self.__RemoveMarkups = qt.QCheckBox()
        self.__RemoveMarkups.checked = True
        self.__RemoveMarkups.setToolTip(
            "Delete the markup points you used to create your 3D ROI.")
        RestartGroupBoxLayout.addRow("Delete Markup Points: ",
                                     self.__RemoveMarkups)

        self.__RemoveModels = qt.QCheckBox()
        self.__RemoveModels.checked = True
        self.__RemoveModels.setToolTip(
            "Delete the 3D model you created from your markup points.")
        RestartGroupBoxLayout.addRow("Delete 3D Model: ", self.__RemoveModels)

        self.__RestartButton.connect('clicked()', self.Restart)
        self.__RestartActivated = True

        self.__layout.addRow(RestartGroupBox)
Exemple #24
0
class SlicerPathologyWidget(ScriptedLoadableModuleWidget, ModuleWidgetMixin):
    def __init__(self, parent=None):
        ScriptedLoadableModuleWidget.__init__(self, parent)
        self.resourcesPath = os.path.join(
            slicer.modules.slicerpathology.path.replace(
                self.moduleName + ".py", ""), 'Resources')
        self.modulePath = os.path.dirname(
            slicer.util.modulePath(self.moduleName))
        self.currentStep = 1

    def setup(self):
        ScriptedLoadableModuleWidget.setup(self)
        # this section is for custom color box
        infoGroupBox = qt.QWidget()
        hbox = qt.QHBoxLayout()
        hbox.setMargin(0)
        self.studySelectionGroupBoxLayout = qt.QGridLayout()
        infoGroupBox.setLayout(hbox)
        self.studySelectionGroupBoxLayout.addWidget(infoGroupBox, 0, 3, 1, 1)
        infoIcon = qt.QPixmap(
            os.path.join(self.resourcesPath, 'Icons', 'icon-infoBox.png'))
        self.customLUTInfoIcon = qt.QLabel()
        self.customLUTInfoIcon.setPixmap(infoIcon)
        self.customLUTInfoIcon.setSizePolicy(PythonQt.QtGui.QSizePolicy())
        hbox.addWidget(self.customLUTInfoIcon)
        self.customLUTLabel = qt.QLabel()
        hbox.addWidget(self.customLUTLabel)
        # end of custom color box section
        self.setupIcons()
        self.setupTabBarNavigation()
        self.setupsetupUI()
        self.setupimageSelectionUI()
        self.setupsegmentationUI()
        self.setupsubmissionUI()
        self.setupEditorWidget()
        editUtil = EditorLib.EditUtil.EditUtil()
        self.parameterNode = editUtil.getParameterNode()

        # 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)

        #
        # check box to trigger taking screen shots for later use in tutorials
        #
        self.enableScreenshotsFlagCheckBox = qt.QCheckBox()
        self.enableScreenshotsFlagCheckBox.checked = 0
        self.enableScreenshotsFlagCheckBox.setToolTip(
            "If checked, take screen shots for tutorials. Use Save Data to write them to disk."
        )
        parametersFormLayout.addRow("Enable Screenshots",
                                    self.enableScreenshotsFlagCheckBox)

        #
        # scale factor for screen shots
        #
        self.screenshotScaleFactorSliderWidget = ctk.ctkSliderWidget()
        self.screenshotScaleFactorSliderWidget.singleStep = 1.0
        self.screenshotScaleFactorSliderWidget.minimum = 1.0
        self.screenshotScaleFactorSliderWidget.maximum = 50.0
        self.screenshotScaleFactorSliderWidget.value = 1.0
        self.screenshotScaleFactorSliderWidget.setToolTip(
            "Set scale factor for the screen shots.")
        parametersFormLayout.addRow("Screenshot scale factor",
                                    self.screenshotScaleFactorSliderWidget)

        #
        # Apply Button
        #
        #self.applyButton = qt.QPushButton("Apply")
        #self.applyButton.toolTip = "Run the algorithm."
        #self.applyButton.enabled = False
        #parametersFormLayout.addRow(self.applyButton)

        # Add vertical spacer
        self.layout.addStretch(1)

    def cleanup(self):
        pass

    def onSelect(self):
        self.applyButton.enabled = self.inputSelector.currentNode(
        ) and self.outputSelector.currentNode()

    def onApplyButton(self):
        logic = SlicerPathologyLogic()
        enableScreenshotsFlag = self.enableScreenshotsFlagCheckBox.checked
        screenshotScaleFactor = int(
            self.screenshotScaleFactorSliderWidget.value)
        print("Run the algorithm")
        logic.run(self.inputSelector.currentNode(),
                  self.outputSelector.currentNode(), enableScreenshotsFlag,
                  screenshotScaleFactor)

    def setupIcons(self):
        self.setupIcon = self.createIcon('icon-setup.png')
        self.imageSelectionIcon = self.createIcon('icon-imageselection.png')
        self.segmentationIcon = self.createIcon('icon-segmentation.png')
        self.submissionIcon = self.createIcon('icon-submission.png')

    def setupTabBarNavigation(self):
        self.tabWidget = qt.QTabWidget()
        self.layout.addWidget(self.tabWidget)

        setupGroupBox = qt.QGroupBox()
        imageSelectionGroupBox = qt.QGroupBox()
        segmentationGroupBox = qt.QGroupBox()
        submissionGroupBox = qt.QGroupBox()

        self.setupGroupBoxLayout = qt.QFormLayout()
        self.imageSelectionGroupBoxLayout = qt.QFormLayout()
        self.segmentationGroupBoxLayout = qt.QGridLayout()
        self.submissionGroupBoxLayout = qt.QFormLayout()

        setupGroupBox.setLayout(self.setupGroupBoxLayout)
        imageSelectionGroupBox.setLayout(self.imageSelectionGroupBoxLayout)
        segmentationGroupBox.setLayout(self.segmentationGroupBoxLayout)
        submissionGroupBox.setLayout(self.submissionGroupBoxLayout)

        self.tabWidget.setIconSize(qt.QSize(85, 30))

        self.tabWidget.addTab(setupGroupBox, self.setupIcon, '')
        self.tabWidget.addTab(imageSelectionGroupBox, self.imageSelectionIcon,
                              '')
        self.tabWidget.addTab(segmentationGroupBox, self.segmentationIcon, '')
        self.tabWidget.addTab(submissionGroupBox, self.submissionIcon, '')
        self.tabWidget.connect('currentChanged(int)', self.onTabWidgetClicked)

        self.setTabsEnabled([1, 2, 3, 4], True)

    def onTabWidgetClicked(self, currentIndex):
        if currentIndex == 0:
            self.onStep1Selected()
        if currentIndex == 1:
            print "to be implemented..."
        if currentIndex == 2:
            print "to be implemented..."
        if currentIndex == 3:
            print "to be implemented..."

    def setTabsEnabled(self, indexes, enabled):
        for index in indexes:
            self.tabWidget.childAt(1, 1).setTabEnabled(index, enabled)

    def onStep1Selected(self):
        #if self.checkStep3or4Leave() is True:
        #return
        if self.currentStep == 1:
            return
        self.currentStep = 1
        self.setTabsEnabled([0], True)
        self.setTabsEnabled([1, 2, 3], False)

    def setupsetupUI(self):
        self.setupUserName = qt.QLineEdit()
        self.setupGroupBoxLayout.addRow("Username:"******"Password:"******"Load Data")
        self.imageSelectionGroupBoxLayout.addWidget(self.loadDataButton)
        self.loadDataButton.connect('clicked()', self.loadTCGAData)
        print "Adding WIP Button!"
        self.WIP = qt.QPushButton("WIP")
        self.WIP.connect('clicked()', self.onWIPButtonClicked)
        self.imageSelectionGroupBoxLayout.addWidget(self.WIP)

    def setupsegmentationUI(self):
        print "adding this for now..."

    def setupsubmissionUI(self):
        self.dataDirButton = ctk.ctkDirectoryButton()
        self.submissionGroupBoxLayout.addWidget(qt.QLabel("Data directory:"))
        self.submissionGroupBoxLayout.addWidget(self.dataDirButton)
        self.SaveButton = qt.QPushButton("Save")
        self.submissionGroupBoxLayout.addWidget(self.SaveButton)
        self.SaveButton.connect('clicked()', self.onSaveButtonClicked)
        self.WebSaveButton = qt.QPushButton("Submit to web")
        self.submissionGroupBoxLayout.addWidget(self.WebSaveButton)
        self.WebSaveButton.connect('clicked()', self.onWebSaveButtonClicked)

    def onWIPButtonClicked(self):
        print "WIP ME!"
        from EditorLib import EditUtil
        self.editUtil = EditorLib.EditUtil.EditUtil()
        self.labelNode = self.editUtil.getLabelVolume()
        print self.labelNode.GetImageData()
        self.labelNode.GetImageData().Modified()
        self.labelNode.Modified()
        self.currentMessage = "WIP Code is done being executed..."
        slicer.util.showStatusMessage(self.currentMessage)

    def onSaveButtonClicked(self):
        bundle = EditUtil.EditUtil().getParameterNode().GetParameter(
            'QuickTCGAEffect,erich')
        tran = json.loads(bundle)
        layers = []
        for key in tran:
            nn = tran[key]
            nn["file"] = key + '.tif'
            layers.append(tran[key])
        j = {}
        j['layers'] = layers
        j['username'] = self.setupUserName.text
        j['sourcetile'] = self.tilename
        j['generator'] = "3DSlicer-4.5.0 with SlicerPathology v1.0a"
        j['timestamp'] = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
        labelNodes = slicer.util.getNodes('vtkMRMLLabelMapVolumeNode*')
        savedMessage = 'Segmentations for the following series were saved:\n\n'
        for label in labelNodes.values():
            labelName = label.GetName()
            labelFileName = os.path.join(self.dataDirButton.directory,
                                         labelName + '.tif')
            print "labelFileName : " + labelFileName
            sNode = slicer.vtkMRMLVolumeArchetypeStorageNode()
            sNode.SetFileName(labelFileName)
            sNode.SetWriteFileFormat('tif')
            sNode.SetURI(None)
            success = sNode.WriteData(label)
            if success:
                print "successful writing " + labelFileName
            else:
                print "failed writing " + labelFileName
        jstr = json.dumps(j, sort_keys=True, indent=4, separators=(',', ': '))
        f = open(
            os.path.join(self.dataDirButton.directory,
                         self.tilename + '.json'), 'w')
        f.write(jstr)
        f.close()

    def onWebSaveButtonClicked(self):
        print "Web Save to be implemented...."

    def checkAndSetLUT(self):
        # Default to module color table
        self.resourcesPath = os.path.join(
            slicer.modules.slicerpathology.path.replace(
                self.moduleName + ".py", ""), 'Resources')
        self.colorFile = os.path.join(self.resourcesPath,
                                      "Colors/SlicerPathology.csv")
        self.customLUTLabel.setText('Using Default LUT')
        try:
            self.editorWidget.helper.structureListWidget.merge = None
        except AttributeError:
            pass
        # setup the color table, make sure SlicerPathology LUT is a singleton
        allColorTableNodes = slicer.util.getNodes(
            'vtkMRMLColorTableNode*').values()
        for ctn in allColorTableNodes:
            #print "color: "+ctn.GetName()
            if ctn.GetName() == 'SlicerPathologyColor':
                slicer.mrmlScene.RemoveNode(ctn)
                break
        self.SlicerPathologyColorNode = slicer.vtkMRMLColorTableNode()
        colorNode = self.SlicerPathologyColorNode
        colorNode.SetName('SlicerPathologyColor')
        slicer.mrmlScene.AddNode(colorNode)
        colorNode.SetTypeToUser()
        with open(self.colorFile) as f:
            n = sum(1 for line in f)
        colorNode.SetNumberOfColors(n - 1)
        colorNode.NamesInitialisedOn()
        import csv
        self.structureNames = []
        with open(self.colorFile, 'rb') as csvfile:
            reader = csv.DictReader(csvfile, delimiter=',')
            for index, row in enumerate(reader):
                success = colorNode.SetColor(index, row['Label'],
                                             float(row['R']) / 255,
                                             float(row['G']) / 255,
                                             float(row['B']) / 255,
                                             float(row['A']))
                if not success:
                    print "color %s could not be set" % row['Label']
                self.structureNames.append(row['Label'])

    def setupEditorWidget(self):
        editorWidgetParent = slicer.qMRMLWidget()
        editorWidgetParent.setLayout(qt.QVBoxLayout())
        editorWidgetParent.setMRMLScene(slicer.mrmlScene)
        self.editorWidget = EditorWidget(parent=editorWidgetParent)
        self.editorWidget.setup()
        self.segmentationGroupBoxLayout.addWidget(self.editorWidget.parent)

    def loadTCGAData(self):
        slicer.util.openAddVolumeDialog()
        red_logic = slicer.app.layoutManager().sliceWidget("Red").sliceLogic()
        red_cn = red_logic.GetSliceCompositeNode()
        fgrdVolID = red_cn.GetBackgroundVolumeID()
        fgrdNode = slicer.util.getNode(fgrdVolID)
        fMat = vtk.vtkMatrix4x4()
        fgrdNode.GetIJKToRASDirectionMatrix(fMat)
        bgrdName = fgrdNode.GetName() + '_gray'
        self.tilename = fgrdNode.GetName() + '_gray'
        self.parameterNode.SetParameter("SlicerPathology,tilename",
                                        self.tilename)
        # Get dummy grayscale image
        magnitude = vtk.vtkImageMagnitude()
        magnitude.SetInputData(fgrdNode.GetImageData())
        magnitude.Update()
        bgrdNode = slicer.vtkMRMLScalarVolumeNode()
        bgrdNode.SetImageDataConnection(magnitude.GetOutputPort())
        bgrdNode.SetName(bgrdName)
        bgrdNode.SetIJKToRASDirectionMatrix(fMat)
        slicer.mrmlScene.AddNode(bgrdNode)
        bgrdVolID = bgrdNode.GetID()
        # Reset slice configuration
        red_cn.SetForegroundVolumeID(fgrdVolID)
        red_cn.SetBackgroundVolumeID(bgrdVolID)
        red_cn.SetForegroundOpacity(1)
        self.checkAndSetLUT()
        print bgrdName
        cv = slicer.util.getNode(bgrdName)
        self.volumesLogic = slicer.modules.volumes.logic()
        labelName = bgrdName + '-label'
        refLabel = self.volumesLogic.CreateAndAddLabelVolume(
            slicer.mrmlScene, cv, labelName)
        refLabel.GetDisplayNode().SetAndObserveColorNodeID(
            self.SlicerPathologyColorNode.GetID())
        self.editorWidget.helper.setMasterVolume(cv)
class ReviewStep(BeersSingleStep):
    def __init__(self, stepid):
        """ This method creates a drop-down menu that includes the whole step.
			The description also acts as a tooltip for the button. There may be 
			some way to override this. The initialize method is inherited
			from ctk.
		"""
        self.initialize(stepid)
        self.setName('6. Review')
        self.setDescription(
            'The segment from the subtraction map is now overlaid on your post-contrast image. Use the threshold bar below to edit the volume rendering node. Use the official Volume Rendering module for more specific visualization.'
        )

        self.__pNode = None
        self.__vrDisplayNode = None
        self.__threshold = [-1, -1]

        # initialize VR stuff
        self.__vrLogic = slicer.modules.volumerendering.logic()
        self.__vrOpacityMap = None

        self.__roiSegmentationNode = None
        self.__roiVolume = None

        self.__parent = super(ReviewStep, self)
        self.__RestartActivated = False

    def createUserInterface(self):
        """ This step is mostly empty. A volume rendering threshold is added to be useful.
		"""

        self.__layout = self.__parent.createUserInterface()

        self.__threshRange = slicer.qMRMLRangeWidget()
        self.__threshRange.decimals = 0
        self.__threshRange.singleStep = 1
        self.__threshRange.connect('valuesChanged(double,double)',
                                   self.onThresholdChanged)
        qt.QTimer.singleShot(0, self.killButton)

        ThreshGroupBox = qt.QGroupBox()
        ThreshGroupBox.setTitle('3D Visualization Intensity Threshold')
        ThreshGroupBoxLayout = qt.QFormLayout(ThreshGroupBox)
        ThreshGroupBoxLayout.addRow(self.__threshRange)
        self.__layout.addRow(ThreshGroupBox)

        editorWidgetParent = slicer.qMRMLWidget()
        editorWidgetParent.setLayout(qt.QVBoxLayout())
        editorWidgetParent.setMRMLScene(slicer.mrmlScene)
        self.__editorWidget = EditorWidget(parent=editorWidgetParent)
        self.__editorWidget.setup()
        self.__layout.addRow(editorWidgetParent)
        self.hideUnwantedEditorUIElements()

        RestartGroupBox = qt.QGroupBox()
        RestartGroupBox.setTitle('Restart')
        RestartGroupBoxLayout = qt.QFormLayout(RestartGroupBox)

        self.__RestartButton = qt.QPushButton('Return to Step 1')
        RestartGroupBoxLayout.addRow(self.__RestartButton)

        self.__RemoveCroppedSubtractionMap = qt.QCheckBox()
        self.__RemoveCroppedSubtractionMap.checked = True
        self.__RemoveCroppedSubtractionMap.setToolTip(
            "Delete the cropped version of your subtaction map.")
        RestartGroupBoxLayout.addRow("Delete cropped subtraction map: ",
                                     self.__RemoveCroppedSubtractionMap)

        self.__RemoveFullSubtracitonMap = qt.QCheckBox()
        self.__RemoveFullSubtracitonMap.checked = True
        self.__RemoveFullSubtracitonMap.setToolTip(
            "Delete the full version of your subtaction map.")
        RestartGroupBoxLayout.addRow("Delete full subtraction map: ",
                                     self.__RemoveFullSubtracitonMap)

        self.__RemoveROI = qt.QCheckBox()
        self.__RemoveROI.checked = False
        self.__RemoveROI.setToolTip(
            "Delete the ROI resulting from your subtaction map.")
        RestartGroupBoxLayout.addRow("Delete ROI: ", self.__RemoveROI)

        # self.__RestartButton.setEnabled(0)

        self.__RestartButton.connect('clicked()', self.Restart)
        self.__RestartActivated = True

        self.__layout.addRow(RestartGroupBox)

    def hideUnwantedEditorUIElements(self):
        print self.__editorWidget.editBoxFrame
        self.__editorWidget.volumes.hide()
        print dir(self.__editorWidget)
        print slicer.util.findChildren()
        # for widgetName in slicer.util.findChildren(self.__editorWidget.editBoxFrame):
        for widgetName in slicer.util.findChildren(self.__editorWidget.helper):
            # widget = slicer.util.findChildren(self.__editorWidget.editBoxFrame)
            print widgetName.objectName
            # print widgetName.parent.name
            # widgetName.hide()
        for widget in [
                'DrawEffectToolButton', 'RectangleEffectToolButton',
                'IdentifyIslandsEffectToolButton',
                'RemoveIslandsEffectToolButton', 'SaveIslandEffectToolButton',
                'RowFrame2'
        ]:
            slicer.util.findChildren(self.__editorWidget.editBoxFrame,
                                     widget)[0].hide()
        print slicer.util.findChildren('', 'EditColorFrame')

    def Restart(self):
        print self.__pNode

        slicer.mrmlScene.RemoveNode(testVolume)

        self.__pNode.SetParameter('baselineVolumeID', None)
        self.__pNode.SetParameter('croppedSubtractVolumeID', None)
        self.__pNode.SetParameter('croppedSubtractVolumeSegmentationID', None)
        self.__pNode.SetParameter('followupVolumeID', None)
        self.__pNode.SetParameter('roiNodeID', None)
        self.__pNode.SetParameter('roiTransformID', None)
        self.__pNode.SetParameter('subtractVolumeID', None)
        self.__pNode.SetParameter('vrDisplayNodeID', None)
        self.__pNode.SetParameter('thresholdRange', None)
        if self.__RestartActivated:
            self.workflow().goForward()

    def onThresholdChanged(self):

        if self.__vrOpacityMap == None:
            return

        range0 = self.__threshRange.minimumValue
        range1 = self.__threshRange.maximumValue

        self.__vrOpacityMap.RemoveAllPoints()
        self.__vrOpacityMap.AddPoint(range0 - 75, 0)
        self.__vrOpacityMap.AddPoint(range0, 1)
        self.__vrOpacityMap.AddPoint(range1, 1)
        self.__vrOpacityMap.AddPoint(range1 + 75, 0)

    def killButton(self):

        # ctk creates a useless final page button. This method gets rid of it.
        bl = slicer.util.findChildren(text='ReviewStep')
        ex = slicer.util.findChildren('', 'EditColorFrame')
        if len(bl):
            bl[0].hide()
        if len(ex):
            ex[0].hide()
            print 'success'
        else:
            print 'fail'

        self.__editLabelMapsFrame = slicer.util.findChildren(
            '', 'EditLabelMapsFrame')[0]
        self.__toolsColor = EditorLib.EditColor(self.__editLabelMapsFrame)

    def validate(self, desiredBranchId):

        # For now, no validation required.
        self.__parent.validationSucceeded(desiredBranchId)

    def onEntry(self, comingFrom, transitionType):
        super(ReviewStep, self).onEntry(comingFrom, transitionType)

        # self.__RestartButton.setEnabled(1)
        self.__RestartActivated = True

        pNode = self.parameterNode()
        self.__pNode = pNode

        self.__clippingModelNode = Helper.getNodeByID(
            pNode.GetParameter('clippingModelNodeID'))
        print self.__clippingModelNode
        print pNode.GetParameter('clippingModelNodeID')
        self.__baselineVolumeID = pNode.GetParameter('baselineVolumeID')
        self.__followupVolumeID = pNode.GetParameter('followupVolumeID')
        self.__subtractVolumeID = pNode.GetParameter('subtractVolumeID')
        self.__roiNodeID = pNode.GetParameter('roiNodeID')
        self.__followupVolumeNode = Helper.getNodeByID(self.__followupVolumeID)
        self.__subtractVolumeNode = Helper.getNodeByID(self.__subtractVolumeID)
        self.__vrDisplayNodeID = pNode.GetParameter('vrDisplayNodeID')
        self.__roiSegmentationNode = Helper.getNodeByID(
            pNode.GetParameter('croppedSubtractVolumeSegmentationID'))
        self.__roiVolumeNode = Helper.getNodeByID(
            pNode.GetParameter('croppedSubtractVolumeID'))

        self.__editorWidget.setMergeNode(self.__roiSegmentationNode)
        self.__clippingModelNode.GetDisplayNode().VisibilityOn()

        followupRange = self.__followupVolumeNode.GetImageData(
        ).GetScalarRange()
        ROIRange = self.__roiSegmentationNode.GetImageData().GetScalarRange()

        if self.__vrDisplayNode == None:
            if self.__vrDisplayNodeID != '':
                self.__vrDisplayNode = slicer.mrmlScene.GetNodeByID(
                    self.__vrDisplayNodeID)

        self.__vrDisplayNode.SetCroppingEnabled(1)
        self.__followupVolumeNode.AddAndObserveDisplayNodeID(
            self.__vrDisplayNode.GetID())
        Helper.InitVRDisplayNode(self.__vrDisplayNode, self.__followupVolumeID,
                                 self.__roiNodeID)

        self.__threshRange.minimum = followupRange[0]
        self.__threshRange.maximum = followupRange[1]
        self.__threshRange.setValues(followupRange[1] / 3,
                                     2 * followupRange[1] / 3)

        self.__vrOpacityMap = self.__vrDisplayNode.GetVolumePropertyNode(
        ).GetVolumeProperty().GetScalarOpacity()
        vrColorMap = self.__vrDisplayNode.GetVolumePropertyNode(
        ).GetVolumeProperty().GetRGBTransferFunction()

        vrColorMap.RemoveAllPoints()
        vrColorMap.AddRGBPoint(followupRange[0], 0.8, 0.8, 0)
        vrColorMap.AddRGBPoint(followupRange[1], 0.8, 0.8, 0)

        self.__vrDisplayNode.VisibilityOn()

        # threshRange = [self.__threshRange.minimumValue, self.__threshRange.maximumValue]
        # self.__vrOpacityMap.RemoveAllPoints()
        # self.__vrOpacityMap.AddPoint(threshRange[1]/2-75,0)
        # self.__vrOpacityMap.AddPoint(threshRange[1]/2,1)
        # self.__vrOpacityMap.AddPoint(threshRange[1]/2+200,1)
        # self.__vrOpacityMap.AddPoint(threshRange[1]/2+250,0)

        Helper.SetBgFgVolumes(self.__baselineVolumeID, self.__followupVolumeID)
        Helper.SetLabelVolume(self.__roiSegmentationNode.GetID())

        self.onThresholdChanged()

        pNode.SetParameter('currentStep', self.stepid)

        qt.QTimer.singleShot(0, self.killButton)

    def onExit(self, goingTo, transitionType):
        # extra error checking, in case the user manages to click ReportROI button
        super(BeersSingleStep, self).onExit(goingTo, transitionType)
Exemple #26
0
class qSlicerReportingModuleWidget:
    def __init__(self, parent=None):

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

        # Reference to the logic that Slicer instantiated
        self.__logic = slicer.modules.reporting.logic()
        if not self.__logic:
            # create a new instance
            self.__logic = slicer.modulelogic.vtkSlicerReportingModuleLogic()

        # Get the location and initialize the DICOM DB
        settings = qt.QSettings()
        self.__dbFileName = settings.value("DatabaseDirectory", "")
        if self.__dbFileName == "":
            Helper.Warning("DICOM Database is not accessible.")
        else:
            self.__dbFileName = self.__dbFileName + "/ctkDICOM.sql"

            if self.__logic.InitializeDICOMDatabase(self.__dbFileName):
                Helper.Info('DICOM database initialized correctly!')
            else:
                Helper.Error('Failed to initialize DICOM database at ' +
                             self.__dbFileName)

        if not self.__logic.GetMRMLScene():
            # set the logic's mrml scene
            self.__logic.SetMRMLScene(slicer.mrmlScene)

        # for export
        self.exportFileName = None
        self.exportFileDialog = None

        # initialize parameter node
        self.__parameterNode = None
        nNodes = slicer.mrmlScene.GetNumberOfNodesByClass(
            'vtkMRMLScriptedModuleNode')
        for n in xrange(nNodes):
            compNode = slicer.mrmlScene.GetNthNodeByClass(
                n, 'vtkMRMLScriptedModuleNode')
            compNode.SetReferenceCount(compNode.GetReferenceCount() - 1)
            nodeid = None
            if compNode.GetModuleName() == 'Reporting':
                self.__parameterNode = compNode
                'Found existing Reporting parameter node'
                break
        if self.__parameterNode == None:
            self.__parameterNode = slicer.vtkMRMLScriptedModuleNode()
            self.__parameterNode.SetModuleName('Reporting')
            self.__parameterNode.SetSingletonTag('Reporting')
            slicer.mrmlScene.AddNode(self.__parameterNode)

            # keep active report and volume
            self.__rNode = None
            self.__vNode = None

        if self.__parameterNode != None:
            paramID = self.__parameterNode.GetID()
            self.__logic.SetActiveParameterNodeID(paramID)
        else:
            Helper.Error('Unable to set logic active parameter node')

        # TODO: figure out why module/class hierarchy is different
        # between developer builds ans packages
        try:
            # for developer build...
            self.editUtil = EditorLib.EditUtil.EditUtil()
        except AttributeError:
            # for release package...
            self.editUtil = EditorLib.EditUtil()

    def setup(self):
        #
        # Input frame
        #
        self.__inputFrame = ctk.ctkCollapsibleButton()
        self.__inputFrame.text = "Input"
        self.__inputFrame.collapsed = 0
        inputFrameLayout = qt.QFormLayout(self.__inputFrame)

        self.layout.addWidget(self.__inputFrame)

        # Active report node
        label = qt.QLabel('Report: ')
        self.__reportSelector = slicer.qMRMLNodeComboBox()
        self.__reportSelector.nodeTypes = ['vtkMRMLReportingReportNode']
        self.__reportSelector.setMRMLScene(slicer.mrmlScene)
        self.__reportSelector.addEnabled = 1
        self.__reportSelector.removeEnabled = 0

        inputFrameLayout.addRow(label, self.__reportSelector)

        self.__reportSelector.connect('mrmlSceneChanged(vtkMRMLScene*)',
                                      self.onMRMLSceneChanged)
        self.__reportSelector.connect('currentNodeChanged(vtkMRMLNode*)',
                                      self.onReportNodeChanged)

        # Volume being annotated (only one is allowed for the report)
        label = qt.QLabel(
            'NOTE: Only volumes loaded from DICOM can be annotated!')
        inputFrameLayout.addRow(label)
        label = qt.QLabel('Annotated volume: ')
        self.__volumeSelector = slicer.qMRMLNodeComboBox()
        self.__volumeSelector.nodeTypes = ['vtkMRMLScalarVolumeNode']
        # only allow volumes with the attribute DICOM.instanceUIDs
        self.__volumeSelector.addAttribute('vtkMRMLScalarVolumeNode',
                                           'DICOM.instanceUIDs')
        self.__volumeSelector.setMRMLScene(slicer.mrmlScene)
        self.__volumeSelector.addEnabled = False

        inputFrameLayout.addRow(label, self.__volumeSelector)

        self.__volumeSelector.connect('currentNodeChanged(vtkMRMLNode*)',
                                      self.onAnnotatedVolumeNodeChanged)
        self.__volumeSelector.connect('mrmlSceneChanged(vtkMRMLScene*)',
                                      self.onMRMLSceneChanged)

        #
        # Annotation frame -- vocabulary-based description of what is
        # being annotated/marked up in this report
        #
        self.__annotationsFrame = ctk.ctkCollapsibleButton()
        self.__annotationsFrame.text = "Annotation"
        self.__annotationsFrame.collapsed = 0
        annotationsFrameLayout = qt.QFormLayout(self.__annotationsFrame)

        self.layout.addWidget(self.__annotationsFrame)

        self.__defaultColorNode = self.__logic.GetDefaultColorNode()

        self.__toolsColor = EditColor(self.__annotationsFrame,
                                      colorNode=self.__defaultColorNode)

        #
        # Markup frame -- summary of all the markup elements contained in the
        # report
        #
        self.__markupFrame = ctk.ctkCollapsibleButton()
        self.__markupFrame.text = "Markup"
        self.__markupFrame.collapsed = 0
        markupFrameLayout = qt.QFormLayout(self.__markupFrame)

        self.layout.addWidget(self.__markupFrame)

        # Add a flag to switch between different tree view models
        self.__useNewTreeView = 1

        # Add the tree widget
        if self.__useNewTreeView == 1:
            self.__markupTreeView = slicer.modulewidget.qMRMLReportingTreeView(
            )
            self.__markupTreeView.sceneModelType = "DisplayableHierarchy"
        else:
            self.__markupTreeView = slicer.qMRMLTreeView()
            self.__markupTreeView.sceneModelType = "Displayable"
        self.__markupTreeView.setMRMLScene(self.__logic.GetMRMLScene())

        self.__markupSliceText = qt.QLabel()
        markupFrameLayout.addRow(self.__markupSliceText)
        markupFrameLayout.addRow(self.__markupTreeView)

        # Editor frame
        self.__editorFrame = ctk.ctkCollapsibleButton()
        self.__editorFrame.text = 'Segmentation'
        self.__editorFrame.collapsed = 0
        editorFrameLayout = qt.QFormLayout(self.__editorFrame)

        label = qt.QLabel('Segmentation volume: ')
        self.__segmentationSelector = slicer.qMRMLNodeComboBox()
        self.__segmentationSelector.nodeTypes = ['vtkMRMLScalarVolumeNode']
        self.__segmentationSelector.setMRMLScene(slicer.mrmlScene)
        self.__segmentationSelector.addEnabled = 1
        self.__segmentationSelector.noneEnabled = 1
        self.__segmentationSelector.removeEnabled = 0
        self.__segmentationSelector.showHidden = 0
        self.__segmentationSelector.showChildNodeTypes = 0
        self.__segmentationSelector.selectNodeUponCreation = 1
        self.__segmentationSelector.addAttribute('vtkMRMLScalarVolumeNode',
                                                 'LabelMap', 1)

        editorFrameLayout.addRow(label, self.__segmentationSelector)

        editorWidgetParent = slicer.qMRMLWidget()
        editorWidgetParent.setLayout(qt.QVBoxLayout())
        editorWidgetParent.setMRMLScene(slicer.mrmlScene)
        self.__editorWidget = EditorWidget(parent=editorWidgetParent,
                                           showVolumesFrame=False)
        self.__editorWidget.setup()
        self.__editorWidget.toolsColor.frame.setVisible(False)
        editorFrameLayout.addRow(editorWidgetParent)

        markupFrameLayout.addRow(self.__editorFrame)

        self.__segmentationSelector.connect('currentNodeChanged(vtkMRMLNode*)',
                                            self.onSegmentationNodeChanged)
        self.__segmentationSelector.connect('mrmlSceneChanged(vtkMRMLScene*)',
                                            self.onMRMLSceneChanged)

        # IO frame
        self.__ioFrame = ctk.ctkCollapsibleButton()
        self.__ioFrame.text = 'Import/Export'
        self.__ioFrame.collapsed = 1
        ioFrameLayout = qt.QGridLayout(self.__ioFrame)

        self.layout.addWidget(self.__ioFrame)

        # Buttons to save/load report using AIM XML serialization
        label = qt.QLabel('Export folder')
        self.__exportFolderPicker = ctk.ctkDirectoryButton()
        exportButton = qt.QPushButton('Export')
        exportButton.connect('clicked()', self.onReportExport)
        ioFrameLayout.addWidget(label, 0, 0)
        ioFrameLayout.addWidget(self.__exportFolderPicker, 0, 1)
        ioFrameLayout.addWidget(exportButton, 0, 2)

        label = qt.QLabel('AIM file to import')
        self.__aimFilePicker = qt.QPushButton('N/A')
        self.__aimFilePicker.connect('clicked()', self.onSelectAIMFile)
        button = qt.QPushButton('Import')
        button.connect('clicked()', self.onReportImport)
        ioFrameLayout.addWidget(label, 1, 0)
        ioFrameLayout.addWidget(self.__aimFilePicker, 1, 1)
        ioFrameLayout.addWidget(button, 1, 2)
        self.__importAIMFile = None

        self.__reportSelector.connect('currentNodeChanged(vtkMRMLNode*)',
                                      self.updateWidgets)
        self.__volumeSelector.connect('currentNodeChanged(vtkMRMLNode*)',
                                      self.updateWidgets)
        self.updateWidgets()

        self.layout.addStretch(1)

        self.__editorParameterNode = self.editUtil.getParameterNode()

        self.__editorParameterNode.AddObserver(
            vtk.vtkCommand.ModifiedEvent, self.onEditorParameterNodeChanged)

    def onEditorParameterNodeChanged(self, caller, event):
        print('Editor parameter node changed')
        label = self.__editorParameterNode.GetParameter('label')
        if self.__rNode:
            print("Updating report label")
            self.__rNode.SetFindingLabel(int(label))

    def enter(self):
        # switch to Two-over-Two layout
        lm = slicer.app.layoutManager()
        lm.setLayout(26)  # two over two

        # update the logic to know that the module has been entered
        self.__logic.GUIHiddenOff()
        self.updateWidgetFromParameters()

        # respond to error events
        Helper.Info(
            'Enter: Setting up connection to respond to logic error events')
        hasObserver = self.__logic.HasObserver(vtk.vtkCommand.ErrorEvent)
        if hasObserver == 0:
            tag = self.__logic.AddObserver(vtk.vtkCommand.ErrorEvent,
                                           self.respondToErrorMessage)
            # print '\tobserver tag = ',tag
        else:
            Helper.Debug('Logic already has an observer on the ErrorEvent')

        vnode = self.__volumeSelector.currentNode()
        if vnode != None:
            # print "Enter: setting active hierarchy from node ",vnode.GetID()
            # update the logic active markup
            self.__logic.SetActiveMarkupHierarchyIDFromNode(vnode)
            self.updateTreeView()

        self.__editorWidget.enter()

    def exit(self):
        self.updateParametersFromWidget()

        Helper.Debug(
            "Reporting Exit. Letting logic know that module has been exited")
        # let the module logic know that the GUI is hidden, so that fiducials can go elsewehre
        self.__logic.GUIHiddenOn()
        # disconnect observation
        self.__logic.RemoveObservers(vtk.vtkCommand.ErrorEvent)

        self.__editorWidget.exit()

    # respond to error events from the logic
    def respondToErrorMessage(self, caller, event):
        errorMessage = self.__logic.GetErrorMessage()
        # inform user only if the message is not empty since vtkErrorMacro invokes this event as well
        if errorMessage != None:
            Helper.Debug('respondToErrorMessage, event = ' + str(event) +
                         ', message =\n\t' + str(errorMessage))
            errorDialog = qt.QErrorMessage(self.parent)
            errorDialog.showMessage(errorMessage)

    def onMRMLSceneChanged(self, mrmlScene):
        if mrmlScene != self.__logic.GetMRMLScene():
            self.__logic.SetMRMLScene(mrmlScene)
            self.__logic.RegisterNodes()
        self.__reportSelector.setMRMLScene(slicer.mrmlScene)

    def updateTreeView(self):
        # make the tree view update
        if self.__useNewTreeView == 1:
            self.__markupTreeView.updateTreeView()
        else:
            self.__markupTreeView.sceneModelType = "Displayable"
            nodeTypes = [
                'vtkMRMLDisplayableHierarchyNode',
                'vtkMRMLAnnotationHierarchyNode', 'vtkMRMLAnnotationNode',
                'vtkMRMLVolumeNode', 'vtkMRMLReportingReportNode'
            ]
            self.__markupTreeView.nodeTypes = nodeTypes
            self.__markupTreeView.listenNodeModifiedEvent = 1
            self.__markupTreeView.sceneModelType = "Displayable"
            # show these nodes even if they're hidden by being children of hidden hierarchy nodes
            showHiddenNodeTypes = [
                'vtkMRMLAnnotationNode', 'vtkMRMLVolumeNode',
                'vtkMRMLDisplayableHierarchyNode'
            ]
            self.__markupTreeView.model(
            ).showHiddenForTypes = showHiddenNodeTypes
        # set the root to be the current report hierarchy root
        if self.__rNode == None:
            Helper.Error("updateTreeView: report node is not initialized!")
            self.__markupTreeView.setRootNode(None)
            return
        else:
            # the tree root node has to be a hierarchy node, so get the associated hierarchy node for the active report node
            rootNode = slicer.vtkMRMLHierarchyNode(
            ).GetAssociatedHierarchyNode(self.__rNode.GetScene(),
                                         self.__rNode.GetID())
            if rootNode:
                self.__markupTreeView.setRootNode(rootNode)
                Helper.Debug("Setting tree view root to be " +
                             rootNode.GetID())
                self.__markupTreeView.expandAll()
            else:
                Helper.Debug("Setting tree view root to be None")
                self.__markupTreeView.setRootNode(None)

    def onAnnotatedVolumeNodeChanged(self):
        Helper.Debug("onAnnotatedVolumeNodeChanged()")

        # get the current volume node
        selectedVolume = self.__volumeSelector.currentNode()

        # do the error checks
        if selectedVolume == None or self.__rNode == None:
            self.__volumeSelector.setCurrentNode(None)
            return

        uids = selectedVolume.GetAttribute('DICOM.instanceUIDs')
        if uids == None:
            Helper.ErrorPopup(
                "Volume \"" + selectedVolume.GetName() +
                "\" was not loaded from DICOM. Only volumes loaded from DICOM data can be annotated in the Reporting module."
            )
            self.__volumeSelector.setCurrentNode(None)
            return

        nSlices = selectedVolume.GetImageData().GetExtent()[-1] + 1
        if nSlices != len(string.split(uids)):
            Helper.ErrorPopup(
                "Volume \"" + selectedVolume.GetName() +
                "\" was loaded from multi-frame DICOM. Multi-frame DICOM is currently not supported by the Reporting module"
            )
            self.__volumeSelector.setCurrentNode(None)
            return

        # volume node is valid!
        self.__vNode = selectedVolume

        # update the report node
        if self.__rNode != None:
            self.__rNode.SetVolumeNodeID(self.__vNode.GetID())
            self.__rNode.SetName('Report for Volume ' + self.__vNode.GetName())

        Helper.SetBgFgVolumes(self.__vNode.GetID(), '')
        Helper.RotateToVolumePlanes()

        # go over all label nodes in the scene
        # if there is a label that has the selected volume as associated node,
        #   initialize label selector to show that label
        volumeNodes = slicer.mrmlScene.GetNodesByClass(
            'vtkMRMLScalarVolumeNode')
        volumeNodes.SetReferenceCount(volumeNodes.GetReferenceCount() - 1)
        associatedLabelFound = False
        for i in range(volumeNodes.GetNumberOfItems()):
            vol = volumeNodes.GetItemAsObject(i)
            associatedNodeID = vol.GetAttribute('AssociatedNodeID')
            label = vol.GetAttribute('LabelMap')
            if associatedNodeID == self.__vNode.GetID() and label == '1':
                Helper.SetLabelVolume(vol.GetID())
                associatedLabelFound = True

        # if there is no associated label node, set the selector to none
        if associatedLabelFound == False:
            Helper.SetLabelVolume("")

        orientation = Helper.GetScanOrderSliceName(self.__vNode)
        message = "Slice viewers to be used for markup: "
        for sliceViewer in orientation:
            message = message + sliceViewer
            if orientation.index(sliceViewer) < (len(orientation) - 1):
                message = message + ", "
        Helper.Debug(message)
        self.__markupSliceText.text = message

        # take the first one
        self.__parameterNode.SetParameter('acquisitionSliceViewer',
                                          orientation[0])

        # print "Calling logic to set up hierarchy"
        self.__logic.InitializeHierarchyForVolume(self.__vNode)
        self.updateTreeView()

    def onSegmentationNodeChanged(self):
        Helper.Debug('onSegmentationNodeChanged()')

        if self.__vNode == None:
            Helper.Error(
                'Should not be possible to select segmentation unless annotated volume is initialized!'
            )
            return

        # get the current segmentation (label) node
        sNode = self.__segmentationSelector.currentNode()
        if sNode == None:
            self.updateWidgets()
            return

        # if it's a new label, it should have/will be added to the report
        # automatically
        image = sNode.GetImageData()
        if image == None:
            Helper.initializeNewLabel(sNode, self.__vNode)
        else:
            # if it's an existing label, we need to check that the geometry matches
            # the annotated label geometry, and if so, add it to the hierarchy
            if Helper.GeometriesMatch(sNode, self.__vNode) == False:
                Helper.ErrorPopup(
                    'The geometry of the segmentation label you attempted to select does not match the geometry of the volume being annotated! Please select a different label or create a new one.'
                )
                self.__segmentationSelector.setCurrentNode(None)
                self.updateWidgets()
                return

        # assign the color LUT we use
        dNode = sNode.GetDisplayNode()
        dNode.SetAndObserveColorNodeID(self.__defaultColorNode.GetID())

        sNode.SetAttribute('AssociatedNodeID', self.__vNode.GetID())
        self.__logic.AddNodeToReport(sNode)

        # assign the volume and the selected color to the editor parameter node
        Helper.SetLabelVolume(sNode.GetID())

        # TODO: disable adding new label node to the hierarchy if it was added
        # outside the reporting module

        self.__segmentationSelector.setCurrentNode(sNode)

        self.__editorWidget.setMasterNode(self.__vNode)
        self.__editorWidget.setMergeNode(sNode)

        self.__editorParameterNode.Modified()

        self.updateWidgets()

    def onReportNodeChanged(self):
        Helper.Debug("onReportNodeChanged()")

        # cancel the active effect in Editor
        if self.__editorWidget:
            self.__editorWidget.toolsBox.defaultEffect()
        # TODO
        #  -- initialize annotations and markup frames based on the report node
        #  content
        self.__rNode = self.__reportSelector.currentNode()

        self.__segmentationSelector.setCurrentNode(None)
        # disable editor frame
        self.onSegmentationNodeChanged()

        if self.__rNode != None:

            Helper.Debug("Selected report has changed to " +
                         self.__rNode.GetID())

            if self.__rNode.GetDICOMDatabaseFileName() == "":
                self.__rNode.SetDICOMDatabaseFileName(self.__dbFileName)

            self.__parameterNode.SetParameter('reportID', self.__rNode.GetID())

            # setup the default color node, if not initialized
            if self.__rNode.GetColorNodeID() == "":
                self.__rNode.SetColorNodeID(self.__defaultColorNode.GetID())
                Helper.Debug('Set color node id to ' +
                             self.__defaultColorNode.GetID())
            else:
                Helper.Debug('Color node has already been set to ' +
                             self.__rNode.GetColorNodeID())

            self.__logic.InitializeHierarchyForReport(self.__rNode)
            self.updateTreeView()
            vID = self.__rNode.GetVolumeNodeID()
            if vID:
                Helper.Debug('Have a volume node id in the report ' + vID +
                             ', setting current volume node selector')
                self.__vNode = slicer.mrmlScene.GetNodeByID(vID)
                self.__volumeSelector.setCurrentNode(self.__vNode)
            else:
                Helper.Debug(
                    'Do not have a volume id in the report, setting current volume node selector to none'
                )
                # set the volume to be none
                self.__vNode = None
                self.__volumeSelector.setCurrentNode(None)

            # hide the markups that go with other report nodes
            self.__logic.HideAnnotationsForOtherReports(self.__rNode)

            # update the GUI annotation name/label/color
            self.updateWidgets()

            # initialize the label used by the EditorWidget
            if self.__editorParameterNode:
                self.__editorParameterNode.SetParameter(
                    'label', str(self.__rNode.GetFindingLabel()))

    '''
  Load report and initialize GUI based on .xml report file content
  '''

    def onReportImport(self):

        print('onReportImport here!!!')
        # TODO
        #  -- popup file open dialog to choose the .xml AIM file
        #  -- warn the user if the selected report node is not empty
        #  -- populate the selected report node, initializing annotation template,
        #  content, markup hierarchy and content
        if not self.__importAIMFile:
            Helper.Debug('onReportImport: import file name not specified')
            return

        Helper.Debug('onReportImport')

        # For now, always create a new report node
        newReport = slicer.modulemrml.vtkMRMLReportingReportNode()

        # always use the default color map
        newReport.SetColorNodeID(self.__defaultColorNode.GetID())

        slicer.mrmlScene.AddNode(newReport)
        self.__reportSelector.setCurrentNode(newReport)
        self.onReportNodeChanged()

        # initialize the report hierarchy
        #  -- assume that report node has been created and is in the selector

        Helper.LoadAIMFile(newReport.GetID(), self.__importAIMFile)

        # update the GUI
        Helper.Debug('onReportImport --> calling onReportNodeChanged()')
        self.onReportNodeChanged()

    def onSelectAIMFile(self):
        #  -- popup file dialog prompting output file
        if not self.__importAIMFile:
            fileName = qt.QFileDialog.getOpenFileName(self.parent,
                                                      "Choose AIM report", "/",
                                                      "XML Files (*.xml)")
        else:
            lastDir = self.__importAIMFile[0:string.
                                           rfind(self.__importAIMFile, '/')]
            fileName = qt.QFileDialog.getOpenFileName(self.parent,
                                                      "Choose AIM report",
                                                      lastDir,
                                                      "XML Files (*.xml)")

        if fileName == '':
            return

        self.__importAIMFile = fileName
        try:
            label = string.split(fileName, '/')[-1]
        except:
            label = fileName
        self.__aimFilePicker.text = label

    '''
  Save report to an xml file
  '''

    def onReportExport(self):
        if self.__rNode == None:
            return

        Helper.Debug('onReportExport')

        exportDirectory = self.__exportFolderPicker.directory
        self.__rNode.SetStorageDirectoryName(exportDirectory)

        Helper.Debug('Will export to ' + exportDirectory)

        # use the currently selected report
        self.__rNode = self.__reportSelector.currentNode()
        if self.__rNode == None:
            return

        #  -- traverse markup hierarchy and translate
        retval = self.__logic.SaveReportToAIM(self.__rNode)
        if retval == EXIT_FAILURE:
            Helper.Error("Failed to save report to '" + exportDirectory + "'")
        else:
            Helper.Debug("Saved report to '" + exportDirectory + "'")

        # This code is commented out because repeated insertion into the database
        # leads to database lockout (illustrated in Testing/RepeatInsertTest.py).
        # For now, the solution will be to import the created DICOM objects
        # manually.
        # attempt to insert each of the saved items into the database
        #filesToInsert = glob.glob(exportDirectory+'/*')
        #for f in filesToInsert:
        #  Helper.Debug('Inserting '+f+' into DICOM database...')
        #  slicer.dicomDatabase.insert(f)
        #  Helper.Debug('Done')

    def updateWidgetFromParameters(self):
        pn = self.__parameterNode
        if pn == None:
            return
        reportID = pn.GetParameter('reportID')

        if reportID != None:
            self.__rNode = Helper.getNodeByID(reportID)
            # AF: looks like this does not trigger event, why?
            self.__reportSelector.setCurrentNode(self.__rNode)

    def updateParametersFromWidget(self):
        pn = self.__parameterNode
        if pn == None:
            return

        report = self.__reportSelector.currentNode()

        if report != None:
            pn.SetParameter('reportID', report.GetID())

    def updateWidgets(self):

        Helper.Debug("updateWidgets()")

        report = self.__rNode
        volume = None
        label = self.__segmentationSelector.currentNode()

        if report != None:
            self.__reportSelector.setCurrentNode(self.__rNode)
            volume = slicer.mrmlScene.GetNodeByID(report.GetVolumeNodeID())
            # TODO: get the label node from volume hieararchy

            if volume != None:
                self.__volumeSelector.setCurrentNode(volume)
                self.__markupFrame.enabled = 1
                self.__annotationsFrame.enabled = 1
                self.__volumeSelector.enabled = 0
            else:
                self.__volumeSelector.enabled = 1
                self.__markupFrame.enabled = 0
                self.__annotationsFrame.enabled = 0

        else:
            self.__volumeSelector.enabled = 0
            self.__markupFrame.enabled = 0
            self.__annotationsFrame.enabled = 0

        if not label:
            self.__editorWidget.editLabelMapsFrame.collapsed = True
            self.__editorWidget.editLabelMapsFrame.setEnabled(False)
        else:
            self.__editorWidget.editLabelMapsFrame.collapsed = False
            self.__editorWidget.editLabelMapsFrame.setEnabled(True)
class qSlicerReportingModuleWidget:
  def __init__( self, parent=None ):

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

    # Reference to the logic that Slicer instantiated
    self.__logic  = slicer.modules.reporting.logic()
    if not self.__logic:
      # create a new instance
      self.__logic = slicer.modulelogic.vtkSlicerReportingModuleLogic()

    # Get the location and initialize the DICOM DB
    settings = qt.QSettings()
    self.__dbFileName = settings.value("DatabaseDirectory","")
    if self.__dbFileName == "":
      Helper.Warning("DICOM Database is not accessible.")
    else:
      self.__dbFileName = self.__dbFileName+"/ctkDICOM.sql"

      if self.__logic.InitializeDICOMDatabase(self.__dbFileName):
        Helper.Info('DICOM database initialized correctly!')
      else:
        Helper.Error('Failed to initialize DICOM database at '+self.__dbFileName)

    if not self.__logic.GetMRMLScene():
      # set the logic's mrml scene
      self.__logic.SetMRMLScene(slicer.mrmlScene)

    # for export
    self.exportFileName = None
    self.exportFileDialog = None

    # initialize parameter node
    self.__parameterNode = None
    nNodes = slicer.mrmlScene.GetNumberOfNodesByClass('vtkMRMLScriptedModuleNode')
    for n in xrange(nNodes):
      compNode = slicer.mrmlScene.GetNthNodeByClass(n, 'vtkMRMLScriptedModuleNode')
      compNode.SetReferenceCount(compNode.GetReferenceCount() - 1)
      nodeid = None
      if compNode.GetModuleName() == 'Reporting':
        self.__parameterNode = compNode
        'Found existing Reporting parameter node'
        break
    if self.__parameterNode == None:
      self.__parameterNode = slicer.vtkMRMLScriptedModuleNode()
      self.__parameterNode.SetModuleName('Reporting')
      self.__parameterNode.SetSingletonTag('Reporting')
      slicer.mrmlScene.AddNode(self.__parameterNode)

      # keep active report and volume
      self.__rNode = None
      self.__vNode = None

    if self.__parameterNode != None:
      paramID = self.__parameterNode.GetID()
      self.__logic.SetActiveParameterNodeID(paramID)
    else:
      Helper.Error('Unable to set logic active parameter node')
    
    # TODO: figure out why module/class hierarchy is different
    # between developer builds ans packages
    try:
      # for developer build...
      self.editUtil = EditorLib.EditUtil.EditUtil()
    except AttributeError:
      # for release package...
      self.editUtil = EditorLib.EditUtil()

  def setup( self ):
    #
    # Input frame
    #
    self.__inputFrame = ctk.ctkCollapsibleButton()
    self.__inputFrame.text = "Input"
    self.__inputFrame.collapsed = 0
    inputFrameLayout = qt.QFormLayout(self.__inputFrame)
    
    self.layout.addWidget(self.__inputFrame)

    # Active report node
    label = qt.QLabel('Report: ')
    self.__reportSelector = slicer.qMRMLNodeComboBox()
    self.__reportSelector.nodeTypes =  ['vtkMRMLReportingReportNode']
    self.__reportSelector.setMRMLScene(slicer.mrmlScene)
    self.__reportSelector.addEnabled = 1
    self.__reportSelector.removeEnabled = 0
    
    inputFrameLayout.addRow(label, self.__reportSelector)

    self.__reportSelector.connect('mrmlSceneChanged(vtkMRMLScene*)', self.onMRMLSceneChanged)
    self.__reportSelector.connect('currentNodeChanged(vtkMRMLNode*)', self.onReportNodeChanged)
 
    # Volume being annotated (only one is allowed for the report)
    label = qt.QLabel('NOTE: Only volumes loaded from DICOM can be annotated!')
    inputFrameLayout.addRow(label)
    label = qt.QLabel('Annotated volume: ')
    self.__volumeSelector = slicer.qMRMLNodeComboBox()
    self.__volumeSelector.nodeTypes = ['vtkMRMLScalarVolumeNode']
    # only allow volumes with the attribute DICOM.instanceUIDs
    self.__volumeSelector.addAttribute('vtkMRMLScalarVolumeNode','DICOM.instanceUIDs')
    self.__volumeSelector.setMRMLScene(slicer.mrmlScene)
    self.__volumeSelector.addEnabled = False
    
    inputFrameLayout.addRow(label, self.__volumeSelector)

    self.__volumeSelector.connect('currentNodeChanged(vtkMRMLNode*)', self.onAnnotatedVolumeNodeChanged)
    self.__volumeSelector.connect('mrmlSceneChanged(vtkMRMLScene*)', self.onMRMLSceneChanged)

    #
    # Annotation frame -- vocabulary-based description of what is
    # being annotated/marked up in this report
    #
    self.__annotationsFrame = ctk.ctkCollapsibleButton()
    self.__annotationsFrame.text = "Annotation"
    self.__annotationsFrame.collapsed = 0
    annotationsFrameLayout = qt.QFormLayout(self.__annotationsFrame)
    
    self.layout.addWidget(self.__annotationsFrame)

    self.__defaultColorNode = self.__logic.GetDefaultColorNode()

    self.__toolsColor = EditColor(self.__annotationsFrame,colorNode=self.__defaultColorNode)

    #
    # Markup frame -- summary of all the markup elements contained in the
    # report
    #
    self.__markupFrame = ctk.ctkCollapsibleButton()
    self.__markupFrame.text = "Markup"
    self.__markupFrame.collapsed = 0
    markupFrameLayout = qt.QFormLayout(self.__markupFrame)
    
    self.layout.addWidget(self.__markupFrame)

    # Add a flag to switch between different tree view models
    self.__useNewTreeView = 1

    # Add the tree widget
    if self.__useNewTreeView == 1:
      self.__markupTreeView = slicer.modulewidget.qMRMLReportingTreeView()
      self.__markupTreeView.sceneModelType = "DisplayableHierarchy"
    else:
      self.__markupTreeView = slicer.qMRMLTreeView()
      self.__markupTreeView.sceneModelType = "Displayable"
    self.__markupTreeView.setMRMLScene(self.__logic.GetMRMLScene())
        
    self.__markupSliceText = qt.QLabel()
    markupFrameLayout.addRow(self.__markupSliceText)
    markupFrameLayout.addRow(self.__markupTreeView)

    # Editor frame
    self.__editorFrame = ctk.ctkCollapsibleButton()
    self.__editorFrame.text = 'Segmentation'
    self.__editorFrame.collapsed = 0
    editorFrameLayout = qt.QFormLayout(self.__editorFrame)

    label = qt.QLabel('Segmentation volume: ')
    self.__segmentationSelector = slicer.qMRMLNodeComboBox()
    self.__segmentationSelector.nodeTypes = ['vtkMRMLScalarVolumeNode']
    self.__segmentationSelector.setMRMLScene(slicer.mrmlScene)
    self.__segmentationSelector.addEnabled = 1
    self.__segmentationSelector.noneEnabled = 1
    self.__segmentationSelector.removeEnabled = 0
    self.__segmentationSelector.showHidden = 0
    self.__segmentationSelector.showChildNodeTypes = 0
    self.__segmentationSelector.selectNodeUponCreation = 1
    self.__segmentationSelector.addAttribute('vtkMRMLScalarVolumeNode','LabelMap',1)

    editorFrameLayout.addRow(label, self.__segmentationSelector)

    editorWidgetParent = slicer.qMRMLWidget()
    editorWidgetParent.setLayout(qt.QVBoxLayout())
    editorWidgetParent.setMRMLScene(slicer.mrmlScene)
    self.__editorWidget = EditorWidget(parent=editorWidgetParent,showVolumesFrame=False)
    self.__editorWidget.setup()
    self.__editorWidget.toolsColor.frame.setVisible(False)
    editorFrameLayout.addRow(editorWidgetParent)

    markupFrameLayout.addRow(self.__editorFrame)

    self.__segmentationSelector.connect('currentNodeChanged(vtkMRMLNode*)', self.onSegmentationNodeChanged)
    self.__segmentationSelector.connect('mrmlSceneChanged(vtkMRMLScene*)', self.onMRMLSceneChanged)

    # IO frame
    self.__ioFrame = ctk.ctkCollapsibleButton()
    self.__ioFrame.text = 'Import/Export'
    self.__ioFrame.collapsed = 1
    ioFrameLayout = qt.QGridLayout(self.__ioFrame)

    self.layout.addWidget(self.__ioFrame)

    # Buttons to save/load report using AIM XML serialization
    label = qt.QLabel('Export folder')
    self.__exportFolderPicker = ctk.ctkDirectoryButton()
    exportButton = qt.QPushButton('Export')
    exportButton.connect('clicked()', self.onReportExport)
    ioFrameLayout.addWidget(label,0,0)
    ioFrameLayout.addWidget(self.__exportFolderPicker,0,1)
    ioFrameLayout.addWidget(exportButton,0,2)

    label = qt.QLabel('AIM file to import')
    self.__aimFilePicker = qt.QPushButton('N/A')
    self.__aimFilePicker.connect('clicked()',self.onSelectAIMFile)
    button = qt.QPushButton('Import')
    button.connect('clicked()', self.onReportImport)
    ioFrameLayout.addWidget(label,1,0)
    ioFrameLayout.addWidget(self.__aimFilePicker,1,1)
    ioFrameLayout.addWidget(button,1,2)
    self.__importAIMFile = None

    self.__reportSelector.connect('currentNodeChanged(vtkMRMLNode*)', self.updateWidgets)
    self.__volumeSelector.connect('currentNodeChanged(vtkMRMLNode*)', self.updateWidgets)
    self.updateWidgets()

    self.layout.addStretch(1)

    self.__editorParameterNode = self.editUtil.getParameterNode()

    self.__editorParameterNode.AddObserver(vtk.vtkCommand.ModifiedEvent, self.onEditorParameterNodeChanged)

  def onEditorParameterNodeChanged(self,caller,event):
    print('Editor parameter node changed')
    label = self.__editorParameterNode.GetParameter('label')
    if self.__rNode:
      print("Updating report label")
      self.__rNode.SetFindingLabel(int(label))

  def enter(self):
    # switch to Two-over-Two layout
    lm = slicer.app.layoutManager()
    lm.setLayout(26) # two over two

    # update the logic to know that the module has been entered
    self.__logic.GUIHiddenOff()
    self.updateWidgetFromParameters()

    # respond to error events
    Helper.Info('Enter: Setting up connection to respond to logic error events')
    hasObserver = self.__logic.HasObserver(vtk.vtkCommand.ErrorEvent)
    if hasObserver == 0:
      tag = self.__logic.AddObserver(vtk.vtkCommand.ErrorEvent, self.respondToErrorMessage)
      # print '\tobserver tag = ',tag
    else:
      Helper.Debug('Logic already has an observer on the ErrorEvent')

    vnode = self.__volumeSelector.currentNode()
    if vnode != None:
      # print "Enter: setting active hierarchy from node ",vnode.GetID()
      # update the logic active markup
      self.__logic.SetActiveMarkupHierarchyIDFromNode(vnode)
      self.updateTreeView()

    self.__editorWidget.enter()


  def exit(self):
    self.updateParametersFromWidget()

    Helper.Debug("Reporting Exit. Letting logic know that module has been exited")
    # let the module logic know that the GUI is hidden, so that fiducials can go elsewehre
    self.__logic.GUIHiddenOn()
    # disconnect observation
    self.__logic.RemoveObservers(vtk.vtkCommand.ErrorEvent)

    self.__editorWidget.exit()

  # respond to error events from the logic
  def respondToErrorMessage(self, caller, event):
    errorMessage = self.__logic.GetErrorMessage()
    # inform user only if the message is not empty since vtkErrorMacro invokes this event as well
    if errorMessage != None:
      Helper.Debug('respondToErrorMessage, event = '+str(event)+', message =\n\t'+str(errorMessage))
      errorDialog = qt.QErrorMessage(self.parent)
      errorDialog.showMessage(errorMessage)

  def onMRMLSceneChanged(self, mrmlScene):
    if mrmlScene != self.__logic.GetMRMLScene():
      self.__logic.SetMRMLScene(mrmlScene)
      self.__logic.RegisterNodes()
    self.__reportSelector.setMRMLScene(slicer.mrmlScene)
    
  def updateTreeView(self):
    # make the tree view update
    if self.__useNewTreeView == 1:
      self.__markupTreeView.updateTreeView()
    else:
      self.__markupTreeView.sceneModelType = "Displayable"
      nodeTypes = ['vtkMRMLDisplayableHierarchyNode', 'vtkMRMLAnnotationHierarchyNode', 'vtkMRMLAnnotationNode', 'vtkMRMLVolumeNode', 'vtkMRMLReportingReportNode']
      self.__markupTreeView.nodeTypes = nodeTypes
      self.__markupTreeView.listenNodeModifiedEvent = 1      
      self.__markupTreeView.sceneModelType = "Displayable"
      # show these nodes even if they're hidden by being children of hidden hierarchy nodes
      showHiddenNodeTypes = ['vtkMRMLAnnotationNode', 'vtkMRMLVolumeNode', 'vtkMRMLDisplayableHierarchyNode'] 
      self.__markupTreeView.model().showHiddenForTypes = showHiddenNodeTypes
    # set the root to be the current report hierarchy root 
    if self.__rNode == None:
      Helper.Error("updateTreeView: report node is not initialized!")
      self.__markupTreeView.setRootNode(None)
      return
    else:
      # the tree root node has to be a hierarchy node, so get the associated hierarchy node for the active report node
      rootNode = slicer.vtkMRMLHierarchyNode().GetAssociatedHierarchyNode(self.__rNode.GetScene(), self.__rNode.GetID())
      if rootNode:
        self.__markupTreeView.setRootNode(rootNode)
        Helper.Debug("Setting tree view root to be " + rootNode.GetID())
        self.__markupTreeView.expandAll()
      else:
        Helper.Debug("Setting tree view root to be None")
        self.__markupTreeView.setRootNode(None)

  def onAnnotatedVolumeNodeChanged(self):
    Helper.Debug("onAnnotatedVolumeNodeChanged()")

    # get the current volume node
    selectedVolume = self.__volumeSelector.currentNode()

    # do the error checks
    if selectedVolume == None or self.__rNode == None:
      self.__volumeSelector.setCurrentNode(None)
      return

    uids = selectedVolume.GetAttribute('DICOM.instanceUIDs')
    if uids == None:
      Helper.ErrorPopup("Volume \""+selectedVolume.GetName()+"\" was not loaded from DICOM. Only volumes loaded from DICOM data can be annotated in the Reporting module.")
      self.__volumeSelector.setCurrentNode(None)
      return

    nSlices = selectedVolume.GetImageData().GetExtent()[-1]+1
    if nSlices != len(string.split(uids)):
      Helper.ErrorPopup("Volume \""+selectedVolume.GetName()+"\" was loaded from multi-frame DICOM. Multi-frame DICOM is currently not supported by the Reporting module")
      self.__volumeSelector.setCurrentNode(None)
      return

    # volume node is valid!
    self.__vNode = selectedVolume

    # update the report node
    if self.__rNode != None:
      self.__rNode.SetVolumeNodeID(self.__vNode.GetID())
      self.__rNode.SetName('Report for Volume '+self.__vNode.GetName())

    Helper.SetBgFgVolumes(self.__vNode.GetID(), '')
    Helper.RotateToVolumePlanes()

    # go over all label nodes in the scene
    # if there is a label that has the selected volume as associated node, 
    #   initialize label selector to show that label
    volumeNodes = slicer.mrmlScene.GetNodesByClass('vtkMRMLScalarVolumeNode')
    volumeNodes.SetReferenceCount(volumeNodes.GetReferenceCount()-1)
    associatedLabelFound = False
    for i in range(volumeNodes.GetNumberOfItems()):
      vol = volumeNodes.GetItemAsObject(i)
      associatedNodeID = vol.GetAttribute('AssociatedNodeID')
      label = vol.GetAttribute('LabelMap')
      if associatedNodeID == self.__vNode.GetID() and label == '1':
        Helper.SetLabelVolume(vol.GetID())
        associatedLabelFound = True

    # if there is no associated label node, set the selector to none
    if associatedLabelFound == False:
      Helper.SetLabelVolume("")

    orientation = Helper.GetScanOrderSliceName(self.__vNode)
    message = "Slice viewers to be used for markup: "
    for sliceViewer in orientation:
      message = message + sliceViewer
      if orientation.index(sliceViewer) < (len(orientation) - 1 ):
        message = message + ", "
    Helper.Debug(message)
    self.__markupSliceText.text = message

    # take the first one
    self.__parameterNode.SetParameter('acquisitionSliceViewer',orientation[0])

    # print "Calling logic to set up hierarchy"
    self.__logic.InitializeHierarchyForVolume(self.__vNode)
    self.updateTreeView()

  def onSegmentationNodeChanged(self):
    Helper.Debug('onSegmentationNodeChanged()')

    if self.__vNode == None:
      Helper.Error('Should not be possible to select segmentation unless annotated volume is initialized!')
      return

    # get the current segmentation (label) node
    sNode = self.__segmentationSelector.currentNode()
    if sNode == None:
      self.updateWidgets()
      return

    # if it's a new label, it should have/will be added to the report
    # automatically
    image = sNode.GetImageData()
    if image == None:
      Helper.initializeNewLabel(sNode, self.__vNode)
    else:
      # if it's an existing label, we need to check that the geometry matches
      # the annotated label geometry, and if so, add it to the hierarchy
      if Helper.GeometriesMatch(sNode, self.__vNode) == False:
        Helper.ErrorPopup('The geometry of the segmentation label you attempted to select does not match the geometry of the volume being annotated! Please select a different label or create a new one.')
        self.__segmentationSelector.setCurrentNode(None)
        self.updateWidgets()
        return

    # assign the color LUT we use
    dNode = sNode.GetDisplayNode()
    dNode.SetAndObserveColorNodeID(self.__defaultColorNode.GetID())

    sNode.SetAttribute('AssociatedNodeID',self.__vNode.GetID())
    self.__logic.AddNodeToReport(sNode)

    # assign the volume and the selected color to the editor parameter node
    Helper.SetLabelVolume(sNode.GetID())

    # TODO: disable adding new label node to the hierarchy if it was added
    # outside the reporting module

    self.__segmentationSelector.setCurrentNode(sNode)

    self.__editorWidget.setMasterNode(self.__vNode)
    self.__editorWidget.setMergeNode(sNode)

    self.__editorParameterNode.Modified()

    self.updateWidgets()
  
  def onReportNodeChanged(self):
    Helper.Debug("onReportNodeChanged()")

    # cancel the active effect in Editor
    if self.__editorWidget:
      self.__editorWidget.toolsBox.defaultEffect()
    # TODO
    #  -- initialize annotations and markup frames based on the report node
    #  content
    self.__rNode = self.__reportSelector.currentNode()
      
    self.__segmentationSelector.setCurrentNode(None)
    # disable editor frame
    self.onSegmentationNodeChanged()

    if self.__rNode != None:
    
      Helper.Debug("Selected report has changed to " + self.__rNode.GetID())

      if self.__rNode.GetDICOMDatabaseFileName() == "":
        self.__rNode.SetDICOMDatabaseFileName(self.__dbFileName)

      self.__parameterNode.SetParameter('reportID', self.__rNode.GetID())

      # setup the default color node, if not initialized
      if self.__rNode.GetColorNodeID() == "":
        self.__rNode.SetColorNodeID(self.__defaultColorNode.GetID())
        Helper.Debug('Set color node id to '+self.__defaultColorNode.GetID())
      else:
        Helper.Debug('Color node has already been set to '+self.__rNode.GetColorNodeID())

      self.__logic.InitializeHierarchyForReport(self.__rNode)
      self.updateTreeView()
      vID = self.__rNode.GetVolumeNodeID()
      if vID:
        Helper.Debug('Have a volume node id in the report ' + vID + ', setting current volume node selector')
        self.__vNode = slicer.mrmlScene.GetNodeByID(vID)      
        self.__volumeSelector.setCurrentNode(self.__vNode)
      else:
        Helper.Debug('Do not have a volume id in the report, setting current volume node selector to none')
        # set the volume to be none
        self.__vNode = None
        self.__volumeSelector.setCurrentNode(None)

      # hide the markups that go with other report nodes
      self.__logic.HideAnnotationsForOtherReports(self.__rNode)

      # update the GUI annotation name/label/color
      self.updateWidgets()

      # initialize the label used by the EditorWidget
      if self.__editorParameterNode:
        self.__editorParameterNode.SetParameter('label',str(self.__rNode.GetFindingLabel()))

  '''
  Load report and initialize GUI based on .xml report file content
  '''
  def onReportImport(self):

    print('onReportImport here!!!')
    # TODO
    #  -- popup file open dialog to choose the .xml AIM file
    #  -- warn the user if the selected report node is not empty
    #  -- populate the selected report node, initializing annotation template,
    #  content, markup hierarchy and content
    if not self.__importAIMFile:
      Helper.Debug('onReportImport: import file name not specified')
      return

    Helper.Debug('onReportImport')    

    # For now, always create a new report node
    newReport = slicer.modulemrml.vtkMRMLReportingReportNode()

    # always use the default color map
    newReport.SetColorNodeID(self.__defaultColorNode.GetID())

    slicer.mrmlScene.AddNode(newReport)
    self.__reportSelector.setCurrentNode(newReport)
    self.onReportNodeChanged()

    # initialize the report hierarchy
    #  -- assume that report node has been created and is in the selector

    Helper.LoadAIMFile(newReport.GetID(),self.__importAIMFile)

    # update the GUI
    Helper.Debug('onReportImport --> calling onReportNodeChanged()')
    self.onReportNodeChanged()
    
  def onSelectAIMFile(self):
    #  -- popup file dialog prompting output file
    if not self.__importAIMFile:
      fileName = qt.QFileDialog.getOpenFileName(self.parent, "Choose AIM report","/","XML Files (*.xml)")
    else:
      lastDir = self.__importAIMFile[0:string.rfind(self.__importAIMFile,'/')]
      fileName = qt.QFileDialog.getOpenFileName(self.parent, "Choose AIM report",lastDir,"XML Files (*.xml)")

    if fileName == '':
      return
    
    self.__importAIMFile = fileName
    try:
      label = string.split(fileName,'/')[-1]
    except:
      label = fileName
    self.__aimFilePicker.text = label

  '''
  Save report to an xml file
  '''
  def onReportExport(self):
    if self.__rNode == None:
      return

    Helper.Debug('onReportExport')
    
    exportDirectory = self.__exportFolderPicker.directory
    self.__rNode.SetStorageDirectoryName(exportDirectory)

    Helper.Debug('Will export to '+exportDirectory)

    # use the currently selected report
    self.__rNode = self.__reportSelector.currentNode()
    if self.__rNode == None:
      return

    #  -- traverse markup hierarchy and translate
    retval = self.__logic.SaveReportToAIM(self.__rNode)
    if retval == EXIT_FAILURE:
      Helper.Error("Failed to save report to '"+exportDirectory+"'")
    else:
      Helper.Debug("Saved report to '"+exportDirectory+"'")

    # This code is commented out because repeated insertion into the database
    # leads to database lockout (illustrated in Testing/RepeatInsertTest.py).
    # For now, the solution will be to import the created DICOM objects
    # manually.
    # attempt to insert each of the saved items into the database
    #filesToInsert = glob.glob(exportDirectory+'/*')
    #for f in filesToInsert:
    #  Helper.Debug('Inserting '+f+' into DICOM database...')
    #  slicer.dicomDatabase.insert(f)
    #  Helper.Debug('Done')

  def updateWidgetFromParameters(self):
    pn = self.__parameterNode
    if pn == None:
      return
    reportID = pn.GetParameter('reportID')

    if reportID != None:
      self.__rNode = Helper.getNodeByID(reportID)
      # AF: looks like this does not trigger event, why?
      self.__reportSelector.setCurrentNode(self.__rNode)

  def updateParametersFromWidget(self):
    pn = self.__parameterNode
    if pn == None:
      return

    report = self.__reportSelector.currentNode()
  
    if report != None:
      pn.SetParameter('reportID', report.GetID())

  def updateWidgets(self):

    Helper.Debug("updateWidgets()")

    report = self.__rNode
    volume = None
    label = self.__segmentationSelector.currentNode()

    if report != None:
      self.__reportSelector.setCurrentNode(self.__rNode)
      volume = slicer.mrmlScene.GetNodeByID(report.GetVolumeNodeID())
      # TODO: get the label node from volume hieararchy

      if volume != None:
        self.__volumeSelector.setCurrentNode(volume)
        self.__markupFrame.enabled = 1
        self.__annotationsFrame.enabled = 1
        self.__volumeSelector.enabled = 0
      else:
        self.__volumeSelector.enabled = 1
        self.__markupFrame.enabled = 0
        self.__annotationsFrame.enabled = 0

    else:
      self.__volumeSelector.enabled = 0
      self.__markupFrame.enabled = 0
      self.__annotationsFrame.enabled = 0
      
    if not label:
      self.__editorWidget.editLabelMapsFrame.collapsed = True
      self.__editorWidget.editLabelMapsFrame.setEnabled(False)
    else:      
      self.__editorWidget.editLabelMapsFrame.collapsed = False
      self.__editorWidget.editLabelMapsFrame.setEnabled(True)
Exemple #28
0
class VisAIReWidget:
  def __init__(self, parent = None):
    if not parent:
      self.parent = slicer.qMRMLWidget()
      self.parent.setLayout(qt.QVBoxLayout())
      self.parent.setMRMLScene(slicer.mrmlScene)
    else:
      self.parent = parent
    self.layout = self.parent.layout()
    if not parent:
      self.setup()
      self.parent.show()

    # TODO: figure out why module/class hierarchy is different
    # between developer builds ans packages
    try:
      # for developer build...
      self.editUtil = EditorLib.EditUtil.EditUtil()
    except AttributeError:
      # for release package...
      self.editUtil = EditorLib.EditUtil()

  def setup(self):
    self.viewMode = 'compare'
    self.compare0 = None
    self.compare1 = None
    self.sidebyside0 = None
    self.sidebyside1 = None

    # Instantiate and connect widgets ...

    # reload button
    # (use this during development, but remove it when delivering
    #  your module to users)
    self.reloadButton = qt.QPushButton("Reload")
    self.reloadButton.toolTip = "Reload this module."
    self.reloadButton.name = "VisAIRe Reload"
    self.layout.addWidget(self.reloadButton)
    self.reloadButton.connect('clicked()', self.onReload)

    # reload and test button
    # (use this during development, but remove it when delivering
    #  your module to users)
    #self.reloadAndTestButton = qt.QPushButton("Reload and Test")
    #self.reloadAndTestButton.toolTip = "Reload this module and then run the self tests."
    #self.layout.addWidget(self.reloadAndTestButton)
    #self.reloadAndTestButton.connect('clicked()', self.onReloadAndTest)

    # entry for the rater name
    label = qt.QLabel('Rater name:')
    self.raterName = qt.QLineEdit()
    self.layout.addWidget(label)
    self.layout.addWidget(self.raterName)

    # Configuration file picker
    label = qt.QLabel('Configuration file:')
    self.configFilePicker = qt.QPushButton('N/A')
    self.configFilePicker.connect('clicked()',self.onConfigFileSelected)
    self.layout.addWidget(label)
    self.layout.addWidget(self.configFilePicker)

    self.makeSnapshots = qt.QPushButton('Make snapshots')
    self.layout.addWidget(self.makeSnapshots)
    self.makeSnapshots.connect('clicked()', self.onMakeSnapshots)

    # Opacity control
    label = qt.QLabel('Foreground/Background opacity:')
    self.opacitySlider = ctk.ctkSliderWidget()
    self.opacitySlider.connect('valueChanged(double)',self.onOpacityChangeRequested)
    self.opacitySlider.minimum = 0.
    self.opacitySlider.maximum = 1.
    self.opacitySlider.decimals = 1
    self.opacitySlider.singleStep = 0.1
    self.layout.addWidget(label)
    self.layout.addWidget(self.opacitySlider)

    #  Button to switch between showing background/foreground volumes
    self.bgfgButton = qt.QPushButton("Switch Background/Foreground")
    self.layout.addWidget(self.bgfgButton)
    self.bgfgButton.connect('clicked()', self.onbgfgButtonPressed)

    # Select between compare view and editing layouts
    groupLabel = qt.QLabel('Review mode:')
    self.viewGroup = qt.QButtonGroup()
    self.compareSelector = qt.QRadioButton('Compare view')
    self.sideBySideSelector = qt.QRadioButton('Side by side')
    self.compareSelector.setChecked(1)
    self.viewGroup.addButton(self.compareSelector,1)
    self.viewGroup.addButton(self.sideBySideSelector,2)
    self.groupWidget = qt.QWidget()
    self.groupLayout = qt.QFormLayout(self.groupWidget)
    self.groupLayout.addRow(self.compareSelector, self.sideBySideSelector)
    self.layout.addWidget(self.groupWidget)
    # step4Layout.addRow(groupLabel, self.viewGroup)

    self.viewGroup.connect('buttonClicked(int)', self.onViewUpdateRequested)

    # setup Editor widget
    editorWidgetParent = slicer.qMRMLWidget()
    editorWidgetParent.setLayout(qt.QVBoxLayout())
    editorWidgetParent.setMRMLScene(slicer.mrmlScene)
    self.editorWidget = EditorWidget(parent=editorWidgetParent,showVolumesFrame=False)
    self.editorWidget.setup()
    self.editorParameterNode = self.editUtil.getParameterNode()
    self.layout.addWidget(editorWidgetParent)

    # Slice control
    #label = qt.QLabel('Slice selector:')
    #self.sliceSlider = ctk.ctkSliderWidget()
    #self.sliceSlider.connect('valueChanged(double)',self.onSliceChangeRequested)
    #self.sliceSlider.minimum = 0.
    #self.sliceSlider.maximum = 1.
    #self.sliceSlider.decimals = 1
    #self.sliceSlider.singleStep = 0.1
    #self.layout.addWidget(label)
    #self.layout.addWidget(self.opacitySlider)

    # Collapsible button to keep the content of the form
    self.evaluationFrame = ctk.ctkCollapsibleButton()
    self.evaluationFrame.text = "Assessment Form"
    self.evaluationFrame.collapsed = 0
    self.evaluationFrameLayout = qt.QFormLayout(self.evaluationFrame)
    self.layout.addWidget(self.evaluationFrame)

    self.formEntries = []
    self.questions = {'Improved compared to non-registered?':'binary','Diagnostic quality?':'binary','Error quantification (if available)':'numeric'}
    self.formEntryMapper = qt.QSignalMapper()
    self.formEntryMapper.connect('mapped(const QString&)', self.entrySelected)

    self.maxFormEntries = 30
    for i in range(self.maxFormEntries):
    # populate the assessment form
      # create a new sub-frame with the questions
      cb = ctk.ctkCollapsibleButton()
      cb.visible = False
      cb.collapsed = True
      self.formEntries.append(cb)
      self.formEntryMapper.setMapping(cb, str(i))
      cb.connect('contentsCollapsed(bool)', self.formEntryMapper, 'map()')

      layout = qt.QFormLayout(cb)
      self.evaluationFrameLayout.addRow(cb)

      for (q,c) in self.questions.items():
        if c == 'binary':
          self.addBinaryEntry(q, layout)
        elif c == 'numeric':
          self.addNumericEntry(q, layout)


    # Save button
    self.doneButton = qt.QPushButton("Save")
    self.doneButton.toolTip = "Click this when done."
    self.layout.addWidget(self.doneButton)
    self.doneButton.connect('clicked(bool)', self.onDoneButtonClicked)

    # Add vertical spacer
    self.layout.addStretch(1)

    # Initialize internal persistent variables
    self.configFile = None
    self.movingVolume = None
    self.perVolumeForms = []
    self.fixedVolumes = []
    self.registeredVolumes = []
    self.transforms = []
    self.caseName = None


    # add custom layout for comparing two pairs of volumes
    compareViewTwoRows ="<layout type=\"vertical\">"
    for i in range(2):
      compareViewTwoRows = compareViewTwoRows+"   <item>\
    <view class=\"vtkMRMLSliceNode\" singletontag=\"Compare"+str(i)+"\">\
    <property name=\"orientation\" action=\"default\">Axial</property>\
    <property name=\"viewlabel\" action=\"default\">"+str(i)+"</property>\
    <property name=\"viewcolor\" action=\"default\">#E17012</property>\
    <property name=\"lightboxrows\" action=\"default\">1</property>\
    <property name=\"lightboxcolumns\" action=\"default\">6</property>\
    <property name=\"lightboxrows\" action=\"relayout\">1</property>\
    <property name=\"lightboxcolumns\" action=\"relayout\">6</property>\
    </view>\
    </item>"
    compareViewTwoRows = compareViewTwoRows+"</layout>"

    sideBySide = "<layout type=\"horizontal\">\
     <item>\
      <view class=\"vtkMRMLSliceNode\" singletontag=\"SideBySide0\">\
       <property name=\"orientation\" action=\"default\">Axial</property>\
       <property name=\"viewlabel\" action=\"default\">Moving</property>\
       <property name=\"viewcolor\" action=\"default\">#F34A33</property>\
      </view>\
     </item>\
     <item>\
      <view class=\"vtkMRMLSliceNode\" singletontag=\"SideBySide1\">\
       <property name=\"orientation\" action=\"default\">Axial</property>\
       <property name=\"viewlabel\" action=\"default\">Reference</property>\
       <property name=\"viewcolor\" action=\"default\">#EDD54C</property>\
      </view>\
     </item>\
    </layout>"
    print(sideBySide)

    layoutNodes = slicer.mrmlScene.GetNodesByClass('vtkMRMLLayoutNode')
    layoutNodes.SetReferenceCount(layoutNodes.GetReferenceCount()-1)
    self.layoutNode = layoutNodes.GetItemAsObject(0)
    self.CompareLayout = 123
    self.ContouringLayout = 124
    self.layoutNode.AddLayoutDescription(self.CompareLayout,compareViewTwoRows)
    self.layoutNode.AddLayoutDescription(self.ContouringLayout,sideBySide)
    self.layoutNode.SetViewArrangement(self.ContouringLayout)
    self.layoutNode.SetViewArrangement(self.CompareLayout)
    sliceCompositeNodes = slicer.mrmlScene.GetNodesByClass('vtkMRMLSliceCompositeNode')
    sliceCompositeNodes.SetReferenceCount(sliceCompositeNodes.GetReferenceCount()-1)
    sliceNodes = slicer.mrmlScene.GetNodesByClass('vtkMRMLSliceNode')
    sliceNodes.SetReferenceCount(sliceNodes.GetReferenceCount()-1)
    for i in range(sliceCompositeNodes.GetNumberOfItems()):
      scn = sliceCompositeNodes.GetItemAsObject(i)
      sn = sliceNodes.GetItemAsObject(i)
      sn.SetUseLabelOutline(1)
      if sn.GetName() == 'Compare0':
        self.compare0 = scn
      if sn.GetName() == 'Compare1':
        self.compare1 = scn
      if sn.GetName() == 'SideBySide0':
        self.sidebyside0 = scn
      if sn.GetName() == 'SideBySide1':
        self.sidebyside1 = scn

  def compositeNodeForWidget(self,name):
    sliceCompositeNodes = slicer.mrmlScene.GetNodesByClass('vtkMRMLSliceCompositeNode')
    sliceCompositeNodes.SetReferenceCount(sliceCompositeNodes.GetReferenceCount()-1)
    sliceNodes = slicer.mrmlScene.GetNodesByClass('vtkMRMLSliceNode')
    sliceNodes.SetReferenceCount(sliceNodes.GetReferenceCount()-1)
    for i in range(sliceCompositeNodes.GetNumberOfItems()):
      scn = sliceCompositeNodes.GetItemAsObject(i)
      sn = sliceNodes.GetItemAsObject(i)
      sn.SetUseLabelOutline(1)
      if sn.GetName() == name:
        return scn
    return None

  def onViewUpdateRequested(self,id):
    if id == 1:
      self.viewMode = 'compare'
    if id == 2:
      self.viewMode = 'sidebyside'
    self.entrySelected('0')

  def onOpacityChangeRequested(self,value):
    if self.viewMode == 'compare':
      viewer0 = self.compare0
      viewer1 = self.compare1
    else:
      viewer0 = self.sidebyside0
      viewer1 = self.sidebyside1

    if viewer0:
      viewer0.SetForegroundOpacity(value)
    if viewer1:
      viewer1.SetForegroundOpacity(value)

  def onbgfgButtonPressed(self):
    if self.viewMode == 'compare':
      viewer0 = self.compare0
      viewer1 = self.compare1
    else:
      viewer0 = self.sidebyside0
      viewer1 = self.sidebyside1

    if viewer0.GetForegroundOpacity() == 1:
      viewer0.SetForegroundOpacity(0)
      viewer1.SetForegroundOpacity(0)
    else:
      viewer0.SetForegroundOpacity(1)
      viewer1.SetForegroundOpacity(1)

  def onMakeSnapshots(self):
    for key in range(len(self.transforms)):
      print('Key :'+str(key))
      if not self.transforms[key]:
        continue
      self.makeSnapshotsForKey(key)

  def makeSnapshotsForKey(self,name,snapshots=True):
      movingID = self.movingVolume.GetID()
      registeredID = self.registeredVolumes[int(name)].GetID()
      fixedID = self.fixedVolumes[int(name)].GetID()

      snapshotsDir = '/Users/fedorov/Temp/RegistrationSnapshots'
      # assume this is full path, and the file name has the format
      #  <CaseID>_<junk>
      caseId = os.path.split(self.configFileName)[-1].split('_')[0]

      redSliceCompositeNode = self.compositeNodeForWidget('Red')

      redSliceCompositeNode.SetForegroundOpacity(0)

      self.setupLightbox(fixedID,movingID)
      if snapshots:
        snapshotName = os.path.join(snapshotsDir,caseId+'_'+str(name)+'_fixed.png')
        self.makeSnapshot('Red',snapshotName)

      self.setupLightbox(registeredID,movingID)
      if snapshots:
        snapshotName = os.path.join(snapshotsDir,caseId+'_'+str(name)+'_registered.png')
        self.makeSnapshot('Red',snapshotName)

      # make snapshots of the moving image for the first one
      # (same for all keys)
      if str(name) == '0':
        redSliceCompositeNode.SetForegroundOpacity(1)
        if snapshots:
          snapshotName = os.path.join(snapshotsDir,caseId+'_moving.png')
          self.makeSnapshot('Red',snapshotName)

  def makeSnapshot(self, widgetName, snapshotName):
      w = slicer.app.layoutManager().sliceWidget(widgetName)
      if w:
        qt.QPixmap().grabWidget(w).toImage().save(snapshotName)

  def setupSliceWidget(self,swName):
      w = slicer.app.layoutManager().sliceWidget(swName)
      w.fitSliceToBackground()
      sn = self.compositeNodeForWidget(swName)
      sn.SetForegroundOpacity(0)
      n = w.sliceLogic().GetSliceNode()
      fov = n.GetFieldOfView()
      n.SetFieldOfView(fov[0]/2.,fov[1]/2.,fov[2]/2.)

  def entrySelected(self, name):

    # prepare fixed volume label, if it is not available
    if self.movingVolumeSeg and not self.fixedVolumesSegmentations[int(name)] and self.transforms[int(name)]:
      tfm = self.transforms[int(name)]
      print('Resampled segmentation is missing, but will resample with '+tfm.GetID())

      resample = slicer.modules.brainsresample
      volumesLogic = slicer.modules.volumes.logic()
      labelName = self.fixedVolumes[int(name)].GetName()+'-label'
      self.fixedVolumesSegmentations[int(name)] = volumesLogic.CreateAndAddLabelVolume(slicer.mrmlScene, self.fixedVolumes[int(name)], labelName)
      parameters = {}
      parameters['inputVolume'] = self.movingVolumeSeg.GetID()
      parameters['referenceVolume'] = self.fixedVolumes[int(name)].GetID()
      parameters['warpTransform'] = self.transforms[int(name)].GetID()
      parameters['outputVolume'] = self.fixedVolumesSegmentations[int(name)]
      parameters['pixelType'] = 'short'
      parameters['interpolationMode'] = 'NearestNeighbor'
      slicer.cli.run(resample, None, parameters, wait_for_completion = True)

      # initialize the file name for the segmentation
      storageNode = self.fixedVolumesSegmentations[int(name)].GetStorageNode()
      fixedVolumeIdStr = str(self.fixedVolumeIds[int(name)])
      segFileName = os.path.join(os.path.split(self.config.get('MovingData','Segmentation'))[0],fixedVolumeIdStr+'-label.nrrd')
      storageNode.SetFileName(segFileName)
      storageNode.SetWriteFileFormat('.nrrd')

      # update the config file to keep reference to the newly created
      # segmentation label
      self.config.set('FixedData','Segmentation'+fixedVolumeIdStr,segFileName)

      # setup the Editor
      self.editorWidget.setMasterNode(self.fixedVolumes[int(name)])
      self.editorWidget.setMergeNode(self.fixedVolumesSegmentations[int(name)])
      self.editorParameterNode.Modified()

    if self.viewMode == 'compare':
      self.layoutNode.SetViewArrangement(self.CompareLayout)
      viewer0 = self.compare0
      viewer1 = self.compare1
    else:
      self.layoutNode.SetViewArrangement(self.ContouringLayout)
      viewer0 = self.sidebyside0
      viewer1 = self.sidebyside1

    entry = self.formEntries[int(name)]
    if entry.collapsed == True:
      return

    print 'Entry selected: ',name
    for i in range(len(self.fixedVolumes)):
      #self.formEntries[i].blockSignals(True)
      if i == int(name):
        self.formEntries[i].collapsed = False
        continue
      else:
        self.formEntries[i].collapsed = True
      #self.formEntries[i].blockSignals(False)
    viewer0.SetLinkedControl(False)
    viewer1.SetLinkedControl(False)

    v0fgID = self.movingVolume.GetID()
    v1fgID = self.registeredVolumes[int(name)].GetID()
    bgID = self.fixedVolumes[int(name)].GetID()
    print('Will be setting ids: '+v0fgID+','+v1fgID+','+bgID)

    viewer0.SetForegroundVolumeID(v0fgID)
    if self.movingVolumeSeg:
      viewer0.SetLabelVolumeID(self.movingVolumeSeg.GetID())

    viewer1.SetForegroundVolumeID(v1fgID)
    # if segmentation is available for the registered node, display it
    if self.fixedVolumesSegmentations[int(name)]:
      viewer1.SetLabelVolumeID(self.fixedVolumesSegmentations[int(name)].GetID())
    # otherwise, if the transform is available, resample the moving volume
    # segmentation, populate the entry in the list of segmentations and
    # initialize the view


    viewer0.SetLinkedControl(True)
    viewer1.SetLinkedControl(True)
    viewer0.SetBackgroundVolumeID(bgID)
    viewer1.SetBackgroundVolumeID(bgID)

  def setupLightbox(self,fixedID,movingID):
    lm = slicer.app.layoutManager()
    lm.setLayout(6) # Red
    w = lm.sliceWidget('Red')
    cn = self.compositeNodeForWidget('Red')
    cn.SetForegroundVolumeID(movingID)
    cn.SetBackgroundVolumeID(fixedID)
    slicer.app.processEvents()
    sc = w.sliceController()
    sc.setLightbox(3,6)
    w.fitSliceToBackground()
    slider = sc.children()[1].children()[-1]
    n = w.sliceLogic().GetSliceNode()
    fov = n.GetFieldOfView()
    # zoom into the prostate region
    n.SetFieldOfView(fov[0]/2.5,fov[1]/2.5,fov[2])
    sc.setSliceOffsetValue(slider.minimum)

  def initializeViews(self, name):
    if self.viewMode == 'compare':
      self.layoutNode.SetViewArrangement(self.CompareLayout)
      viewer0 = self.compare0
      viewer1 = self.compare1
    else:
      self.layoutNode.SetViewArrangement(self.ContouringLayout)
      viewer0 = self.sidebyside0
      viewer1 = self.sidebyside1

    viewer0.SetLinkedControl(False)
    viewer1.SetLinkedControl(False)

    v0fgID = self.movingVolume.GetID()
    v1fgID = self.registeredVolumes[int(name)].GetID()
    bgID = self.fixedVolumes[int(name)].GetID()
    print('Will be setting ids: '+v0fgID+','+v1fgID+','+bgID)

    viewer0.SetForegroundVolumeID(v0fgID)
    if self.movingVolumeSeg:
      viewer0.SetLabelVolumeID(self.movingVolumeSeg.GetID())

    viewer1.SetForegroundVolumeID(v1fgID)
    # if segmentation is available for the registered node, display it
    if self.fixedVolumesSegmentations[int(name)]:
      viewer1.SetLabelVolumeID(self.fixedVolumesSegmentations[int(name)].GetID())
    # otherwise, if the transform is available, resample the moving volume
    # segmentation, populate the entry in the list of segmentations and
    # initialize the view


    viewer0.SetLinkedControl(True)
    viewer1.SetLinkedControl(True)
    viewer0.SetBackgroundVolumeID(bgID)
    viewer1.SetBackgroundVolumeID(bgID)


  def onConfigFileSelected(self):
    if not self.configFile:
      fileName = qt.QFileDialog.getOpenFileName(self.parent, "Choose assessment for configuration file","/","Conf Files (*.ini)")
    else:
      lastDir = self.configFile[0:string.rfind(self.configFile,'/')]
      fileName = qt.QFileDialog.getOpenFileName(self.parent, "Choose assessment for configuration file",lastDir,"Conf Files (*.ini)")

    if fileName == '':
      return

    self.configFile = fileName
    try:
      label = string.split(fileName,'/')[-1]
    except:
      label = fileName
    self.configFilePicker.text = label

    self.initFromFile(fileName)

  def initFromFile(self, fileName):
    # parse config file and load all of the volumes referenced
    slicer.mrmlScene.Clear(0)
    self.clearForm()
    self.fixedVolumes = []
    self.fixedVolumeIds = []
    self.registeredVolumes = []
    self.movingVolume = None
    self.movingVolumeSeg = None

    self.config = config.SafeConfigParser()
    cf = self.config
    cf.optionxform = str
    cf.read(fileName)
    self.configFileName = fileName

    assert cf.has_section('Info')
    assert cf.has_section('MovingData')
    assert cf.has_section('FixedData')
    assert cf.has_section('RegisteredData')

    # there should only be one moving image
    self.movingVolume = slicer.util.loadVolume(cf.get('MovingData','Image'),returnNode=True)[1]
    dn = self.movingVolume.GetDisplayNode()
    mwl = [dn.GetWindow(), dn.GetLevel()]

    # (optional) segmentation of the moving image
    print('Set moving volume seg')
    try:
      self.movingVolumeSeg = slicer.util.loadLabelVolume(cf.get('MovingData','Segmentation'),{},returnNode=True)[1]
      self.movingVolumeSeg.SetAttribute('LabelMap','1')
      self.movingVolumeSeg.GetDisplayNode().SetAndObserveColorNodeID('vtkMRMLColorTableNodeFileGenericAnatomyColors.txt')
      print('Setup color node: '+self.movingVolumeSeg.GetDisplayNode().GetColorNodeID())
    except:
      print(' ... to None')
      self.movingVolumeSeg = None

    # fixedVolumes: Slicer volume nodes corresponding to fixed images from the
    #   config file
    # fixedVolumeIds: Each volume appears as "Image<id>" in the config file;
    #   this list stores the ids assigned to the volumes
    # registeredVolumes: results of registration
    # transforms: transformations mapping moving volume to the corresponding
    #   fixed volume
    # fixedVolumesSegmentations: masks of a structure contoured in each of the
    #   fixed volumes
    # movingFiducials: fiducial points corresponding to image landmarks
    # fixedFiducials: fiducial points corresponding to the same landmarks in
    #   the fixed images

    # and an arbitrary number of fixed images
    fixedImageFiles = cf.options('FixedData')
    print(str(fixedImageFiles))
    for fi in fixedImageFiles:
      if re.match('Image\d+',fi):
        self.fixedVolumes.append(slicer.util.loadVolume(cf.get('FixedData',fi),returnNode=True)[1])
        fixedDisplNode = self.fixedVolumes[-1].GetDisplayNode()
        fixedDisplNode.SetAutoWindowLevel(0)
        fixedDisplNode.SetWindow(mwl[0])
        fixedDisplNode.SetLevel(mwl[1])
        self.fixedVolumeIds.append(fi.split('Image')[1])
    print('Fixed volumes: '+str(self.fixedVolumes))

    # (optional) segmentations of the structure in the fixed images
    self.registeredVolumes = [None] * len(self.fixedVolumes)
    self.fixedVolumesSegmentations = [None] * len(self.fixedVolumes)
    self.transforms = [None] * len(self.fixedVolumes)
    for fvId in range(len(self.fixedVolumes)):
      imageId = 'Image'+self.fixedVolumeIds[fvId]
      segId = 'Segmentation'+self.fixedVolumeIds[fvId]
      tfmId = 'Transform'+self.fixedVolumeIds[fvId]
      try:
        self.registeredVolumes[fvId] = slicer.util.loadVolume(cf.get('RegisteredData',imageId),{},returnNode=True)[1]
        registeredDisplNode = self.registeredVolumes[fvId].GetDisplayNode()
        registeredDisplNode.SetAutoWindowLevel(0)
        registeredDisplNode.SetWindow(mwl[0])
        registeredDisplNode.SetLevel(mwl[1])
      except:
        print('Failed to read RegisteredData/'+imageId)
        pass
      try:
        self.fixedVolumesSegmentations[fvId] = slicer.util.loadLabelVolume(cf.get('FixedData',segId),{},returnNode=True)[1]
      except:
        print('Failed to read FixedData/'+segId)
        pass
      #try:
      self.transforms[fvId] = slicer.util.loadTransform(cf.get('RegisteredData',tfmId),returnNode=True)[1]
      #except:
      #  print('Failed to read RegisteredData/'+tfmId)
      #  pass

    print('Number of fixed images: '+str(self.registeredVolumes))
    print('Number of transformations: '+str(self.transforms))
    print('Number of fixed image segmentations: '+str(self.fixedVolumesSegmentations))

    assert len(self.fixedVolumes) == len(self.registeredVolumes)

    self.caseName = cf.get('Info','CaseName')
    self.evaluationFrame.text = "Assessment Form for "+self.caseName

    # populate the assessment form
    for fv in range(len(self.fixedVolumes)):
      self.formEntries[fv].visible = True
      self.formEntries[fv].text = self.fixedVolumes[fv].GetName()

    # self.entrySelected('0')

  def clearForm(self):
    for i in range(self.maxFormEntries):
      self.formEntries[i].visible = False

  def onDoneButtonClicked(self):
    # save the config file
    self.config.write(open(self.configFileName,'w'))

    return

    path = self.configFile[0:string.rfind(self.configFile,'/')]
    reportName = path+'/'+self.caseName+'-'+self.raterName.text+'-report.log'
    report = open(reportName,'w')
    report.write(self.configFile+'\n')
    for i in range(len(self.fixedVolumes)):
      report.write(self.fixedVolumes[i].GetName()+';')
      item = 2
      print 'num children: ',len(self.formEntries[i].children())
      for (q,c) in self.questions.items():
        report.write(q+';')
        widget = self.formEntries[i].children()[item]
        print widget
        if c == 'binary':
          checked = str(int(widget.checked))
          report.write(str(checked)+';')
        elif c == 'numeric':
          error = str(widget.text)
          report.write(error+';')
        item = item+2
      report.write('\n')
    report.close()

  def addBinaryEntry(self,question,layout):
    self.questions[question] = 'binary'
    label = qt.QLabel(question)
    item = qt.QCheckBox()
    layout.addRow(label,item)
    #self.formEntries.append(item)

  def addNumericEntry(self,question,layout):
    self.questions[question] = 'numeric'
    label = qt.QLabel(question)
    item = qt.QLineEdit()
    layout.addRow(label,item)
    #self.formEntries.append(item)

  def onReload(self,moduleName="VisAIRe"):
    """Generic reload method for any scripted module.
    ModuleWizard will subsitute correct default moduleName.
    """
    import imp, sys, os, slicer

    widgetName = moduleName + "Widget"

    # reload the source code
    # - set source file path
    # - load the module to the global space
    filePath = eval('slicer.modules.%s.path' % moduleName.lower())
    p = os.path.dirname(filePath)
    if not sys.path.__contains__(p):
      sys.path.insert(0,p)
    fp = open(filePath, "r")
    globals()[moduleName] = imp.load_module(
        moduleName, fp, filePath, ('.py', 'r', imp.PY_SOURCE))
    fp.close()

    # rebuild the widget
    # - find and hide the existing widget
    # - create a new widget in the existing parent
    parent = slicer.util.findChildren(name='%s Reload' % moduleName)[0].parent()
    for child in parent.children():
      try:
        child.hide()
      except AttributeError:
        pass
    # Remove spacer items
    item = parent.layout().itemAt(0)
    while item:
      parent.layout().removeItem(item)
      item = parent.layout().itemAt(0)

    # delete the old widget instance
    '''
    widgetName = moduleName+'Widget'
    if hasattr(globals()['slicer'].modules, widgetName):
      getattr(globals()['slicer'].modules, widgetName).cleanup()
    '''

    # create new widget inside existing parent
    globals()[widgetName.lower()] = eval(
        'globals()["%s"].%s(parent)' % (moduleName, widgetName))
    globals()[widgetName.lower()].setup()

  def onReloadAndTest(self,moduleName="VisAIRe"):
    self.onReload()
    evalString = 'globals()["%s"].%sTest()' % (moduleName, moduleName)
    tester = eval(evalString)
    tester.runTest()
class SliceTrackerZFrameRegistrationWidget(ScriptedLoadableModuleWidget, ModuleWidgetMixin):

  ZFRAME_MODEL_PATH = 'Resources/zframe/zframe-model.vtk'
  ZFRAME_MODEL_NAME = 'ZFrameModel'

  def __init__(self, parent=None):
    ScriptedLoadableModuleWidget.__init__(self, parent)
    self.logic = SliceTrackerZFrameRegistrationLogic()

  def setup(self):
    ScriptedLoadableModuleWidget.setup(self)

    self.setupSliceWidget()
    self.tag = None
    self.zFrameModelNode = None

    self.registrationGroupBox = qt.QGroupBox()
    self.registrationGroupBoxLayout = qt.QFormLayout()
    self.registrationGroupBox.setLayout(self.registrationGroupBoxLayout)
    self.zFrameTemplateVolumeSelector = self.createComboBox(nodeTypes=["vtkMRMLScalarVolumeNode", ""], showChildNodeTypes=False,
                                                            selectNodeUponCreation=True, toolTip="Pick algorithm input.")
    self.applyRegistrationButton = self.createButton("Run Registration")
    self.registrationGroupBoxLayout.addRow("ZFrame template: ", self.zFrameTemplateVolumeSelector)
    self.registrationGroupBoxLayout.addRow(self.applyRegistrationButton)
    self.layout.addWidget(self.registrationGroupBox)
    self.layout.addStretch()
    self.setupConnections()
    self.setupEditorWidget()
    self.loadZFrameModel()

  def loadZFrameModel(self):
    collection = slicer.mrmlScene.GetNodesByName(self.ZFRAME_MODEL_NAME)
    for index in range(collection.GetNumberOfItems()):
      slicer.mrmlScene.RemoveNode(collection.GetItemAsObject(index))
    self.modulePath = os.path.dirname(slicer.util.modulePath(self.moduleName))
    zFrameModelPath = os.path.join(self.modulePath, self.ZFRAME_MODEL_PATH)
    if not self.zFrameModelNode:
      _, self.zFrameModelNode = slicer.util.loadModel(zFrameModelPath, returnNode=True)
      self.zFrameModelNode.SetName(self.ZFRAME_MODEL_NAME)
      slicer.mrmlScene.AddNode(self.zFrameModelNode)
      modelDisplayNode = self.zFrameModelNode.GetDisplayNode()
      modelDisplayNode.SetColor(1, 1, 0)

  def setupSliceWidget(self, name):
    self.redWidget = self.layoutManager.sliceWidget("Red")
    self.redCompositeNode = self.redWidget.mrmlSliceCompositeNode()
    self.redSliceView = self.redWidget.sliceView()
    self.redSliceLogic = self.redWidget.sliceLogic()
    self.redSliceNode = self.redSliceLogic.GetSliceNode()

  def setupEditorWidget(self):
    self.editorWidgetParent = slicer.qMRMLWidget()
    self.editorWidgetParent.setLayout(qt.QVBoxLayout())
    self.editorWidgetParent.setMRMLScene(slicer.mrmlScene)
    self.editUtil = EditorLib.EditUtil.EditUtil()
    self.editorWidget = EditorWidget(parent=self.editorWidgetParent, showVolumesFrame=False)
    self.editorWidget.setup()
    self.editorParameterNode = self.editUtil.getParameterNode()

  def setupConnections(self):
    self.applyRegistrationButton.clicked.connect(self.runRegistration)
    self.zFrameTemplateVolumeSelector.connect('currentNodeChanged(bool)', self.loadVolumeAndEnableEditor)

  def processEvent(self, caller=None, event=None):
    if event == "LeftButtonReleaseEvent":
      interactor = self.redSliceView.interactorStyle().GetInteractor()
      xy = interactor.GetEventPosition()
      interactor.RemoveObserver(self.tag)
      self.tag = None
      self.onCenterPointSet(xy)

  def loadVolumeAndEnableEditor(self):
    zFrameTemplateVolume = self.zFrameTemplateVolumeSelector.currentNode()
    self.redCompositeNode.SetBackgroundVolumeID(zFrameTemplateVolume.GetID())
    interactor = self.redSliceView.interactorStyle().GetInteractor()
    if self.tag:
      interactor.RemoveObserver(self.tag)
    self.tag = interactor.AddObserver(vtk.vtkCommand.LeftButtonReleaseEvent, self.processEvent, 1.0)

  def onCenterPointSet(self, xy):
    import vtk.util.numpy_support as vnp

    zFrameTemplateVolume = self.zFrameTemplateVolumeSelector.currentNode()
    volumesLogic = slicer.modules.volumes.logic()
    zFrameTemplateMask = volumesLogic.CreateLabelVolume(slicer.mrmlScene, zFrameTemplateVolume, 'zFrameTemplateMask')

    imageDataWorkingCopy = vtk.vtkImageData()
    imageDataWorkingCopy.DeepCopy(zFrameTemplateMask.GetImageData())
    newLabelNodeImage=vtk.vtkImageData()
    newLabelNodeImage.AllocateScalars(vtk.VTK_SHORT, 1)
    newLabelNodeImage.SetExtent(zFrameTemplateMask.GetImageData().GetExtent())
    numpyArray = vnp.vtk_to_numpy(imageDataWorkingCopy.GetPointData().GetScalars()).reshape(imageDataWorkingCopy.GetDimensions()).transpose(2,1,0)
    numpyArray[6:10,70:185,65:190].fill(1)
    spacing = imageDataWorkingCopy.GetSpacing()
    vtk_data = vnp.numpy_to_vtk(num_array=numpyArray.ravel(), deep=True, array_type=vtk.VTK_SHORT)
    newLabelNodeImage.GetPointData().SetScalars(vtk_data)
    dims = numpyArray.shape
    newLabelNodeImage.SetDimensions(dims[2], dims[1], dims[0])
    newLabelNodeImage.SetOrigin(0,0,0)
    newLabelNodeImage.SetSpacing(spacing[0], spacing[1], spacing[2])
    zFrameTemplateMask.SetAndObserveImageData(newLabelNodeImage)
    # update the default label map to the generic anatomy colors
    labelDisplayNode = zFrameTemplateMask.GetDisplayNode()
    labelColorTable = slicer.util.getNode('GenericAnatomyColors')
    labelDisplayNode.SetAndObserveColorNodeID(labelColorTable.GetID())

    self.redCompositeNode.SetBackgroundVolumeID(zFrameTemplateVolume.GetID())
    self.redCompositeNode.SetLabelVolumeID(zFrameTemplateMask.GetID())
    self.redCompositeNode.SetLabelOpacity(0.6)

    self.maskedVolume = self.createMaskedVolume(zFrameTemplateVolume, zFrameTemplateMask)

  def createMaskedVolume(self, inputVolume, labelVolume):
    maskedVolume = slicer.vtkMRMLScalarVolumeNode()
    maskedVolume.SetName("maskedTemplateVolume")
    slicer.mrmlScene.AddNode(maskedVolume)
    params = {'InputVolume': inputVolume, 'MaskVolume': labelVolume, 'OutputVolume': maskedVolume}
    slicer.cli.run(slicer.modules.maskscalarvolume, None, params, wait_for_completion=True)
    return maskedVolume

  def isRegistrationPossible(self):
    return False

  def runRegistration(self):
    registration = OpenSourceZFrameRegistration(self.maskedVolume)
    registration.runRegistration()
    self.zFrameModelNode.SetAndObserveTransformNodeID(registration.outputTransform.GetID())
Exemple #30
0
  def setup(self):
    self.viewMode = 'compare'
    self.compare0 = None
    self.compare1 = None
    self.sidebyside0 = None
    self.sidebyside1 = None

    # Instantiate and connect widgets ...

    # reload button
    # (use this during development, but remove it when delivering
    #  your module to users)
    self.reloadButton = qt.QPushButton("Reload")
    self.reloadButton.toolTip = "Reload this module."
    self.reloadButton.name = "VisAIRe Reload"
    self.layout.addWidget(self.reloadButton)
    self.reloadButton.connect('clicked()', self.onReload)

    # reload and test button
    # (use this during development, but remove it when delivering
    #  your module to users)
    #self.reloadAndTestButton = qt.QPushButton("Reload and Test")
    #self.reloadAndTestButton.toolTip = "Reload this module and then run the self tests."
    #self.layout.addWidget(self.reloadAndTestButton)
    #self.reloadAndTestButton.connect('clicked()', self.onReloadAndTest)

    # entry for the rater name
    label = qt.QLabel('Rater name:')
    self.raterName = qt.QLineEdit()
    self.layout.addWidget(label)
    self.layout.addWidget(self.raterName)

    # Configuration file picker
    label = qt.QLabel('Configuration file:')
    self.configFilePicker = qt.QPushButton('N/A')
    self.configFilePicker.connect('clicked()',self.onConfigFileSelected)
    self.layout.addWidget(label)
    self.layout.addWidget(self.configFilePicker)

    self.makeSnapshots = qt.QPushButton('Make snapshots')
    self.layout.addWidget(self.makeSnapshots)
    self.makeSnapshots.connect('clicked()', self.onMakeSnapshots)

    # Opacity control
    label = qt.QLabel('Foreground/Background opacity:')
    self.opacitySlider = ctk.ctkSliderWidget()
    self.opacitySlider.connect('valueChanged(double)',self.onOpacityChangeRequested)
    self.opacitySlider.minimum = 0.
    self.opacitySlider.maximum = 1.
    self.opacitySlider.decimals = 1
    self.opacitySlider.singleStep = 0.1
    self.layout.addWidget(label)
    self.layout.addWidget(self.opacitySlider)

    #  Button to switch between showing background/foreground volumes
    self.bgfgButton = qt.QPushButton("Switch Background/Foreground")
    self.layout.addWidget(self.bgfgButton)
    self.bgfgButton.connect('clicked()', self.onbgfgButtonPressed)

    # Select between compare view and editing layouts
    groupLabel = qt.QLabel('Review mode:')
    self.viewGroup = qt.QButtonGroup()
    self.compareSelector = qt.QRadioButton('Compare view')
    self.sideBySideSelector = qt.QRadioButton('Side by side')
    self.compareSelector.setChecked(1)
    self.viewGroup.addButton(self.compareSelector,1)
    self.viewGroup.addButton(self.sideBySideSelector,2)
    self.groupWidget = qt.QWidget()
    self.groupLayout = qt.QFormLayout(self.groupWidget)
    self.groupLayout.addRow(self.compareSelector, self.sideBySideSelector)
    self.layout.addWidget(self.groupWidget)
    # step4Layout.addRow(groupLabel, self.viewGroup)

    self.viewGroup.connect('buttonClicked(int)', self.onViewUpdateRequested)

    # setup Editor widget
    editorWidgetParent = slicer.qMRMLWidget()
    editorWidgetParent.setLayout(qt.QVBoxLayout())
    editorWidgetParent.setMRMLScene(slicer.mrmlScene)
    self.editorWidget = EditorWidget(parent=editorWidgetParent,showVolumesFrame=False)
    self.editorWidget.setup()
    self.editorParameterNode = self.editUtil.getParameterNode()
    self.layout.addWidget(editorWidgetParent)

    # Slice control
    #label = qt.QLabel('Slice selector:')
    #self.sliceSlider = ctk.ctkSliderWidget()
    #self.sliceSlider.connect('valueChanged(double)',self.onSliceChangeRequested)
    #self.sliceSlider.minimum = 0.
    #self.sliceSlider.maximum = 1.
    #self.sliceSlider.decimals = 1
    #self.sliceSlider.singleStep = 0.1
    #self.layout.addWidget(label)
    #self.layout.addWidget(self.opacitySlider)

    # Collapsible button to keep the content of the form
    self.evaluationFrame = ctk.ctkCollapsibleButton()
    self.evaluationFrame.text = "Assessment Form"
    self.evaluationFrame.collapsed = 0
    self.evaluationFrameLayout = qt.QFormLayout(self.evaluationFrame)
    self.layout.addWidget(self.evaluationFrame)

    self.formEntries = []
    self.questions = {'Improved compared to non-registered?':'binary','Diagnostic quality?':'binary','Error quantification (if available)':'numeric'}
    self.formEntryMapper = qt.QSignalMapper()
    self.formEntryMapper.connect('mapped(const QString&)', self.entrySelected)

    self.maxFormEntries = 30
    for i in range(self.maxFormEntries):
    # populate the assessment form
      # create a new sub-frame with the questions
      cb = ctk.ctkCollapsibleButton()
      cb.visible = False
      cb.collapsed = True
      self.formEntries.append(cb)
      self.formEntryMapper.setMapping(cb, str(i))
      cb.connect('contentsCollapsed(bool)', self.formEntryMapper, 'map()')

      layout = qt.QFormLayout(cb)
      self.evaluationFrameLayout.addRow(cb)

      for (q,c) in self.questions.items():
        if c == 'binary':
          self.addBinaryEntry(q, layout)
        elif c == 'numeric':
          self.addNumericEntry(q, layout)


    # Save button
    self.doneButton = qt.QPushButton("Save")
    self.doneButton.toolTip = "Click this when done."
    self.layout.addWidget(self.doneButton)
    self.doneButton.connect('clicked(bool)', self.onDoneButtonClicked)

    # Add vertical spacer
    self.layout.addStretch(1)

    # Initialize internal persistent variables
    self.configFile = None
    self.movingVolume = None
    self.perVolumeForms = []
    self.fixedVolumes = []
    self.registeredVolumes = []
    self.transforms = []
    self.caseName = None


    # add custom layout for comparing two pairs of volumes
    compareViewTwoRows ="<layout type=\"vertical\">"
    for i in range(2):
      compareViewTwoRows = compareViewTwoRows+"   <item>\
    <view class=\"vtkMRMLSliceNode\" singletontag=\"Compare"+str(i)+"\">\
    <property name=\"orientation\" action=\"default\">Axial</property>\
    <property name=\"viewlabel\" action=\"default\">"+str(i)+"</property>\
    <property name=\"viewcolor\" action=\"default\">#E17012</property>\
    <property name=\"lightboxrows\" action=\"default\">1</property>\
    <property name=\"lightboxcolumns\" action=\"default\">6</property>\
    <property name=\"lightboxrows\" action=\"relayout\">1</property>\
    <property name=\"lightboxcolumns\" action=\"relayout\">6</property>\
    </view>\
    </item>"
    compareViewTwoRows = compareViewTwoRows+"</layout>"

    sideBySide = "<layout type=\"horizontal\">\
     <item>\
      <view class=\"vtkMRMLSliceNode\" singletontag=\"SideBySide0\">\
       <property name=\"orientation\" action=\"default\">Axial</property>\
       <property name=\"viewlabel\" action=\"default\">Moving</property>\
       <property name=\"viewcolor\" action=\"default\">#F34A33</property>\
      </view>\
     </item>\
     <item>\
      <view class=\"vtkMRMLSliceNode\" singletontag=\"SideBySide1\">\
       <property name=\"orientation\" action=\"default\">Axial</property>\
       <property name=\"viewlabel\" action=\"default\">Reference</property>\
       <property name=\"viewcolor\" action=\"default\">#EDD54C</property>\
      </view>\
     </item>\
    </layout>"
    print(sideBySide)

    layoutNodes = slicer.mrmlScene.GetNodesByClass('vtkMRMLLayoutNode')
    layoutNodes.SetReferenceCount(layoutNodes.GetReferenceCount()-1)
    self.layoutNode = layoutNodes.GetItemAsObject(0)
    self.CompareLayout = 123
    self.ContouringLayout = 124
    self.layoutNode.AddLayoutDescription(self.CompareLayout,compareViewTwoRows)
    self.layoutNode.AddLayoutDescription(self.ContouringLayout,sideBySide)
    self.layoutNode.SetViewArrangement(self.ContouringLayout)
    self.layoutNode.SetViewArrangement(self.CompareLayout)
    sliceCompositeNodes = slicer.mrmlScene.GetNodesByClass('vtkMRMLSliceCompositeNode')
    sliceCompositeNodes.SetReferenceCount(sliceCompositeNodes.GetReferenceCount()-1)
    sliceNodes = slicer.mrmlScene.GetNodesByClass('vtkMRMLSliceNode')
    sliceNodes.SetReferenceCount(sliceNodes.GetReferenceCount()-1)
    for i in range(sliceCompositeNodes.GetNumberOfItems()):
      scn = sliceCompositeNodes.GetItemAsObject(i)
      sn = sliceNodes.GetItemAsObject(i)
      sn.SetUseLabelOutline(1)
      if sn.GetName() == 'Compare0':
        self.compare0 = scn
      if sn.GetName() == 'Compare1':
        self.compare1 = scn
      if sn.GetName() == 'SideBySide0':
        self.sidebyside0 = scn
      if sn.GetName() == 'SideBySide1':
        self.sidebyside1 = scn
Exemple #31
0
class CMRToolkitWizardEndoSegmentationStep(CMRToolkitWizardStep):
    def __init__(self, stepid):
        self.initialize(stepid)
        self.setName('2. Segmentation of endocardium')
        self.setDescription(
            'Segment the endocardium using the Editor paint tool and select the final label image to proceed.'
        )

        self.__parent = super(CMRToolkitWizardEndoSegmentationStep, self)

    def killButton(self):
        # Hide unneccesary button
        bl = slicer.util.findChildren(text='AutomaticLeft*')
        if len(bl):
            bl[0].hide()

    def createUserInterface(self):
        from Editor import EditorWidget

        self.__layout = self.__parent.createUserInterface()

        #TODO: Create label map and set it for editing by user?
        #volumesLogic = slicer.modules.volumes.logic()
        #headLabel = volumesLogic.CreateLabelVolume( slicer.mrmlScene, head, head.GetName() + '-segmentation' )

        #selectionNode = slicer.app.applicationLogic().GetSelectionNode()
        #selectionNode.SetReferenceActiveVolumeID( head.GetID() )
        #selectionNode.SetReferenceActiveLabelVolumeID( headLabel.GetID() )
        #slicer.app.applicationLogic().PropagateVolumeSelection(0)

        editorFrame = qt.QFrame()
        editorFrame.setLayout(qt.QVBoxLayout())
        palette = editorFrame.palette
        bgColor = 230
        palette.setColor(qt.QPalette.Background,
                         qt.QColor(bgColor, bgColor, bgColor))
        editorFrame.setPalette(palette)
        editorFrame.setAutoFillBackground(True)
        self.__layout.addRow(editorFrame)
        self.editorFrame = editorFrame
        global editorWidget
        self.editorWidget = EditorWidget(parent=self.editorFrame,
                                         showVolumesFrame=True)
        self.editorWidget.setup()
        self.editorWidget.enter()

        endoSegLabel = qt.QLabel('Endo Segmentation Image:')
        self.__endoSegSelector = slicer.qMRMLNodeComboBox()
        self.__endoSegSelector.toolTip = "Choose the endo segmentation label image."
        self.__endoSegSelector.nodeTypes = ['vtkMRMLScalarVolumeNode']
        self.__endoSegSelector.setMRMLScene(slicer.mrmlScene)
        self.__endoSegSelector.addEnabled = 0
        self.__layout.addRow(endoSegLabel, self.__endoSegSelector)

    #def startEditor(self):
    #  from Editor import EditorWidget
    #  editorWidget = EditorWidget(showVolumesFrame=True)

    def validate(self, desiredBranchId):
        self.__parent.validate(desiredBranchId)
        endoSegVolume = self.__endoSegSelector.currentNode()

        if endoSegVolume != None:
            endoSegID = endoSegVolume.GetID()
            pNode = self.parameterNode()
            pNode.SetParameter('endoSegVolumeID', endoSegID)
            Helper.SetLabelVolume(endoSegVolume.GetID())
            self.__parent.validationSucceeded(desiredBranchId)
        else:
            self.__parent.validationFailed(
                desiredBranchId, 'Error',
                'Please select an endo segmentation image to proceed.')

    def onEntry(self, comingFrom, transitionType):
        super(CMRToolkitWizardEndoSegmentationStep,
              self).onEntry(comingFrom, transitionType)
        pNode = self.parameterNode()
        pNode.SetParameter('currentStep', self.stepid)

        qt.QTimer.singleShot(0, self.killButton)

    def onExit(self, goingTo, transitionType):
        pNode = self.parameterNode()
        #if goingTo.id() != 'AxialDilate':
        #  return

        self.editorWidget.exit()

        super(CMRToolkitWizardEndoSegmentationStep,
              self).onExit(goingTo, transitionType)
  def setup( self ):
    #
    # Input frame
    #
    self.__inputFrame = ctk.ctkCollapsibleButton()
    self.__inputFrame.text = "Input"
    self.__inputFrame.collapsed = 0
    inputFrameLayout = qt.QFormLayout(self.__inputFrame)
    
    self.layout.addWidget(self.__inputFrame)

    # Active report node
    label = qt.QLabel('Report: ')
    self.__reportSelector = slicer.qMRMLNodeComboBox()
    self.__reportSelector.nodeTypes =  ['vtkMRMLReportingReportNode']
    self.__reportSelector.setMRMLScene(slicer.mrmlScene)
    self.__reportSelector.addEnabled = 1
    self.__reportSelector.removeEnabled = 0
    
    inputFrameLayout.addRow(label, self.__reportSelector)

    self.__reportSelector.connect('mrmlSceneChanged(vtkMRMLScene*)', self.onMRMLSceneChanged)
    self.__reportSelector.connect('currentNodeChanged(vtkMRMLNode*)', self.onReportNodeChanged)
 
    # Volume being annotated (only one is allowed for the report)
    label = qt.QLabel('NOTE: Only volumes loaded from DICOM can be annotated!')
    inputFrameLayout.addRow(label)
    label = qt.QLabel('Annotated volume: ')
    self.__volumeSelector = slicer.qMRMLNodeComboBox()
    self.__volumeSelector.nodeTypes = ['vtkMRMLScalarVolumeNode']
    # only allow volumes with the attribute DICOM.instanceUIDs
    self.__volumeSelector.addAttribute('vtkMRMLScalarVolumeNode','DICOM.instanceUIDs')
    self.__volumeSelector.setMRMLScene(slicer.mrmlScene)
    self.__volumeSelector.addEnabled = False
    
    inputFrameLayout.addRow(label, self.__volumeSelector)

    self.__volumeSelector.connect('currentNodeChanged(vtkMRMLNode*)', self.onAnnotatedVolumeNodeChanged)
    self.__volumeSelector.connect('mrmlSceneChanged(vtkMRMLScene*)', self.onMRMLSceneChanged)

    #
    # Annotation frame -- vocabulary-based description of what is
    # being annotated/marked up in this report
    #
    self.__annotationsFrame = ctk.ctkCollapsibleButton()
    self.__annotationsFrame.text = "Annotation"
    self.__annotationsFrame.collapsed = 0
    annotationsFrameLayout = qt.QFormLayout(self.__annotationsFrame)
    
    self.layout.addWidget(self.__annotationsFrame)

    self.__defaultColorNode = self.__logic.GetDefaultColorNode()

    self.__toolsColor = EditColor(self.__annotationsFrame,colorNode=self.__defaultColorNode)

    #
    # Markup frame -- summary of all the markup elements contained in the
    # report
    #
    self.__markupFrame = ctk.ctkCollapsibleButton()
    self.__markupFrame.text = "Markup"
    self.__markupFrame.collapsed = 0
    markupFrameLayout = qt.QFormLayout(self.__markupFrame)
    
    self.layout.addWidget(self.__markupFrame)

    # Add a flag to switch between different tree view models
    self.__useNewTreeView = 1

    # Add the tree widget
    if self.__useNewTreeView == 1:
      self.__markupTreeView = slicer.modulewidget.qMRMLReportingTreeView()
      self.__markupTreeView.sceneModelType = "DisplayableHierarchy"
    else:
      self.__markupTreeView = slicer.qMRMLTreeView()
      self.__markupTreeView.sceneModelType = "Displayable"
    self.__markupTreeView.setMRMLScene(self.__logic.GetMRMLScene())
        
    self.__markupSliceText = qt.QLabel()
    markupFrameLayout.addRow(self.__markupSliceText)
    markupFrameLayout.addRow(self.__markupTreeView)

    # Editor frame
    self.__editorFrame = ctk.ctkCollapsibleButton()
    self.__editorFrame.text = 'Segmentation'
    self.__editorFrame.collapsed = 0
    editorFrameLayout = qt.QFormLayout(self.__editorFrame)

    label = qt.QLabel('Segmentation volume: ')
    self.__segmentationSelector = slicer.qMRMLNodeComboBox()
    self.__segmentationSelector.nodeTypes = ['vtkMRMLScalarVolumeNode']
    self.__segmentationSelector.setMRMLScene(slicer.mrmlScene)
    self.__segmentationSelector.addEnabled = 1
    self.__segmentationSelector.noneEnabled = 1
    self.__segmentationSelector.removeEnabled = 0
    self.__segmentationSelector.showHidden = 0
    self.__segmentationSelector.showChildNodeTypes = 0
    self.__segmentationSelector.selectNodeUponCreation = 1
    self.__segmentationSelector.addAttribute('vtkMRMLScalarVolumeNode','LabelMap',1)

    editorFrameLayout.addRow(label, self.__segmentationSelector)

    editorWidgetParent = slicer.qMRMLWidget()
    editorWidgetParent.setLayout(qt.QVBoxLayout())
    editorWidgetParent.setMRMLScene(slicer.mrmlScene)
    self.__editorWidget = EditorWidget(parent=editorWidgetParent,showVolumesFrame=False)
    self.__editorWidget.setup()
    self.__editorWidget.toolsColor.frame.setVisible(False)
    editorFrameLayout.addRow(editorWidgetParent)

    markupFrameLayout.addRow(self.__editorFrame)

    self.__segmentationSelector.connect('currentNodeChanged(vtkMRMLNode*)', self.onSegmentationNodeChanged)
    self.__segmentationSelector.connect('mrmlSceneChanged(vtkMRMLScene*)', self.onMRMLSceneChanged)

    # IO frame
    self.__ioFrame = ctk.ctkCollapsibleButton()
    self.__ioFrame.text = 'Import/Export'
    self.__ioFrame.collapsed = 1
    ioFrameLayout = qt.QGridLayout(self.__ioFrame)

    self.layout.addWidget(self.__ioFrame)

    # Buttons to save/load report using AIM XML serialization
    label = qt.QLabel('Export folder')
    self.__exportFolderPicker = ctk.ctkDirectoryButton()
    exportButton = qt.QPushButton('Export')
    exportButton.connect('clicked()', self.onReportExport)
    ioFrameLayout.addWidget(label,0,0)
    ioFrameLayout.addWidget(self.__exportFolderPicker,0,1)
    ioFrameLayout.addWidget(exportButton,0,2)

    label = qt.QLabel('AIM file to import')
    self.__aimFilePicker = qt.QPushButton('N/A')
    self.__aimFilePicker.connect('clicked()',self.onSelectAIMFile)
    button = qt.QPushButton('Import')
    button.connect('clicked()', self.onReportImport)
    ioFrameLayout.addWidget(label,1,0)
    ioFrameLayout.addWidget(self.__aimFilePicker,1,1)
    ioFrameLayout.addWidget(button,1,2)
    self.__importAIMFile = None

    self.__reportSelector.connect('currentNodeChanged(vtkMRMLNode*)', self.updateWidgets)
    self.__volumeSelector.connect('currentNodeChanged(vtkMRMLNode*)', self.updateWidgets)
    self.updateWidgets()

    self.layout.addStretch(1)

    self.__editorParameterNode = self.editUtil.getParameterNode()

    self.__editorParameterNode.AddObserver(vtk.vtkCommand.ModifiedEvent, self.onEditorParameterNodeChanged)
Exemple #33
0
class ReviewStep(GBMWizardStep):
    def __init__(self, stepid):

        self.initialize(stepid)
        self.setName('6. Review')

        self.__vrDisplayNode = None
        self.__threshold = [-1, -1]

        # initialize VR stuff
        self.__vrLogic = slicer.modules.volumerendering.logic()
        self.__vrOpacityMap = None
        self.__vrColorMap = None

        self.__thresholdedLabelNode = None
        self.__roiVolume = None

        self.__parent = super(ReviewStep, self)
        self.__RestartActivated = False

    def createUserInterface(self):

        self.__layout = self.__parent.createUserInterface()

        step_label = qt.QLabel(
            """Review your segmentation. Use the 3D Visualization slider to see your segmentation in context with your image. Use the Editor panel to apply spot edits to your segmentation. If you would like to start over, see the Restart box below"""
        )
        step_label.setWordWrap(True)
        self.__primaryGroupBox = qt.QGroupBox()
        self.__primaryGroupBox.setTitle('Information')
        self.__primaryGroupBoxLayout = qt.QFormLayout(self.__primaryGroupBox)
        self.__primaryGroupBoxLayout.addRow(step_label)
        self.__layout.addRow(self.__primaryGroupBox)

        # self.__threshRange = slicer.qMRMLRangeWidget()
        # self.__threshRange.decimals = 0
        # self.__threshRange.singleStep = 1
        # self.__threshRange.connect('valuesChanged(double,double)', self.onThresholdChanged)
        # qt.QTimer.singleShot(0, self.killButton)

        # ThreshGroupBox = qt.QGroupBox()
        # ThreshGroupBox.setTitle('3D Visualization Intensity Threshold')
        # ThreshGroupBoxLayout = qt.QFormLayout(ThreshGroupBox)
        # ThreshGroupBoxLayout.addRow(self.__threshRange)
        # self.__layout.addRow(ThreshGroupBox)

        editorWidgetParent = slicer.qMRMLWidget()
        editorWidgetParent.setLayout(qt.QVBoxLayout())
        editorWidgetParent.setMRMLScene(slicer.mrmlScene)
        self.EditorWidget = EditorWidget(parent=editorWidgetParent)
        self.EditorWidget.setup()
        self.__layout.addRow(editorWidgetParent)

        RestartGroupBox = qt.QGroupBox()
        RestartGroupBox.setTitle('Restart')
        RestartGroupBoxLayout = qt.QFormLayout(RestartGroupBox)

        self.__RestartButton = qt.QPushButton('Return to Step 1')
        RestartGroupBoxLayout.addRow(self.__RestartButton)

        self.__RemoveRegisteredImage = qt.QCheckBox()
        self.__RemoveRegisteredImage.checked = True
        self.__RemoveRegisteredImage.setToolTip(
            "Delete your registered images.")
        RestartGroupBoxLayout.addRow("Delete Registered images: ",
                                     self.__RemoveRegisteredImage)

        self.__RemoveNormalizedImages = qt.QCheckBox()
        self.__RemoveNormalizedImages.checked = True
        self.__RemoveNormalizedImages.setToolTip(
            "Delete your normalized images.")
        RestartGroupBoxLayout.addRow("Delete Normalized images: ",
                                     self.__RemoveNormalizedImages)

        self.__RemoveSubtractionMap = qt.QCheckBox()
        self.__RemoveSubtractionMap.checked = True
        self.__RemoveSubtractionMap.setToolTip("Delete your subtraction map.")
        RestartGroupBoxLayout.addRow("Delete Subtraction map: ",
                                     self.__RemoveSubtractionMap)

        self.__RemoveCroppedMap = qt.QCheckBox()
        self.__RemoveCroppedMap.checked = True
        self.__RemoveCroppedMap.setToolTip(
            "Delete the cropped version of your input volume.")
        RestartGroupBoxLayout.addRow("Delete Cropped Volume: ",
                                     self.__RemoveCroppedMap)

        self.__RemoveROI = qt.QCheckBox()
        self.__RemoveROI.checked = False
        self.__RemoveROI.setToolTip(
            "Delete the ROI you made with your markup points.")
        RestartGroupBoxLayout.addRow("Delete Full ROI: ", self.__RemoveROI)

        self.__RemoveThresholdedROI = qt.QCheckBox()
        self.__RemoveThresholdedROI.checked = False
        self.__RemoveThresholdedROI.setToolTip(
            "Delete the intensity-thresholded version of your ROI.")
        RestartGroupBoxLayout.addRow("Delete Thresholded ROI: ",
                                     self.__RemoveThresholdedROI)

        self.__RemoveMarkups = qt.QCheckBox()
        self.__RemoveMarkups.checked = True
        self.__RemoveMarkups.setToolTip(
            "Delete the markup points you used to create your 3D ROI.")
        RestartGroupBoxLayout.addRow("Delete Markup Points: ",
                                     self.__RemoveMarkups)

        self.__RemoveModels = qt.QCheckBox()
        self.__RemoveModels.checked = True
        self.__RemoveModels.setToolTip(
            "Delete the 3D model you created from your markup points.")
        RestartGroupBoxLayout.addRow("Delete 3D Model: ", self.__RemoveModels)

        self.__RestartButton.connect('clicked()', self.Restart)
        self.__RestartActivated = True

        self.__layout.addRow(RestartGroupBox)

    def hideUnwantedEditorUIElements(self):
        """ We import the Editor module wholesale, which is useful, but it means
            we have to manually hide parts we don't want after the fact..
            If we could somehow import the segmentations module instead, that
            might be better. On the other hand, first-time users often don't know
            how to use the segmentations module.
        """

        self.EditorWidget.setMergeNode(self.__thresholdedLabelNode)
        self.EditorWidget.volumes.collapsed = True
        self.EditorWidget.editLabelMapsFrame.collapsed = False
        try:
            self.EditorWidget.segmentEditorLabel.hide()
            self.EditorWidget.infoIconLabel.hide()
        except:
            pass

    def Restart(self):

        # Unclick any selected editor tools..
        self.__DefaultToolButton.click()

        pNode = self.parameterNode()

        slicer.mrmlScene.RemoveNode(
            Helper.getNodeByID(pNode.GetParameter('clippingModelNodeID')))
        slicer.mrmlScene.RemoveNode(
            Helper.getNodeByID(pNode.GetParameter('clippingMarkupNodeID')))
        slicer.mrmlScene.RemoveNode(
            Helper.getNodeByID(pNode.GetParameter('vrDisplayNodeID')))

        if self.__RemoveRegisteredImage.checked:
            slicer.mrmlScene.RemoveNode(
                Helper.getNodeByID(pNode.GetParameter('registrationVolumeID')))

        if self.__RemoveNormalizedImages.checked:
            for node in [
                    pNode.GetParameter('baselineNormalizeVolumeID'),
                    pNode.GetParameter('followupNormalizeVolumeID')
            ]:
                if node != pNode.GetParameter(
                        'baselineVolumeID') and node != pNode.GetParameter(
                            'followupVolumeID'):
                    slicer.mrmlScene.RemoveNode(Helper.getNodeByID(node))

        if self.__RemoveSubtractionMap.checked:
            slicer.mrmlScene.RemoveNode(
                Helper.getNodeByID(pNode.GetParameter('subtractVolumeID')))

        if self.__RemoveCroppedMap.checked:
            slicer.mrmlScene.RemoveNode(
                Helper.getNodeByID(pNode.GetParameter('croppedVolumeID')))

        if self.__RemoveROI.checked:
            slicer.mrmlScene.RemoveNode(
                Helper.getNodeByID(
                    pNode.GetParameter('nonThresholdedLabelID')))

        if self.__RemoveThresholdedROI.checked:
            slicer.mrmlScene.RemoveNode(
                Helper.getNodeByID(pNode.GetParameter('thresholdedLabelID')))

        if self.__RemoveMarkups.checked:
            slicer.mrmlScene.RemoveNode(
                Helper.getNodeByID(pNode.GetParameter('clippingMarkupNodeID')))

        if self.__RemoveModels.checked:
            slicer.mrmlScene.RemoveNode(
                Helper.getNodeByID(pNode.GetParameter('clippingModelNodeID')))

        pNode.SetParameter('baselineVolumeID', '')
        pNode.SetParameter('followupVolumeID', '')
        pNode.SetParameter('originalBaselineVolumeID', '')
        pNode.SetParameter('originalFollowupVolumeID', '')

        pNode.SetParameter('registrationVolumeID', '')

        pNode.SetParameter('baselineNormalizeVolumeID', '')
        pNode.SetParameter('followupNormalizeVolumeID', '')
        pNode.SetParameter('subtractVolumeID', '')

        pNode.SetParameter('clippingMarkupNodeID', '')
        pNode.SetParameter('clippingModelNodeID', '')
        pNode.SetParameter('outputList', '')
        pNode.SetParameter('markupList', '')
        pNode.SetParameter('modelList', '')

        pNode.SetParameter('thresholdedLabelID', '')
        pNode.SetParameter('croppedVolumeID', '')
        pNode.SetParameter('nonThresholdedLabelID', '')

        pNode.SetParameter('roiNodeID', '')
        pNode.SetParameter('roiTransformID', '')

        pNode.SetParameter('vrDisplayNodeID', '')
        pNode.SetParameter('intensityThreshRangeMin', '')
        pNode.SetParameter('intensityThreshRangeMax', '')
        pNode.SetParameter('vrThreshRange', '')

        Helper.SetLabelVolume('')

        self.EditorWidget.exit()

        if self.__RestartActivated:
            self.workflow().goForward()

    def onThresholdChanged(self):

        if self.__vrOpacityMap == None:
            return

        range0 = self.__threshRange.minimumValue
        range1 = self.__threshRange.maximumValue

        self.__vrOpacityMap.RemoveAllPoints()
        self.__vrOpacityMap.AddPoint(range0 - 75, 0)
        self.__vrOpacityMap.AddPoint(range0, .02)
        self.__vrOpacityMap.AddPoint(range1, .04)
        self.__vrOpacityMap.AddPoint(range1 + 75, .1)

    def killButton(self):

        stepButtons = slicer.util.findChildren(className='ctkPushButton')

        backButton = ''
        nextButton = ''
        for stepButton in stepButtons:
            if stepButton.text == 'Next':
                nextButton = stepButton
            if stepButton.text == 'Back':
                backButton = stepButton

        nextButton.hide()

        # ctk creates a useless final page button. This method gets rid of it.
        bl = slicer.util.findChildren(text='ReviewStep')
        ex = slicer.util.findChildren('', 'EditColorFrame')
        if len(bl):
            bl[0].hide()
        if len(ex):
            ex[0].hide()

        self.__editLabelMapsFrame = slicer.util.findChildren(
            '', 'EditLabelMapsFrame')[0]
        self.__toolsColor = EditorLib.EditColor(self.__editLabelMapsFrame)

    def validate(self, desiredBranchId):

        # For now, no validation required.
        self.__parent.validationSucceeded(desiredBranchId)

    def onEntry(self, comingFrom, transitionType):
        super(ReviewStep, self).onEntry(comingFrom, transitionType)

        self.__RestartActivated = True
        self.__DefaultToolButton = slicer.util.findChildren(
            name='DefaultToolToolButton')[0]

        pNode = self.parameterNode()

        self.updateWidgetFromParameters(pNode)

        Helper.SetBgFgVolumes(self.__visualizedID, '')
        Helper.SetLabelVolume(self.__thresholdedLabelNode.GetID())

        self.onThresholdChanged()

        pNode.SetParameter('currentStep', self.stepid)

        qt.QTimer.singleShot(0, self.killButton)

    def updateWidgetFromParameters(self, pNode):

        self.__clippingModelNode = Helper.getNodeByID(
            pNode.GetParameter('clippingModelNodeID'))
        self.__baselineVolumeID = pNode.GetParameter('baselineVolumeID')
        self.__followupVolumeID = pNode.GetParameter('followupVolumeID')
        self.__subtractVolumeID = pNode.GetParameter('subtractVolumeID')
        self.__croppedVolumeID = pNode.GetParameter('cropedVolumeID')
        self.__baselineVolumeNode = Helper.getNodeByID(self.__baselineVolumeID)
        self.__followupVolumeNode = Helper.getNodeByID(self.__followupVolumeID)
        self.__subtractVolumeNode = Helper.getNodeByID(self.__subtractVolumeID)
        self.__vrDisplayNodeID = pNode.GetParameter('vrDisplayNodeID')
        self.__thresholdedLabelNode = Helper.getNodeByID(
            pNode.GetParameter('thresholdedLabelID'))

        self.__clippingModelNode.GetDisplayNode().VisibilityOn()

        if self.__followupVolumeID == None or self.__followupVolumeID == '':
            self.__visualizedNode = self.__baselineVolumeNode
            self.__visualizedID = self.__baselineVolumeID
        else:
            self.__visualizedID = self.__followupVolumeID
            self.__visualizedNode = self.__followupVolumeNode

        # vrRange = self.__visualizedNode.GetImageData().GetScalarRange()

        # if self.__vrDisplayNode == None:
        #   if self.__vrDisplayNodeID != '':
        #       self.__vrDisplayNode = slicer.mrmlScene.GetNodeByID(self.__vrDisplayNodeID)

        # Replace this, most likely.
        # self.__visualizedNode.AddAndObserveDisplayNodeID(self.__vrDisplayNode.GetID())
        # Helper.InitVRDisplayNode(self.__vrDisplayNode, self.__visualizedID, self.__croppedVolumeID)

        # self.__threshRange.minimum = vrRange[0]
        # self.__threshRange.maximum = vrRange[1]

        # if pNode.GetParameter('vrThreshRangeMin') == '' or pNode.GetParameter('vrThreshRangeMin') == None:
        #   self.__threshRange.setValues(vrRange[1]/3, 2*vrRange[1]/3)
        # else:
        #   self.__threshRange.setValues(float(pNode.GetParameter('vrThreshRangeMin')), float(pNode.GetParameter('vrThreshRangeMax')))

        # self.__vrOpacityMap = self.__vrDisplayNode.GetVolumePropertyNode().GetVolumeProperty().GetScalarOpacity()
        # self.__vrColorMap = self.__vrDisplayNode.GetVolumePropertyNode().GetVolumeProperty().GetRGBTransferFunction()

        # self.__vrColorMap.RemoveAllPoints()
        # self.__vrColorMap.AddRGBPoint(vrRange[0], 0.8, 0.8, 0)
        # self.__vrColorMap.AddRGBPoint(vrRange[1], 0.8, 0.8, 0)

        self.hideUnwantedEditorUIElements()

    def onExit(self, goingTo, transitionType):

        self.__DefaultToolButton.click()

        super(GBMWizardStep, self).onExit(goingTo, transitionType)
Exemple #34
0
    def setup(self):
        #
        # Input frame
        #
        self.__inputFrame = ctk.ctkCollapsibleButton()
        self.__inputFrame.text = "Input"
        self.__inputFrame.collapsed = 0
        inputFrameLayout = qt.QFormLayout(self.__inputFrame)

        self.layout.addWidget(self.__inputFrame)

        # Active report node
        label = qt.QLabel('Report: ')
        self.__reportSelector = slicer.qMRMLNodeComboBox()
        self.__reportSelector.nodeTypes = ['vtkMRMLReportingReportNode']
        self.__reportSelector.setMRMLScene(slicer.mrmlScene)
        self.__reportSelector.addEnabled = 1
        self.__reportSelector.removeEnabled = 0

        inputFrameLayout.addRow(label, self.__reportSelector)

        self.__reportSelector.connect('mrmlSceneChanged(vtkMRMLScene*)',
                                      self.onMRMLSceneChanged)
        self.__reportSelector.connect('currentNodeChanged(vtkMRMLNode*)',
                                      self.onReportNodeChanged)

        # Volume being annotated (only one is allowed for the report)
        label = qt.QLabel(
            'NOTE: Only volumes loaded from DICOM can be annotated!')
        inputFrameLayout.addRow(label)
        label = qt.QLabel('Annotated volume: ')
        self.__volumeSelector = slicer.qMRMLNodeComboBox()
        self.__volumeSelector.nodeTypes = ['vtkMRMLScalarVolumeNode']
        # only allow volumes with the attribute DICOM.instanceUIDs
        self.__volumeSelector.addAttribute('vtkMRMLScalarVolumeNode',
                                           'DICOM.instanceUIDs')
        self.__volumeSelector.setMRMLScene(slicer.mrmlScene)
        self.__volumeSelector.addEnabled = False

        inputFrameLayout.addRow(label, self.__volumeSelector)

        self.__volumeSelector.connect('currentNodeChanged(vtkMRMLNode*)',
                                      self.onAnnotatedVolumeNodeChanged)
        self.__volumeSelector.connect('mrmlSceneChanged(vtkMRMLScene*)',
                                      self.onMRMLSceneChanged)

        #
        # Annotation frame -- vocabulary-based description of what is
        # being annotated/marked up in this report
        #
        self.__annotationsFrame = ctk.ctkCollapsibleButton()
        self.__annotationsFrame.text = "Annotation"
        self.__annotationsFrame.collapsed = 0
        annotationsFrameLayout = qt.QFormLayout(self.__annotationsFrame)

        self.layout.addWidget(self.__annotationsFrame)

        self.__defaultColorNode = self.__logic.GetDefaultColorNode()

        self.__toolsColor = EditColor(self.__annotationsFrame,
                                      colorNode=self.__defaultColorNode)

        #
        # Markup frame -- summary of all the markup elements contained in the
        # report
        #
        self.__markupFrame = ctk.ctkCollapsibleButton()
        self.__markupFrame.text = "Markup"
        self.__markupFrame.collapsed = 0
        markupFrameLayout = qt.QFormLayout(self.__markupFrame)

        self.layout.addWidget(self.__markupFrame)

        # Add a flag to switch between different tree view models
        self.__useNewTreeView = 1

        # Add the tree widget
        if self.__useNewTreeView == 1:
            self.__markupTreeView = slicer.modulewidget.qMRMLReportingTreeView(
            )
            self.__markupTreeView.sceneModelType = "DisplayableHierarchy"
        else:
            self.__markupTreeView = slicer.qMRMLTreeView()
            self.__markupTreeView.sceneModelType = "Displayable"
        self.__markupTreeView.setMRMLScene(self.__logic.GetMRMLScene())

        self.__markupSliceText = qt.QLabel()
        markupFrameLayout.addRow(self.__markupSliceText)
        markupFrameLayout.addRow(self.__markupTreeView)

        # Editor frame
        self.__editorFrame = ctk.ctkCollapsibleButton()
        self.__editorFrame.text = 'Segmentation'
        self.__editorFrame.collapsed = 0
        editorFrameLayout = qt.QFormLayout(self.__editorFrame)

        label = qt.QLabel('Segmentation volume: ')
        self.__segmentationSelector = slicer.qMRMLNodeComboBox()
        self.__segmentationSelector.nodeTypes = ['vtkMRMLScalarVolumeNode']
        self.__segmentationSelector.setMRMLScene(slicer.mrmlScene)
        self.__segmentationSelector.addEnabled = 1
        self.__segmentationSelector.noneEnabled = 1
        self.__segmentationSelector.removeEnabled = 0
        self.__segmentationSelector.showHidden = 0
        self.__segmentationSelector.showChildNodeTypes = 0
        self.__segmentationSelector.selectNodeUponCreation = 1
        self.__segmentationSelector.addAttribute('vtkMRMLScalarVolumeNode',
                                                 'LabelMap', 1)

        editorFrameLayout.addRow(label, self.__segmentationSelector)

        editorWidgetParent = slicer.qMRMLWidget()
        editorWidgetParent.setLayout(qt.QVBoxLayout())
        editorWidgetParent.setMRMLScene(slicer.mrmlScene)
        self.__editorWidget = EditorWidget(parent=editorWidgetParent,
                                           showVolumesFrame=False)
        self.__editorWidget.setup()
        self.__editorWidget.toolsColor.frame.setVisible(False)
        editorFrameLayout.addRow(editorWidgetParent)

        markupFrameLayout.addRow(self.__editorFrame)

        self.__segmentationSelector.connect('currentNodeChanged(vtkMRMLNode*)',
                                            self.onSegmentationNodeChanged)
        self.__segmentationSelector.connect('mrmlSceneChanged(vtkMRMLScene*)',
                                            self.onMRMLSceneChanged)

        # IO frame
        self.__ioFrame = ctk.ctkCollapsibleButton()
        self.__ioFrame.text = 'Import/Export'
        self.__ioFrame.collapsed = 1
        ioFrameLayout = qt.QGridLayout(self.__ioFrame)

        self.layout.addWidget(self.__ioFrame)

        # Buttons to save/load report using AIM XML serialization
        label = qt.QLabel('Export folder')
        self.__exportFolderPicker = ctk.ctkDirectoryButton()
        exportButton = qt.QPushButton('Export')
        exportButton.connect('clicked()', self.onReportExport)
        ioFrameLayout.addWidget(label, 0, 0)
        ioFrameLayout.addWidget(self.__exportFolderPicker, 0, 1)
        ioFrameLayout.addWidget(exportButton, 0, 2)

        label = qt.QLabel('AIM file to import')
        self.__aimFilePicker = qt.QPushButton('N/A')
        self.__aimFilePicker.connect('clicked()', self.onSelectAIMFile)
        button = qt.QPushButton('Import')
        button.connect('clicked()', self.onReportImport)
        ioFrameLayout.addWidget(label, 1, 0)
        ioFrameLayout.addWidget(self.__aimFilePicker, 1, 1)
        ioFrameLayout.addWidget(button, 1, 2)
        self.__importAIMFile = None

        self.__reportSelector.connect('currentNodeChanged(vtkMRMLNode*)',
                                      self.updateWidgets)
        self.__volumeSelector.connect('currentNodeChanged(vtkMRMLNode*)',
                                      self.updateWidgets)
        self.updateWidgets()

        self.layout.addStretch(1)

        self.__editorParameterNode = self.editUtil.getParameterNode()

        self.__editorParameterNode.AddObserver(
            vtk.vtkCommand.ModifiedEvent, self.onEditorParameterNodeChanged)
Exemple #35
0
 def __init__(self, parent=None, showVolumesFrame=True, activeTools=("DefaultTool", "PaintEffect", "DrawEffect", "LevelTracingEffect", "RectangleEffect", "EraseLabel", "PreviousCheckPoint", "NextCheckPoint")):
     """Constructor. Just invokes the parent's constructor"""         
     self.activeTools = activeTools
     EditorWidget.__init__(self, parent, showVolumesFrame)