def enter(self):
    # switch to Two-over-Two layout
    lm = slicer.app.layoutManager()
    if lm != None:
      lm.setLayout(slicer.vtkMRMLLayoutNode.SlicerLayoutTwoOverTwoView)

    # 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 events')
    hasObserver = self.__logic.HasObserver(self.__logic.ErrorEvent)
    if hasObserver == 0:
      tag = self.__logic.AddObserver(self.__logic.ErrorEvent, self.respondToErrorMessage)
      # print '\tobserver tag = ',tag
    else:
      Helper.Debug('Logic already has an observer on the ErrorEvent')
    # respond to logic annotation added events
    hasObserver = self.__logic.HasObserver(self.__logic.AnnotationAdded)
    if hasObserver == 0:
      tag = self.__logic.AddObserver(self.__logic.AnnotationAdded, self.respondToAnnotationAdded)
    vnode = self.volumeSelector.currentNode()
    if vnode != None:
      # print "Enter: updating the tree view"
      self.updateTreeView()

    self.__editorWidget.enter()
Ejemplo n.º 2
0
    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()
Ejemplo n.º 3
0
    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 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()

    self.updateTreeView()
 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)
Ejemplo n.º 6
0
    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)
  def setHeader(self,reportNode):
    """Load the table widget with annotations for the report
    """
    Helper.Debug('setHeader() called')
    self.widget.clearContents()
    self.widget.setColumnCount(2)
    self.widget.setHorizontalHeaderLabels(['Markup','Visibility'])
    self.widget.horizontalHeader().setResizeMode(0, qt.QHeaderView.Stretch)
    self.widget.horizontalHeader().setResizeMode(1, qt.QHeaderView.Fixed)
    self.widget.setEditTriggers(qt.QAbstractItemView.NoEditTriggers)

    if not reportNode:
      return
    # get the volume node associated with this report
    volumeID = reportNode.GetVolumeNodeID()     
    Helper.Debug('volumeID = '+volumeID)

    if volumeID == "":
      return
    volumeNode = slicer.mrmlScene.GetNodeByID(volumeID)
    if not volumeNode:
      return

    # get the annotations associated with this report
    # find displayble nodes that are associated with this volume
    numDisplayableNodes = slicer.mrmlScene.GetNumberOfNodesByClass("vtkMRMLDisplayableNode")
    nodeIDList = [volumeID]
    for n in range(numDisplayableNodes): 
      displayableNode = slicer.mrmlScene.GetNthNodeByClass(n, "vtkMRMLDisplayableNode")
      # how best to get at module widget logic?
      Helper.Debug('Will check if in report here for '+displayableNode.GetID())
      inReport = slicer.modules.reporting.logic().IsInReport(displayableNode)
      Helper.Debug('Checked for report')
      if inReport:
        Helper.Debug('Found node associated with the report node: ' + displayableNode.GetName())
        nodeIDList.append(displayableNode.GetID())
      else:
        Helper.Debug('Failed to found associated node')

    self.widget.setRowCount(len(nodeIDList))
    row = 0
    for nodeID in nodeIDList:
      node = Helper.getNodeByID(nodeID)
      item = qt.QTableWidgetItem(node.GetName())
      self.widget.setItem(row,0,item)
      self.items.append(item)
      if node.IsA("vtkMRMLAnnotationNode"):
        item = qt.QTableWidgetItem()
        # save the id for toggling visibility on the node
        # TODO: make this more elegant instead of overloading the what's this role with the id
        item.setData(qt.Qt.WhatsThisRole, node.GetID())
        if node.GetDisplayVisibility() == 1:
          item.setData(qt.Qt.DecorationRole,qt.QPixmap(":/Icons/Small/SlicerVisible.png"))
        else:
          item.setData(qt.Qt.DecorationRole,qt.QPixmap(":/Icons/Small/SlicerInvisible.png"))
        self.widget.setItem(row,1,item)
        self.items.append(item)
      row += 1
  def setHeader(self,reportNode):
    """Load the table widget with annotations for the report
    """
    Helper.Debug('setHeader() called')
    self.widget.clearContents()
    self.widget.setColumnCount(2)
    self.widget.setHorizontalHeaderLabels(['Markup','Visibility'])
    self.widget.horizontalHeader().setResizeMode(0, qt.QHeaderView.Stretch)
    self.widget.horizontalHeader().setResizeMode(1, qt.QHeaderView.Fixed)
    self.widget.setEditTriggers(qt.QAbstractItemView.NoEditTriggers)

    if not reportNode:
      return
    # get the volume node associated with this report
    volumeID = reportNode.GetVolumeNodeID()     
    Helper.Debug('volumeID = '+volumeID)

    if volumeID == "":
      return
    volumeNode = slicer.mrmlScene.GetNodeByID(volumeID)
    if not volumeNode:
      return

    # get the annotations associated with this report
    # find displayble nodes that are associated with this volume
    numDisplayableNodes = slicer.mrmlScene.GetNumberOfNodesByClass("vtkMRMLDisplayableNode")
    nodeIDList = [volumeID]
    for n in range(numDisplayableNodes): 
      displayableNode = slicer.mrmlScene.GetNthNodeByClass(n, "vtkMRMLDisplayableNode")
      # how best to get at module widget logic?
      Helper.Debug('Will check if in report here for '+displayableNode.GetID())
      inReport = slicer.modules.reporting.logic().IsInReport(displayableNode)
      Helper.Debug('Checked for report')
      if inReport:
        Helper.Debug('Found node associated with the report node: ' + displayableNode.GetName())
        nodeIDList.append(displayableNode.GetID())
      else:
        Helper.Debug('Failed to found associated node')

    self.widget.setRowCount(len(nodeIDList))
    row = 0
    for nodeID in nodeIDList:
      node = Helper.getNodeByID(nodeID)
      item = qt.QTableWidgetItem(node.GetName())
      self.widget.setItem(row,0,item)
      self.items.append(item)
      if node.IsA("vtkMRMLAnnotationNode"):
        item = qt.QTableWidgetItem()
        # save the id for toggling visibility on the node
        # TODO: make this more elegant instead of overloading the what's this role with the id
        item.setData(qt.Qt.WhatsThisRole, node.GetID())
        if node.GetDisplayVisibility() == 1:
          item.setData(qt.Qt.DecorationRole,qt.QPixmap(":/Icons/Small/SlicerVisible.png"))
        else:
          item.setData(qt.Qt.DecorationRole,qt.QPixmap(":/Icons/Small/SlicerInvisible.png"))
        self.widget.setItem(row,1,item)
        self.items.append(item)
      row += 1
  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)
Ejemplo n.º 10
0
    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)
Ejemplo n.º 11
0
    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()
Ejemplo n.º 12
0
    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()))
Ejemplo n.º 13
0
    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 + "'")
Ejemplo n.º 14
0
 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)
Ejemplo n.º 15
0
    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 onItemClicked(self, item):
   # column 0 is the name, do jump to annotation
   if item.column() == 0:
     # get the id from the item in column 1
     idItem = self.widget.item(item.row(), 1)
     if idItem == None:
        # volumes don't have anything in this column
        return
     nodeID = idItem.data(qt.Qt.WhatsThisRole)
     if nodeID == None:
       return
     controlPointsNode = slicer.mrmlScene.GetNodeByID(nodeID)
     if controlPointsNode == None:
       return
     # is it an annotation?
     if controlPointsNode.IsA('vtkMRMLAnnotationControlPointsNode') == 0:
       return
     # get the coordinates of this annotation
     rasCoordinates = [0,0,0]
     if controlPointsNode.IsA('vtkMRMLAnnotationFiducialNode'):
       controlPointsNode.GetFiducialCoordinates(rasCoordinates)
     if controlPointsNode.IsA('vtkMRMLAnnotationRulerNode'):
       controlPointsNode.GetPosition1(rasCoordinates)
     sliceNode = slicer.mrmlScene.GetNthNodeByClass(0, 'vtkMRMLSliceNode')
     if sliceNode != None:
       Helper.Debug("Jumping to first point in annotation")
       # jump the other slices and then this slice
       sliceNode.JumpAllSlices(rasCoordinates[0],rasCoordinates[1],rasCoordinates[2])
       sliceNode.JumpSlice(rasCoordinates[0],rasCoordinates[1],rasCoordinates[2])
   # column 1 is the visibility column
   if item.column() == 1:
     # is it a displayable?
     nodeID = item.data(qt.Qt.WhatsThisRole)
     if id == None:
       return
     node = slicer.mrmlScene.GetNodeByID(nodeID)
     if node == None:
       return
     # update the visibility and the eye icon
     if node.GetDisplayVisibility() == 0:
       node.SetDisplayVisibility(1)
       item.setData(qt.Qt.DecorationRole,qt.QPixmap(":/Icons/Small/SlicerVisible.png"))
     else:
       node.SetDisplayVisibility(0)
       item.setData(qt.Qt.DecorationRole,qt.QPixmap(":/Icons/Small/SlicerInvisible.png"))
  def populateTreeView(self):
    Helper.Debug('populateTreeView')
    self.__markupTreeView.setHeader(self.__rNode)
    return
    Helper.Debug('populateTreeView')
    if self.__rNode == None:
      Helper.Debug('populateTreeView: no report node set!')
      return

    volumeID = self.__rNode.GetVolumeNodeID()     
    if volumeID == "":
      Helper.Debug('populateTreeView: no active volume node id on report ' + self.__rNode.GetName())
      return
    volumeNode = Helper.getNodeByID(volumeID)   
    Helper.Debug('volumeID = ' + volumeID)

    # find displayble nodes that are associated with this volume
    numDisplayableNodes = slicer.mrmlScene.GetNumberOfNodesByClass("vtkMRMLDisplayableNode")
    nodeIDList = []
    for n in range(numDisplayableNodes): 
      displayableNode = slicer.mrmlScene.GetNthNodeByClass(n, "vtkMRMLDisplayableNode")
      inReport = self.__logic.IsInReport(displayableNode)
      if inReport:
        Helper.Debug('Found node associated with the volume node: ' + displayableNode.GetName())
        nodeIDList.append(displayableNode.GetID())

    print "Report: " + self.__rNode.GetName()
    print "Volume: " + volumeNode.GetName()

    row = 0
    # volume name
    item = qt.QStandardItem()
    item.setEditable(False)
    item.setText(volumeNode.GetName())
    self.__markupsModel.setItem(row,0,item)
    self.items.append(item)
    row += 1

    # get the associated markups
    for nodeID in nodeIDList:
       node = Helper.getNodeByID(nodeID)
       if node != None and node.IsA("vtkMRMLVolumeNode") and node.GetLabelMap() == 1:
         Helper.Debug('Segmentation: ' + node.GetName())
         item = qt.QStandardItem()
         item.setEditable(False)
         item.setText(node.GetName())
         self.__markupsModel.setItem(row,0,item)
         self.items.append(item)
         row += 1
       if node != None and node.IsA("vtkMRMLAnnotationNode"):
         Helper.Debug('Annotation: ' + node.GetName())
         # annotation name
         item = qt.QStandardItem()
         item.setEditable(False)
         item.setText(node.GetName())
         self.__markupsModel.setItem(row,0,item)
         self.items.append(item)
         # annotation visibility
         item = qt.QStandardItem()
         # todo: allow click to toggle visib
         item.setEditable(False)
         if node.GetDisplayVisibility() == 1:
           item.setData(qt.QPixmap(":/Icons/Small/SlicerVisible.png"),qt.Qt.DecorationRole)
         else:
           item.setData(qt.QPixmap(":/Icons/Small/SlicerInvisible.png"),qt.Qt.DecorationRole)
         self.__markupsModel.setItem(row,1,item)
         self.items.append(item)
         row += 1
 def respondToAnnotationAdded(self, caller, event):
   Helper.Debug("respondToAnnotationAdded: updating the tree view")
   self.updateTreeView()
Ejemplo n.º 19
0
    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 updateTreeView(self):
   Helper.Debug('updateTreeView')
   self.__markupTreeView.setHeader(self.__rNode)
Ejemplo n.º 21
0
    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 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
      volumesLogic = slicer.modules.volumes.logic()
      geometryCheckString = volumesLogic.CheckForLabelVolumeValidity(self.__vNode, sNode)
      if geometryCheckString != "":
        newNodeAnswer = Helper.QuestionPopup('The geometry of the segmentation label you selected does not match the geometry of the volume being annotated!\nDo you want to create a new label to match the geometry, resampling data to fit?\n' + geometryCheckString)
        if newNodeAnswer == True:
          # create a new resampled label node from the input image
          resampledSegmentationNode = volumesLogic.ResampleVolumeToReferenceVolume(sNode, self.__vNode)
          # reselect it
          self.segmentationSelector.setCurrentNode(resampledSegmentationNode)
          # reset vars
          sNode = self.segmentationSelector.currentNode()
          Helper.InfoPopup('Created a new segmentation label named ' + sNode.GetName() + ' resampled from the input label map')
          image = sNode.GetImageData()
        else:
          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()

    self.updateTreeView()
Ejemplo n.º 23
0
    def test_RoundTrip(self):
        """
    Test fiducial round trip to and from AIM XML file on disk
    """

        print("ctest, please don't truncate my output: CTEST_FULL_OUTPUT")

        # enter the module
        mainWindow = slicer.util.mainWindow()
        mainWindow.moduleSelector().selectModule('Reporting')

        # l = slicer.modulelogic.vtkSlicerReportingModuleLogic()
        l = slicer.modules.reporting.logic()
        l.GUIHiddenOff()

        # testDataPath = os.path.normpath(os.path.join(os.path.realpath(__file__), "..", "..", "Prototype/TestData/DICOM.CT/")
        print("Reporting round trip test, current working directory = " +
              os.getcwd())
        testDataPath = os.path.join(os.getcwd(),
                                    "../../Testing/Temporary/DICOM.CT")
        # testDataPath = "/projects/birn/nicole/Slicer4/Reporting/Prototype/TestData/DICOM.CT"
        print("test data path = " + testDataPath)

        # set up a new DICOM database
        print("Creating a dicomDatabase!")
        ddb = ctk.ctkDICOMDatabase()
        if not ddb:
            print("ERROR: failed to create a new dicom database!")
            return
        dbpath = slicer.app.slicerHome + '/Testing/Temporary/TestingDCMDB/ctkDICOM.sql'
        print('database path set to ' + dbpath)
        if not os.path.exists(os.path.dirname(dbpath)):
            print('Creating dir ' + os.path.dirname(dbpath))
            os.makedirs(os.path.dirname(dbpath))
        ddb.openDatabase(dbpath, "ReportingTesting")
        if not ddb.isOpen:
            print("ERROR: failed to open a new dicom database at path " +
                  dbpath)
            return
        retval = ddb.initializeDatabase()
        if not retval:
            print("ERROR: failed to init database")
            return

        l.InitializeDICOMDatabase(dbpath)

        testFileNames = []
        for n in [487, 488, 489]:
            filename = os.path.join(testDataPath,
                                    "instance_" + str(n) + ".dcm")
            print("Adding file " + filename)
            testFileNames.append(filename)

        # check to see if the test data is already in it
        patients = ddb.patients()
        if len(patients) == 0:
            # add the files
            for filename in testFileNames:
                print("Inserting file " + filename)
                retval = ddb.insert(filename)
            patients = ddb.patients()
            if len(patients) == 0:
                print("ERROR: unable to add test files to database!")
                print(str(testFileNames))
                return

        # get the UID for the series
        study = ddb.studiesForPatient(patients[0])
        series = ddb.seriesForStudy(study[0])
        seriesUID = series[0]

        # seriesUID = "1.2.392.200103.20080913.113635.2.2009.6.22.21.43.10.23432.1"
        # seriesUID = "2.16.840.1.114362.1.759508.1251415878280.192"
        # seriesUID = "1.3.12.2.1107.5.1.4.53031.30000011032906120157800000219"
        print("For test, using the AIM sample volume with series UID of " +
              seriesUID)
        fileList = ddb.filesForSeries(seriesUID)
        print("fileList = " + str(fileList))
        if not fileList:
            print("ERROR: sample series with id " + seriesUID +
                  " not found in database!")
            return

        # add a parameter node
        parameterNode = slicer.vtkMRMLScriptedModuleNode()
        parameterNode.SetModuleName('Reporting')
        slicer.mrmlScene.AddNode(parameterNode)
        # set it to be the active parameter node
        l.SetActiveParameterNodeID(parameterNode.GetID())

        #
        # create a new report, make it the report in the parameter node, set up hierarchy
        #
        reportNode = slicer.mrmlScene.CreateNodeByClass(
            "vtkMRMLReportingReportNode")
        reportNode.SetReferenceCount(reportNode.GetReferenceCount() - 1)

        # set the color id
        colorID = 'vtkMRMLColorTableNodeFileGenericAnatomyColors.txt'
        reportNode.SetColorNodeID(colorID)
        reportNode.SetDICOMDatabaseFileName(dbpath)

        slicer.mrmlScene.AddNode(reportNode)
        parameterNode.SetParameter("reportID", reportNode.GetID())
        print(
            "Init hierarchy for report node, set parameter node to report id of "
            + reportNode.GetID())
        l.InitializeHierarchyForReport(reportNode)

        #
        # get some sample data from the database
        #
        volId = 1
        volumeNode = None
        volName = 'AIM volume ' + str(volId)

        print("Dicom data base = " + ddb)

        slicer.dicomDatabase = ddb
        scalarVolumePlugin = slicer.modules.dicomPlugins[
            'DICOMScalarVolumePlugin']()
        scalarVolumeLoadables = scalarVolumePlugin.examine([filelist])
        volumeNode = scalarVolumePlugin.load(scalarVolumeLoadables[0])
        volumeNode.SetName(volName)
        # print "volumeNode = ",volumeNode

        print("Initialize Hierarchy For Volume with id " + volumeNode.GetID())
        l.InitializeHierarchyForVolume(volumeNode)
        print("---Now active mark up is " + l.GetActiveMarkupHierarchyID())
        print("adding a fiducial")

        #
        # define a fiducial
        #
        fidNode = slicer.vtkMRMLAnnotationFiducialNode()
        fidName = "AIM Round Trip Test Fiducial"
        fidNode.SetName(fidName)
        fidNode.SetSelected(1)
        fidNode.SetVisible(1)
        fidNode.SetLocked(0)
        print("Calling set fid coords")
        startCoords = [15.8, 70.8, -126.7]
        fidNode.SetFiducialCoordinates(startCoords[0], startCoords[1],
                                       startCoords[2])
        print("Starting fiducial coordinates: " + str(startCoords))
        # point it to the volume
        fidNode.SetAttribute("AssociatedNodeID", volumeNode.GetID())
        fidNode.SetScene(slicer.mrmlScene)
        print("Adding text disp node")
        fidNode.CreateAnnotationTextDisplayNode()
        print("Adding point display node")
        fidNode.CreateAnnotationPointDisplayNode()

        print("add node:")
        # slicer.mrmlScene.DebugOn()
        # l.DebugOn()
        slicer.mrmlScene.AddNode(fidNode)

        print("getting slice uid")
        uid = l.GetSliceUIDFromMarkUp(fidNode)
        print("fidNode uid = " + uid)

        #
        # create a label volume
        #
        volumesLogic = slicer.modules.volumes.logic()
        labelNode = volumesLogic.CreateLabelVolume(slicer.mrmlScene,
                                                   volumeNode, "Segmentation")
        labelDisplayNode = labelNode.GetDisplayNode()
        labelDisplayNode.SetAndObserveColorNodeID(
            'vtkMRMLColorTableNodeFileGenericAnatomyColors.txt')
        l.AddNodeToReport(labelNode)

        # initialize image content
        labelImage = labelNode.GetImageData()
        extent = labelImage.GetExtent()
        pixelCounter = 0
        for k in range(extent[5]):
            for j in range(extent[3]):
                for i in range(extent[1]):
                    if pixelCounter in initializedSegmentationVoxels:
                        labelImage.SetScalarComponentFromFloat(i, j, k, 0, 1)
                    else:
                        labelImage.SetScalarComponentFromFloat(i, j, k, 0, 0)
                    pixelCounter = pixelCounter + 1

        # test save to mrml
        # slicer.mrmlScene.SetURL('/spl/tmp/nicole/Testing/aim/RoundTripTest.mrml')
        # slicer.mrmlScene.Commit()

        #
        # output AIM XML
        #
        dirName = slicer.app.slicerHome + '/Testing/Temporary/'
        reportNode.SetStorageDirectoryName(dirName)

        print("Saving report to " + dirName)
        retval = l.SaveReportToAIM(reportNode)

        if (retval != 0):
            print("ERROR: unable to save report to aim file " + dirName +
                  ", retval=" + retval)
        else:
            print("Saved report to " + dirName)

        self.assertEqual(retval, 0)

        print("\n\n\nReloading aim file...")

        #
        # now clear the scene so can read in
        #
        # TBD: this causes a crash
        # slicer.mrmlScene.Clear(0)

        #
        # load in the aim file
        #
        newReport = slicer.mrmlScene.CreateNodeByClass(
            "vtkMRMLReportingReportNode")
        newReport.SetReferenceCount(newReport.GetReferenceCount() - 1)
        # set the default color map
        newReport.SetColorNodeID(colorID)
        newReport.SetDICOMDatabaseFileName(dbpath)
        slicer.mrmlScene.AddNode(newReport)
        parameterNode.SetParameter("reportID", newReport.GetID())

        Helper.LoadAIMFile(newReport.GetID(), aimFileName)

        # check the fiducial
        endCoords = [0, 0, 0]
        col = slicer.mrmlScene.GetNodesByClass("vtkMRMLAnnotationFiducialNode")
        col.SetReferenceCount(col.GetReferenceCount() - 1)

        # if the scene is not cleared, we should have 2 fiducials
        nFiducials = col.GetNumberOfItems()

        if nFiducials != 2:
            print("Failed to read fiducial form the saved report!")
            self.assertTrue(False)

        f = col.GetItemAsObject(1)
        f.GetFiducialCoordinates(endCoords)

        print("Start Coords = " + str(startCoords[0]) + "," +
              str(startCoords[1]) + "," + str(startCoords[2]))
        print("End Coords = " + str(endCoords))

        xdiff = endCoords[0] - startCoords[0]
        ydiff = endCoords[1] - startCoords[1]
        zdiff = endCoords[2] - startCoords[2]
        diffTotal = xdiff + ydiff + zdiff

        print(
            "Difference between coordinates after loaded the aim file and value from before stored the aim file: "
            + str(xdiff) + "," + str(ydiff) + "," + str(zdiff) +
            ". Total difference = " + str(diffTotal))

        if diffTotal > 0.1:
            print("Fiducial coordinates error exceeds the allowed bounds")
            self.assertTrue(False)

        # check the label node
        sceneVolumes = slicer.mrmlScene.GetNodesByClass(
            "vtkMRMLScalarVolumeNode")
        sceneVolumes.SetReferenceCount(sceneVolumes.GetReferenceCount() - 1)

        sceneLabels = []

        for i in range(sceneVolumes.GetNumberOfItems()):
            vol = sceneVolumes.GetItemAsObject(i)
            if vol.GetLabelMap():
                sceneLabels.append(vol)

        if len(sceneLabels) != 2:
            print(
                "Scene does not have two label nodes after reloading from AIM!"
            )
            self.assertTrue(False)

        newLabelNode = sceneLabels[1]
        newLabelImage = newLabelNode.GetImageData()
        extent = newLabelImage.GetExtent()
        pixelCounter = 0
        for k in range(extent[5]):
            for j in range(extent[3]):
                for i in range(extent[1]):
                    pixel = newLabelImage.GetScalarComponentAsFloat(i, j, k, 0)
                    if ((pixelCounter in initializedSegmentationVoxels)
                            and pixel != 1) or (not (
                                pixelCounter in initializedSegmentationVoxels)
                                                and pixel != 0):
                        print("Segmentation content not recovered correctly!")
                        print("Pixel counter " + str(pixelCounter) +
                              " is set to " + str(pixel))
                        self.assertTrue(False)
                    pixelCounter = pixelCounter + 1

        self.assertTrue(True)