def __checkNewVolume__(self, newVolumeNode):
        if self.blockNodeEvents:
            return
        self.blockNodeEvents = True
        volume = self.currentVolumeLoaded
        if volume is not None and newVolumeNode is not None \
                and newVolumeNode.GetID() != volume.GetID()  \
                and not self.logic.isVolumeSaved(volume.GetID()):
            # Ask the user if he wants to save the previously loaded volume
            if qt.QMessageBox.question(slicer.util.mainWindow(), "Save results?",
                    "The fiducials for the volume '{0}' have not been saved. Do you want to save them?"
                    .format(volume.GetName()),
                    qt.QMessageBox.Yes|qt.QMessageBox.No) == qt.QMessageBox.Yes:
                self.saveResultsCurrentNode()
        # Remove all the previously existing nodes
        if self.currentVolumeLoaded is not None and newVolumeNode != self.currentVolumeLoaded:
            # Remove previously existing node
            self.logic.removeMarkupsAndNode(self.currentVolumeLoaded)
        if newVolumeNode is not None:
            SlicerUtil.setActiveVolumeId(newVolumeNode.GetID())
            SlicerUtil.setFiducialsCursorMode(True, True)

        self.currentVolumeLoaded = newVolumeNode
        self.updateState()
        self.blockNodeEvents = False
예제 #2
0
    def createList(self, name):
        """Add an instance of a fiducial to the scene for a given
        volume node.  Creates a new list if needed.
        If list already has a fiducial with the given name, then
        set the position to the passed value.
        """
        applicationLogic = slicer.app.applicationLogic()
        selectionNode = applicationLogic.GetSelectionNode()
        selectionNode.SetReferenceActivePlaceNodeClassName(
            "vtkMRMLMarkupsFiducialNode")
        interactionNode = applicationLogic.GetInteractionNode()
        interactionNode.SwitchToPersistentPlaceMode()

        fiducialsLogic = slicer.modules.markups.logic()

        listsInScene = slicer.util.getNodes('vtkMRMLMarkupsFiducialNode*')
        createNewList = True
        if (listsInScene):
            for oldList in list(listsInScene.values()):
                if oldList.GetName() == name:
                    fiducialsLogic.SetActiveListID(oldList)
                    createNewList = False
                    break
            if (createNewList):
                fiducialListNodeID = fiducialsLogic.AddNewFiducialNode(
                    "Fiducial", slicer.mrmlScene)
                fiducialList = SlicerUtil.getNode(fiducialListNodeID)
                fiducialsLogic.SetActiveListID(fiducialList)
        else:
            fiducialListNodeID = fiducialsLogic.AddNewFiducialNode(
                "Fiducial", slicer.mrmlScene)
            fiducialList = SlicerUtil.getNode(fiducialListNodeID)
            fiducialsLogic.SetActiveListID(fiducialList)
예제 #3
0
 def exit(self):
     """This is invoked every time that we switch to another module (not only when Slicer is closed)."""
     try:
         self.blockNodeEvents = True
         SlicerUtil.setFiducialsCursorMode(False)
     except:
         pass
예제 #4
0
    def _checkNewVolume_(self, newVolumeNode):
        """ New volume loaded in the scene in some way.
        If it's really a new volume, try to save and close the current one
        @param newVolumeNode:
        """
        if self.blockNodeEvents:
            # "Semaphore" to avoid duplicated events
            return

        self.blockNodeEvents = True
        volume = self.currentVolumeLoaded
        if volume is not None and newVolumeNode is not None \
                and newVolumeNode.GetID() != volume.GetID()  \
                and not self.logic.isVolumeSaved(volume.GetName()):
            # Ask the user if he wants to save the previously loaded volume
            if qt.QMessageBox.question(
                    slicer.util.mainWindow(), "Save results?",
                    "The fiducials for the volume '{0}' have not been saved. Do you want to save them?"
                    .format(volume.GetName()), qt.QMessageBox.Yes
                    | qt.QMessageBox.No) == qt.QMessageBox.Yes:
                self.saveResultsCurrentNode()
        # Remove all the previously existing nodes
        if self.currentVolumeLoaded is not None and newVolumeNode != self.currentVolumeLoaded:
            # Remove previously existing node
            self.logic.removeMarkupsAndNode(self.currentVolumeLoaded)

        if newVolumeNode is not None:
            SlicerUtil.setActiveVolumeIds(newVolumeNode.GetID())
            SlicerUtil.setFiducialsCursorMode(True, True)

        self.currentVolumeLoaded = newVolumeNode
        self.updateState()
        self.blockNodeEvents = False
예제 #5
0
    def setActiveFiducialsListNode(self, volumeNode, typesList, createIfNotExists=True):
        """ Overrriden. Create a fiducials list node corresponding to this volume and this type list.
        In this case
        :param volumeNode: Scalar volume node
        :param typesList: list of types-subtypes. It can be a region-type-artifact or any other combination
        :param createIfNotExists: create the fiducials node if it doesn't exist yet for this subtype list
        :return: fiducials volume node
        """
        typeId = self.getTypeId(typesList)
        artifactId = self.getArtifactId(typesList)
        regionId = self.getRegionId(typesList)
        if volumeNode is not None:
            if artifactId == -1:
                # No artifact
                nodeName = "{}_fiducials_{}_{}".format(volumeNode.GetName(), typeId, regionId)
            else:
                # Artifact. Add the type of artifact to the node name
                nodeName = "{}_fiducials_{}_{}_{}".format(volumeNode.GetName(), typeId, regionId, artifactId)
            fid = slicer.util.getNode(nodeName)
            if fid is None and createIfNotExists:
                SlicerUtil.logDevelop("DEBUG: creating a new fiducials node: " + nodeName)
                fid = self._createFiducialsListNode_(nodeName, typesList)
                # Add the volume to the list of "managed" cases
                self.savedVolumes[volumeNode.GetName()] = False

            self.currentVolumeId = volumeNode.GetID()
            self.currentTypesList = typesList
            # Mark the node list as the active one
            self.markupsLogic.SetActiveListID(fid)
            return fid
예제 #6
0
 def resetModuleState(self):
     """ Reset all the module state variables
     """
     self.savedVolumeID = None  # Active grayscale volume ID
     self.savedLabelmapID = None  # Active labelmap node ID
     self.savedLabelmapOpacity = None  # Labelmap opacity
     self.savedContrastLevel = (None, None)  # Contrast window/level that the user had when entering the module
     SlicerUtil.changeContrastWindow(350, 40)
예제 #7
0
 def saveResultsCurrentNode(self):
     """ Get current active node and save the xml fiducials file
     """
     try:
         d = self.saveResultsDirectoryButton.directory
         if not os.path.isdir(d):
             # Ask the user if he wants to create the folder
             if qt.QMessageBox.question(
                     slicer.util.mainWindow(), "Create directory?",
                     "The directory '{0}' does not exist. Do you want to create it?"
                     .format(d), qt.QMessageBox.Yes
                     | qt.QMessageBox.No) == qt.QMessageBox.Yes:
                 try:
                     os.makedirs(d)
                     # Make sure that everybody has write permissions (sometimes there are problems because of umask)
                     os.chmod(d, 0o777)
                 except:
                     qt.QMessageBox.warning(
                         slicer.util.mainWindow(), 'Directory incorrect',
                         'The folder "{0}" could not be created. Please select a valid directory'
                         .format(d))
                     return
             else:
                 # Abort process
                 SlicerUtil.logDevelop("Saving results process aborted",
                                       includePythonConsole=True)
                 return
                 # self.logic.saveCurrentFiducials(d, self.caseNavigatorWidget, self.uploadFileResult)
                 # qt.QMessageBox.information(slicer.util.mainWindow(), 'Results saved',
                 #                            "The results have been saved succesfully")
         # else:
         if SlicerUtil.isSlicerACILLoaded():
             question = qt.QMessageBox.question(
                 slicer.util.mainWindow(), "Save results remotely?",
                 "Your results will be saved locally. Do you also want to save your results in your remote server? (MAD, etc.)",
                 qt.QMessageBox.Yes | qt.QMessageBox.No
                 | qt.QMessageBox.Cancel)
             if question == qt.QMessageBox.Cancel:
                 return
             saveInRemoteRepo = question == qt.QMessageBox.Yes
         else:
             saveInRemoteRepo = False
         self.logic.saveCurrentFiducials(
             d,
             caseNavigatorWidget=self.caseNavigatorWidget,
             callbackFunction=self.uploadFileResult,
             saveInRemoteRepo=saveInRemoteRepo)
         qt.QMessageBox.information(
             slicer.util.mainWindow(), 'Results saved',
             "The results have been saved succesfully")
     except:
         Util.print_last_exception()
         qt.QMessageBox.critical(
             slicer.util.mainWindow(), "Error when saving the results",
             "Error when saving the results. Please review the console for additional info"
         )
 def exit(self):
     """This is invoked every time that we switch to another module (not only when Slicer is closed)."""
     try:
         self.blockNodeEvents = True
         SlicerUtil.setFiducialsCursorMode(False)
         # for observer in self.observers:
         #     slicer.mrmlScene.RemoveObserver(observer)
         #     self.observers.remove(observer)
     except:
         pass
예제 #9
0
 def enter(self):
     """This is invoked every time that we select this module as the active module in Slicer (not only the first time)"""
     # activeVolumeId = SlicerUtil.getActiveVolumeIdInRedSlice()
     # if activeVolumeId is not None:
     #     self.volumeSelector.setCurrentNodeID(activeVolumeId)
     #     if activeVolumeId not in self.logic.currentVolumesLoaded:
     #         self.placeDefaultRulers(activeVolumeId)
     volumeId = self.volumeSelector.currentNodeId
     if volumeId:
         SlicerUtil.setActiveVolumeId(volumeId)
예제 #10
0
 def enter(self):
     """This is invoked every time that we select this module as the active module in Slicer (not only the first time)"""
     # activeVolumeId = SlicerUtil.getActiveVolumeIdInRedSlice()
     # if activeVolumeId is not None:
     #     self.volumeSelector.setCurrentNodeID(activeVolumeId)
     #     if activeVolumeId not in self.logic.currentVolumesLoaded:
     #         self.placeDefaultRulers(activeVolumeId)
     volumeId = self.volumeSelector.currentNodeId
     if volumeId:
         SlicerUtil.setActiveVolumeId(volumeId)
예제 #11
0
 def exit(self):
     """This is invoked every time that we switch to another module (not only when Slicer is closed)."""
     try:
         self.blockNodeEvents = True
         SlicerUtil.setFiducialsCursorMode(False)
         # for observer in self.observers:
         #     slicer.mrmlScene.RemoveObserver(observer)
         #     self.observers.remove(observer)
     except:
         pass
예제 #12
0
 def onVolumeSelectorChanged(self, node):
     #if node is not None and node.GetID() not in self.currentVolumesLoaded:
     # if node is not None:
     #     # New node. Load default rulers
     #     if node.GetID() not in self.logic.currentVolumesLoaded:
     #         self.placeDefaultRulers(node.GetID())
     logging.info("Volume selector node changed: {0}".format(
         '(None)' if node is None else node.GetName()))
     # Preferred contrast (TODO: set right level)
     SlicerUtil.changeContrastWindow(1144, 447)
     self.refreshTextboxes()
예제 #13
0
    def createLungLabelMap(self, input_node, label_node):
        """Create the lung label map
        """
        self.applyButton.text = "Creating Label Map..."
        self.applyButton.repaint()
        slicer.app.processEvents()

        self.preProcessingWidget.createPartialLM(input_node, label_node)

        SlicerUtil.changeLabelmapOpacity(0.5)
        self.labelSelector.setCurrentNode(label_node)
예제 #14
0
    def enter(self):
        """This is invoked every time that we select this module as the active module in Slicer (not only the first time)"""
        self.blockNodeEvents = False
        # if len(self.observers) == 0:
        #     self.observers.append(slicer.mrmlScene.AddObserver(slicer.vtkMRMLScene.NodeAddedEvent, self.__onNodeAddedObserver__))
        #     self.observers.append(slicer.mrmlScene.AddObserver(slicer.vtkMRMLScene.EndCloseEvent, self.__onSceneClosed__))
        SlicerUtil.setFiducialsCursorMode(True, True)

        if self.volumeSelector.currentNodeId != "":
            SlicerUtil.setActiveVolumeIds(self.volumeSelector.currentNodeId)
            self.currentVolumeLoaded = slicer.mrmlScene.GetNodeByID(self.volumeSelector.currentNodeId)
            self.updateState()
    def enter(self):
        """This is invoked every time that we select this module as the active module in Slicer (not only the first time)"""
        self.blockNodeEvents = False
        # if len(self.observers) == 0:
        #     self.observers.append(slicer.mrmlScene.AddObserver(slicer.vtkMRMLScene.NodeAddedEvent, self.__onNodeAddedObserver__))
        #     self.observers.append(slicer.mrmlScene.AddObserver(slicer.vtkMRMLScene.EndCloseEvent, self.__onSceneClosed__))
        SlicerUtil.setFiducialsCursorMode(True, True)

        if self.volumeSelector.currentNodeId != "":
            SlicerUtil.setActiveVolumeId(self.volumeSelector.currentNodeId)
            self.currentVolumeLoaded = slicer.util.getNode(self.volumeSelector.currentNodeId)
            self.updateState()
예제 #16
0
 def getOrCreateLabelmap(self, masterNode):
     labelmapName = "{0}_{1}".format(masterNode.GetName(), self.labelmapNodeNameExtension)
     labelmapNode = SlicerUtil.getNode(labelmapName)
     if labelmapNode is None:
         # Create a labelmap for this scalar
         labelmapNode = slicer.modules.volumes.logic().CreateAndAddLabelVolume(slicer.mrmlScene, masterNode, labelmapName)
         # Make sure that the labelmap has this name (no suffixes)
         labelmapNode.SetName(labelmapName)
         SlicerUtil.logDevelop("New label map node created: " + labelmapName, includePythonConsole=True)
     else:
         SlicerUtil.logDevelop("Labelmap loaded", includePythonConsole=True)
     return labelmapNode
예제 #17
0
    def _initColumns_(self):
        """
        Create the list of columns in the tableNode based on the existing columns dictionary.
        If the database already existed, create new columns if necessary
        :param columnsDict:
        """
        for colKey, colDesc in self.columnsDict.items():
            if not colKey.isalnum():
                raise Exception(
                    "Column {} is not alphanumeric. The column keys can contain only letters and numbers."
                    .format(colKey))
            if colKey in self.reservedColumnKeys:
                raise Exception(
                    "One of the columns is named as one of the reserved fields: {}"
                    .format(self.reservedColumnKeys))

        table = self.tableNode.GetTable()
        if self.tableNode.GetNumberOfColumns() == 0:
            # Empty table
            # Add columns
            for value in self.columnsDict.itervalues():
                col = self.tableNode.AddColumn()
                # We will keep the "friendly" name of the column until the moment we are saving in db
                col.SetName(value)
            SlicerUtil.logDevelop(
                "Table {} initialized from scratch with the following columns: {}"
                .format(self._dbTableName_, self.columnsDict),
                includePythonConsole=True)
            tableColumnKeys = self.columnsDict.keys()
        else:
            # The table already has previously existing columns. Check if new columns were introduced
            tableColumnKeys = []
            for i in range(self.tableNode.GetNumberOfColumns()):
                tableColumnKeys.append(table.GetColumnName(i))

            for key in self.columnsDict.iterkeys():
                if key not in tableColumnKeys:
                    # Add a new column to the table
                    col = self.tableNode.AddColumn()
                    col.SetName(key)
                    SlicerUtil.logDevelop(
                        "New column added to the table {} in the database: {}".
                        format(self._dbTableName_, key),
                        includePythonConsole=True)

        # Add obligatory columns
        for key in self.reservedColumnKeys:
            if key not in self.columnsDict:
                self.columnsDict[key] = key
            if key not in tableColumnKeys:
                col = self.tableNode.AddColumn()
                col.SetName(key)
예제 #18
0
 def __onNewILDClassificationLabelmapLoaded__(self, labelmapNode, split1,
                                              split2):
     """ Load a new ILD classification labelmap volume.
     If the labelmap is a known labelmap type, set the right colors and opacity
     @param labelmapNode:
     """
     if SlicerUtil.isExtensionMatch(labelmapNode,
                                    "ILDClassificationLabelmap"):
         colorNode = self.__getColorTable__()
         displayNode = labelmapNode.GetDisplayNode()
         displayNode.SetAndObserveColorNodeID(colorNode.GetID())
         # Change Opacity
         SlicerUtil.displayLabelmapVolume(labelmapNode.GetID(), 0.3)
예제 #19
0
 def onSelect(self):
     self.layoutCollapsibleButton.setChecked(True)
     if self.labelSelector.currentNode():
         self.preProcessingWidget.enableFilteringFrame(False)
         self.preProcessingWidget.enableLMFrame(False)
         for color in ['Red', 'Yellow', 'Green']:
             slicer.app.layoutManager().sliceWidget(color).sliceLogic().GetSliceCompositeNode().SetLabelVolumeID(self.labelSelector.currentNode().GetID())
         SlicerUtil.changeLabelmapOpacity(0.5)            
     else:
         self.preProcessingWidget.enableFilteringFrame(True)
         self.preProcessingWidget.enableLMFrame(True)
         for color in ['Red', 'Yellow', 'Green']:
             slicer.app.layoutManager().sliceWidget(color).sliceLogic().GetSliceCompositeNode().SetLabelVolumeID('None')
예제 #20
0
    def createLungLabelMap(self):
        """Create the lung label map
        """
        self.applyButton.enabled = False
        if self.preProcessingWidget.filterOnRadioButton.checked:  # and not self.preProcessingWidget.filterApplication.checked:
            self.filterInputCT()

        inputNode = self.CTNode

        self.applyButton.text = "Creating Label Map..."
        # TODO: why doesn't processEvents alone make the label text change?
        self.applyButton.repaint()
        slicer.app.processEvents()

        self.labelNode = slicer.mrmlScene.AddNode(
            slicer.vtkMRMLLabelMapVolumeNode())
        name = inputNode.GetName() + '_partialLungLabelMap'
        self.labelNode.SetName(slicer.mrmlScene.GenerateUniqueName(name))

        self.preProcessingWidget.createPartialLM(inputNode, self.labelNode)

        label_image = self.labelNode.GetImageData()
        shape = list(label_image.GetDimensions())
        input_array = vtk.util.numpy_support.vtk_to_numpy(
            label_image.GetPointData().GetScalars())
        original_shape = input_array.shape
        input_array = input_array.reshape(
            shape[2], shape[1],
            shape[0])  # input_array.transpose([2, 1, 0]) would not work!

        input_image = sitk.GetImageFromArray(input_array)
        input_image.SetSpacing(self.labelNode.GetSpacing())
        input_image.SetOrigin(self.labelNode.GetOrigin())

        my_lung_splitter = lung_splitter(split_thirds=True)
        split_lm = my_lung_splitter.execute(input_image)

        split = sitk.GetArrayFromImage(split_lm)

        input_aa = vtk.util.numpy_support.vtk_to_numpy(
            label_image.GetPointData().GetScalars())

        input_aa[:] = split.reshape(original_shape)

        self.labelNode.StorableModified()
        self.labelNode.Modified()
        self.labelNode.InvokeEvent(
            slicer.vtkMRMLVolumeNode.ImageDataModifiedEvent, self.labelNode)

        SlicerUtil.changeLabelmapOpacity(0.5)
예제 #21
0
 def _checkNewVolume_(self, newVolumeNode):
     if newVolumeNode == self.currentReslicedVolume and newVolumeNode is not None:
         # Only when we have resliced
         self.currentVolumeLoaded = newVolumeNode
         CIP_ParenchymaSubtypeTrainingWidget._checkNewVolume_(
             self, newVolumeNode)
         SlicerUtil.setFiducialsCursorMode(True, True)
         fidNode = slicer.mrmlScene.GetNodeByID(
             slicer.modules.markups.logic().GetActiveListID())
         displayNode = fidNode.GetDisplayNode()
         displayNode.SetTextScale(4)
         # spacing = newVolumeNode.GetName().split("_")[-1]
         self.customFileName = "{}{}".format(newVolumeNode.GetName(),
                                             self.customExtension)
 def getOrCreateLabelmap(self, masterNode):
     labelmapName = "{0}_{1}".format(masterNode.GetName(), self.labelmapNodeNameExtension)
     labelmapNode = slicer.util.getNode(labelmapName)
     if labelmapNode is None:
         # Create a labelmap for this scalar
         labelmapNode = slicer.modules.volumes.logic().CreateAndAddLabelVolume(slicer.mrmlScene, masterNode, labelmapName)
         # Make sure that the labelmap has this name (no suffixes)
         labelmapNode.SetName(labelmapName)
         # Register the labelmap in the case navigator so that it is removed when moving to another case
         if SlicerUtil.isSlicerACILLoaded():
             self.caseNavigatorWidget.registerVolumeId(labelmapNode.GetID())
         SlicerUtil.logDevelop("New label map node created: " + labelmapName, includePythonConsole=True)
     else:
         SlicerUtil.logDevelop("Labelmap loaded", includePythonConsole=True)
     return labelmapNode
예제 #23
0
 def ModifyList(self):
     """Look at each fiducial list in scene and find any fiducials associated
     with one of our volumes but not in in one of our lists.
     Add the fiducial as a landmark and delete it from the other list.
     Return the name of the last added landmark if it exists.
     """
     fiducialsLogic = slicer.modules.markups.logic()
     originalActiveListID = fiducialsLogic.GetActiveListID(
     )  # TODO: naming convention?
     if (SlicerUtil.getNode(originalActiveListID)):
         fiducialList = SlicerUtil.getNode(originalActiveListID)
         fiducialList.SetName(self.name)
         name = self.name
         fiducialList.SetNthFiducialLabel(0, name + "-1")
     else:
         return
예제 #24
0
    def saveResults(self):
        try:
            if SlicerUtil.isSlicerACILLoaded():
                saveResultsRemotely = qt.QMessageBox.question(
                    slicer.util.mainWindow(), "Save volume remotely?",
                    "Do you want to save the results remotely?",
                    qt.QMessageBox.Yes
                    | qt.QMessageBox.No) == qt.QMessageBox.Yes
            else:
                saveResultsRemotely = False
            # First, save locally to the results directory (as a backup)
            labelmap = self.getCurrentLabelMapNode()
            localPath = os.path.join(self.saveResultsDirectoryButton.directory,
                                     labelmap.GetName() + ".nrrd")
            if saveResultsRemotely:
                self.caseNavigatorWidget.uploadVolume(
                    labelmap,
                    callbackFunction=self._uploadFileCallback_,
                    localPath=localPath)
            else:
                slicer.util.saveNode(labelmap, localPath)
                slicer.util.infoDisplay(
                    "Results saved to '{}'".format(localPath))

        except Exception as ex:
            Util.print_last_exception()
            slicer.util.errorDisplay(ex.message)
예제 #25
0
    def onApplyButton(self):
        red_logic = slicer.app.layoutManager().sliceWidget("Red").sliceLogic()
        red_cn = red_logic.GetSliceCompositeNode()
        volumeID = red_cn.GetBackgroundVolumeID()
        CTNode = SlicerUtil.getNode(volumeID)
        if self.labelSelector.currentNode() == None:
            warning = self.preProcessingWidget.warningMessageForLM()
            if warning == 16384:
                labelNode = slicer.mrmlScene.AddNode(
                    slicer.vtkMRMLLabelMapVolumeNode())
                labelNode.SetName(CTNode.GetName() + '_partialLungLabelMap')

                if not CTNode:
                    self.applyButton.enabled = True
                    return False
                if self.preProcessingWidget.filterOnRadioButton.checked:
                    volumesLogic = slicer.modules.volumes.logic()
                    clonedCTNode = volumesLogic.CloneVolume(
                        slicer.mrmlScene, CTNode, 'Cloned Volume')
                    self.filterInputCT(clonedCTNode)
                    self.createLungLabelMap(clonedCTNode, labelNode)
                    slicer.mrmlScene.RemoveNode(clonedCTNode)
                    for color in ['Red', 'Yellow', 'Green']:
                        slicer.app.layoutManager().sliceWidget(
                            color).sliceLogic().GetSliceCompositeNode(
                            ).SetBackgroundVolumeID(CTNode.GetID())
                else:
                    self.createLungLabelMap(CTNode, labelNode)

            else:
                qt.QMessageBox.warning(slicer.util.mainWindow(),
                                       "Parenchyma Analysis",
                                       "Please select a Lung Label Map.")
                self.applyButton.enabled = True
                return False

        self.visualizationWidget.updateScene()

        self.applyButton.text = "Segmenting Lobes..."
        self.applyButton.repaint()
        slicer.app.processEvents()

        logic = CIP_InteractiveLobeSegmentationLogic()

        self.visualizationWidget.pendingUpdate = True
        outputNode = self.outputSelector.currentNode()
        if not outputNode:
            outputNode = slicer.vtkMRMLLabelMapVolumeNode()
            slicer.mrmlScene.AddNode(outputNode)

        fissureVolume = None
        try:
            fissureVolume = logic.run(self.labelSelector.currentNode(),
                                      outputNode)
        except Exception, e:
            import traceback
            traceback.print_exc()
            qt.QMessageBox.warning(
                slicer.util.mainWindow(), "Running", 'Exception!\n\n' +
                str(e) + "\n\nSee Python Console for Stack Trace")
예제 #26
0
    def checkMasterAndLabelMapNodes(self):
        """Set an appropiate MasterNode LabelMapNode to the Editor.
        The options are:
            - There is no masterNode => try to load the one that the user is watching right now, and go on if so.
            - There is masterNode and there is no label map => create a default label map node with the name "MasterNodeName_structuresDetection" and set the StructuresDetectionColorMap
            - There is masterNode and there is label map => check if the name of the label map is "MasterNodeName_structuresDetection".
                - If so: set this one
                - Otherwise: create a new labelmap with the name 'MasterNodeName_structureslabelMap' """
        if self.disableEvents: return  # To avoid infinite loops

        if self.editorWidget.masterVolume:
            masterNode = self.editorWidget.masterVolume
            SlicerUtil.logDevelop(
                "Master node in Editor = " + masterNode.GetName(), True)
        else:
            SlicerUtil.logDevelop(
                "No master node in Editor. Retrieving it from the selector...",
                False)
            masterNode = self.getCurrentGrayscaleNode()

        if not masterNode:
            # There is no any volume node that the user is watching
            SlicerUtil.logDevelop("Still not master node. Exit", False)
            return

        labelmapNode = self.getOrCreateLabelmap(masterNode)
        displayNode = labelmapNode.GetDisplayNode()

        if displayNode:
            displayNode.SetAndObserveColorNodeID(self.colorNode.GetID())
        else:
            SlicerUtil.logDevelop(
                "There is no DisplayNode for label map " +
                labelmapNode.GetName(), True)

        slicer.app.applicationLogic().PropagateVolumeSelection(0)
        SlicerUtil.changeLabelmapOpacity(0.5)

        # Set the right volumes
        self.disableEvents = True
        #self.editorWidget.masterVolume = masterNode
        #self.editorWidget.labelmapVolume = labelmapNode
        # trigger editor events
        self.editorWidget.helper.setVolumes(masterNode, labelmapNode)
        self.disableEvents = False

        slicer.app.applicationLogic().FitSliceToAll()
예제 #27
0
    def __onResliceButtonClicked__(self):
        currentNode = self.volumeSelector.currentNode()
        if currentNode is None:
            slicer.util.warningDisplay("Please select a volume to reslice")
            return
        checkedId = self.sliceSelectionRadioButtonGroup.checkedId()
        if checkedId < 0:
            slicer.util.warningDisplay("Please select a reslicing size")
            return

        spacing = self.sliceMeasurements[checkedId]
        outputNode = self.logic.run_reslicing_CLI(currentNode, spacing)
        # Set active node
        self.volumeSelector.setCurrentNode(outputNode)
        self.currentReslicedVolume = outputNode
        SlicerUtil.setActiveVolumeIds(outputNode.GetID())
        self._checkNewVolume_(outputNode)
예제 #28
0
 def _onMasterNodeSelect_(self, node):
     if node:
         nodeName = node.GetName()
         if self.getCurrentGrayscaleNode() and self.getCurrentGrayscaleNode().GetName() != nodeName:
             SlicerUtil.logDevelop(
                 "There was a selection of a new master node: {0}. Previous: {1}. We will invoke checkMasterAndLabelMapNodes".
                 format(node.GetName(), self.editorWidget.masterVolume.GetName()), includePythonConsole=True)
             # Update Editor Master node to perform the needed actions.
             # We don't use "setVolumes" function because the interface must not be refeshed yet (it will be in checkMasterAndLabelMapNodes)
             self.setCurrentGrayscaleNode(node)
             # Remove label node to refresh the values properly
             self.setCurrentLabelMapNode(None)
             self.checkMasterAndLabelMapNodes()
     else:
         SlicerUtil.logDevelop("No master node selected. Trying to remove label map", False)
         self.editorWidget.cleanVolumes()
     self.setEditorValues()
예제 #29
0
    def createColormapNode(self, colormapName):
        """ Create a colormap node with one color per type (plus Red for artifacts).
        :param colormapName: the colormap node will be named like this
        :return:
        """
        # Types/Regions (2 bytes)
        colorNode = SlicerUtil.createNewColormapNode(colormapName,
                                                     numberOfColors=256**2)

        # Add background
        colorNode.SetColor(0, "Background", 0, 0, 0, 0)

        # Get Slicer GenericColors colormap node as a template
        slicerGenericColors = SlicerUtil.getNode('GenericColors')

        # Add a region and a type/subtype for each allowed combination
        # The regions will not have a special color, the type is the main object
        for typeId, subtypeId in self.__allowedCombinationsTypes__:
            t = subtypeId if subtypeId != 0 else typeId
            color = [0] * 4
            # Get the color from the RandomIntegers colormap
            slicerGenericColors.GetColor(t, color)
            t1 = self.getMainTypeLabel(typeId)
            t2 = self.getSubtypeLabel(subtypeId)

            typeLabel = "{}-{}".format(t1, t2) if subtypeId != 0 else t1
            for regionId in self.regions.iterkeys():
                label = "{}-{}".format(
                    typeLabel,
                    self.regions[regionId][0]) if regionId != 0 else typeLabel
                colorId = (t << 8) + regionId
                colorNode.SetColor(colorId, label, color[0], color[1],
                                   color[2])

        # Add the regions. Use the same Random
        # for region in self.regions.iterkeys():
        #     color = [0] * 4
        #     slicerGenericColors.GetColor(region + 256, color)
        #     colorNode.SetColor(t, self.getRegionLabel(region), color[0], color[1], color[2])

        # Add Red (Artifact)
        # colorNode.SetColor(512, "ARTIFACT", 1.0, 0, 0)

        return colorNode
예제 #30
0
    def __refreshUI__(self):
        """ Show/hide GUI elements based on the current configuration
        """
        # Disable operation if we are comparing MIP and MinIP
        self.operationComboBox.enabled = (self.currentLayout != self.LAYOUT_COMPARE)

        for operation, controls in self.spacingSliderItems.iteritems():
            for elem in controls:
                elem.visible = False
        if self.currentOperation in (self.OPERATION_MIP, self.OPERATION_MinIP, self.OPERATION_MEAN):
            for elem in self.spacingSliderItems[self.currentOperation]:
                elem.visible = True
        elif self.currentOperation == self.OPERATION_MIP_MinIP:
            for elem in self.spacingSliderItems[self.OPERATION_MIP]:
                elem.visible = True
            for elem in self.spacingSliderItems[self.OPERATION_MinIP]:
                elem.visible = True

        SlicerUtil.setCrosshairCursor(self.crosshairCheckbox.isChecked())
예제 #31
0
    def __refreshUI__(self):
        """ Show/hide GUI elements based on the current configuration
        """
        # Disable operation if we are comparing MIP and MinIP
        self.operationComboBox.enabled = self.currentLayout != self.LAYOUT_COMPARE

        for operation, controls in self.spacingSliderItems.iteritems():
            for elem in controls:
                elem.visible = False
        if self.currentOperation in (self.OPERATION_MIP, self.OPERATION_MinIP, self.OPERATION_MEAN):
            for elem in self.spacingSliderItems[self.currentOperation]:
                elem.visible = True
        elif self.currentOperation == self.OPERATION_MIP_MinIP:
            for elem in self.spacingSliderItems[self.OPERATION_MIP]:
                elem.visible = True
            for elem in self.spacingSliderItems[self.OPERATION_MinIP]:
                elem.visible = True

        SlicerUtil.setCrosshairCursor(self.crosshairCheckbox.isChecked())
예제 #32
0
 def createColormapNode(self, nodeName):
     """
     Create a new colormap node for the editor
     @param nodeName:
     """
     colorNode = SlicerUtil.createNewColormapNode(nodeName, numberOfColors=3)
     colorNode.SetColor(0, "Background", 0, 0, 0, 0)
     colorNode.SetColor(1, "Air", 0, 1.0, 0)
     colorNode.SetColor(2, "Blood", 1.0, 0, 0)
     return colorNode
예제 #33
0
    def __checkNewVolume__(self, newVolumeNode):
        """ New volume loaded in the scene in some way.
        If it's really a new volume, try to save and close the current one
        @param newVolumeNode:
        """
        if self.blockNodeEvents:
            return
        self.blockNodeEvents = True
        volume = self.currentVolumeLoaded
        if volume is not None and newVolumeNode is not None \
                and newVolumeNode.GetID() != volume.GetID()  \
                and not self.logic.isVolumeSaved(volume.GetName()):
            # Ask the user if he wants to save the previously loaded volume
            if qt.QMessageBox.question(
                    slicer.util.mainWindow(), "Save results?",
                    "The fiducials for the volume '{0}' have not been saved. Do you want to save them?"
                    .format(volume.GetName()), qt.QMessageBox.Yes
                    | qt.QMessageBox.No) == qt.QMessageBox.Yes:
                self.saveResultsCurrentNode()
        # Remove all the previously existing nodes
        if self.currentVolumeLoaded is not None and newVolumeNode != self.currentVolumeLoaded:
            # Remove previously existing node
            self.logic.removeMarkupsAndNode(self.currentVolumeLoaded)
        if self.caseNavigatorWidget is not None and newVolumeNode is not None:
            # Try to load a previously existing fiducials file downloaded with the ACIL case navigator
            fiducialsFileName = newVolumeNode.GetName(
            ) + Util.file_conventions_extensions[
                "ParenchymaTrainingFiducialsXml"]
            fiducialsNavigatorFilePath = self.caseNavigatorWidget.logic.getFilePath(
                fiducialsFileName)
            if os.path.exists(fiducialsNavigatorFilePath):
                # The fiducials file was downloaded with the navigator
                self.logic.loadFiducialsXml(newVolumeNode,
                                            fiducialsNavigatorFilePath)

        if newVolumeNode is not None:
            SlicerUtil.setActiveVolumeId(newVolumeNode.GetID())
            SlicerUtil.setFiducialsCursorMode(True, True)

        self.currentVolumeLoaded = newVolumeNode
        self.updateState()
        self.blockNodeEvents = False
예제 #34
0
    def resetLayout(self):
        """ Return to the layout that was active when the user loaded the module
        """
        # Remove links
        compNodes = slicer.util.getNodes("vtkMRMLSliceCompositeNode*")
        for compNode in compNodes.itervalues():
            compNode.SetLinkedControl(False)
        SlicerUtil.changeLayout(self.originalLayout)

        # Remove all possible reslicing and set default planes for default 2D windows
        nodes = slicer.util.getNodes("vtkMRMLSliceNode*")
        for node in nodes.itervalues():
            self.__resliceNode__(node, self.currentPlane, self.OPERATION_NONE)
            if node.GetID() == "vtkMRMLSliceNodeRed":
                node.SetOrientationToAxial()
            elif node.GetID() == "vtkMRMLSliceNodeYellow":
                node.SetOrientationToSagittal()
            elif node.GetID() == "vtkMRMLSliceNodeGreen":
                node.SetOrientationToCoronal()
        self.currentLayout = self.LAYOUT_DEFAULT
예제 #35
0
 def onLabelSelect(self, node):
     self.labelNode = node
     self.applyButton.enabled = bool(
         self.CTNode)  # and bool(self.labelNode)
     self.preProcessingWidget.enableFilteringFrame(bool(self.CTNode))
     self.preProcessingWidget.enableLMFrame(bool(not self.labelNode))
     SlicerUtil.changeLabelmapOpacity(0.5)
     if self.labelNode:
         self.preProcessingWidget.filterApplication.setChecked(1)
         self.preProcessingWidget.filterApplication.setEnabled(0)
         for color in ['Red', 'Yellow', 'Green']:
             slicer.app.layoutManager().sliceWidget(color).sliceLogic(
             ).GetSliceCompositeNode().SetLabelVolumeID(
                 self.labelNode.GetID())
     else:
         self.preProcessingWidget.filterApplication.setChecked(0)
         self.preProcessingWidget.filterApplication.setEnabled(1)
         for color in ['Red', 'Yellow', 'Green']:
             slicer.app.layoutManager().sliceWidget(color).sliceLogic(
             ).GetSliceCompositeNode().SetLabelVolumeID('None')
예제 #36
0
    def __init__(self, moduleName, columnNames, filePreffix):
        self.__moduleName__ = moduleName
        p = SlicerUtil.getSettingsDataFolder(moduleName)
        if filePreffix != "":
            self.__csvFilePath__ = os.path.join(p, "{0}.{1}.storage.csv".format(filePreffix, moduleName))
        else:
            self.__csvFilePath__ = os.path.join(p, moduleName + ".storage.csv")
        self.__columnNames__ = columnNames
        self.showWarningWhenIncompleteColumns = True

        self.db = None
예제 #37
0
    def __setContext__(self, context):
        """ Configure the widget for a particular context. Fix operation, plane, layout and optionally number of slices
        :param context: element of "contexts" list
        """
        self.currentContext = context
        # if context == self.CONTEXT_UNKNOWN:
        #     return

        if context == self.CONTEXT_VASCULATURE:
            # MIP, Axial, Side by side
            self.currentLayout = self.__getDefaultLayoutForContext__(context)
            self.currentPlane = self.PLANE_AXIAL
            self.currentOperation = self.OPERATION_MIP
            self.setCurrentSpacingInMm(self.currentOperation, 20)
            SlicerUtil.changeContrastWindow(1400, -500)
        elif context == self.CONTEXT_EMPHYSEMA:
            # MinIP, Axial, Side by side
            self.currentLayout = self.__getDefaultLayoutForContext__(context)
            self.currentPlane = self.PLANE_AXIAL
            self.currentOperation = self.OPERATION_MinIP
            self.setCurrentSpacingInMm(self.currentOperation, 5)
            SlicerUtil.changeContrastWindow(1400, -500)

        self.executeCurrentSettings()
예제 #38
0
    def executeCurrentSettings(self):
        """ Based on the current GUI settings, configure the viewer.
        It also forces some GUI decisions for incompatible settings (example: comparing operations in a 3x3 layout)
        """
        # Active volumes
        compNode = slicer.mrmlScene.GetNodeByID("vtkMRMLSliceCompositeNodeRed")
        backgroundVolumeID = compNode.GetBackgroundVolumeID()
        if backgroundVolumeID is None:
            # No volumes are active. Nothing to do
            return
        labelmapVolumeID = compNode.GetLabelVolumeID()
        foregroundVolumeID = compNode.GetForegroundVolumeID()

        # Unlink all the controls (the link will be done manually)
        compNodes = slicer.util.getNodes("vtkMRMLSliceCompositeNode*")
        for compNode in compNodes.itervalues():
            compNode.SetLinkedControl(False)

        if self.currentOperation == self.OPERATION_MIP_MinIP or self.currentLayout == self.LAYOUT_COMPARE:
            # Compare MIP-MinIP. Force GUI
            self.currentLayout = self.LAYOUT_COMPARE
            self.currentOperation = self.OPERATION_MIP_MinIP
            SlicerUtil.changeLayout(self.currentLayout)
            # Red window
            sliceNode = slicer.mrmlScene.GetNodeByID("vtkMRMLSliceNodeRed")
            sliceNode.SetOrientation(self.planes[self.currentPlane])
            self.__resliceNode__(sliceNode, self.currentPlane, self.OPERATION_NONE)
            # Bottom-left (Yellow). MIP
            sliceNode = slicer.mrmlScene.GetNodeByID("vtkMRMLSliceNodeYellow")
            sliceNode.SetOrientation(self.planes[self.currentPlane])
            self.__resliceNode__(sliceNode, self.currentPlane, self.OPERATION_MIP)
            # Bottom-right (Green). MinIP
            sliceNode = slicer.mrmlScene.GetNodeByID("vtkMRMLSliceNodeGreen")
            sliceNode.SetOrientation(self.planes[self.currentPlane])
            self.__resliceNode__(sliceNode, self.currentPlane, self.OPERATION_MinIP)
        else:
            # Set the layout and later the operation
            SlicerUtil.changeLayout(self.currentLayout)
            if self.currentLayout == self.LAYOUT_RED_ONLY:
                # Red window
                sliceNode = slicer.mrmlScene.GetNodeByID("vtkMRMLSliceNodeRed")
                sliceNode.SetOrientation(self.planes[self.currentPlane])
                self.__resliceNode__(sliceNode, self.currentPlane, self.currentOperation)
            elif self.currentLayout == self.LAYOUT_SIDE_BY_SIDE:
                # Red window
                sliceNode = slicer.mrmlScene.GetNodeByID("vtkMRMLSliceNodeRed")
                sliceNode.SetOrientation(self.planes[self.currentPlane])
                self.__resliceNode__(sliceNode, self.currentPlane, self.OPERATION_NONE)
                # Yellow window
                sliceNode = slicer.mrmlScene.GetNodeByID("vtkMRMLSliceNodeYellow")
                sliceNode.SetOrientation(self.planes[self.currentPlane])
                self.__resliceNode__(sliceNode, self.currentPlane, self.currentOperation)
            elif self.currentLayout == self.LAYOUT_THREE_OVER_THREE:
                # Top row (no reslice)
                sliceNode = slicer.mrmlScene.GetNodeByID("vtkMRMLSliceNodeRed")
                sliceNode.SetOrientationToAxial()
                self.__resliceNode__(sliceNode, self.PLANE_AXIAL, self.OPERATION_NONE)
                sliceNode = slicer.mrmlScene.GetNodeByID("vtkMRMLSliceNodeYellow")
                sliceNode.SetOrientationToSagittal()
                self.__resliceNode__(sliceNode, self.PLANE_SAGITTAL, self.OPERATION_NONE)
                sliceNode = slicer.mrmlScene.GetNodeByID("vtkMRMLSliceNodeGreen")
                sliceNode.SetOrientationToCoronal()
                self.__resliceNode__(sliceNode, self.PLANE_CORONAL, self.OPERATION_NONE)
                # Bottom row (reslice)
                sliceNode = slicer.mrmlScene.GetNodeByID("vtkMRMLSliceNodeSlice4")
                sliceNode.SetOrientationToAxial()
                self.__resliceNode__(sliceNode, self.PLANE_AXIAL, self.currentOperation)
                sliceNode = slicer.mrmlScene.GetNodeByID("vtkMRMLSliceNodeSlice5")
                sliceNode.SetOrientationToSagittal()
                self.__resliceNode__(sliceNode, self.PLANE_SAGITTAL, self.currentOperation)
                sliceNode = slicer.mrmlScene.GetNodeByID("vtkMRMLSliceNodeSlice6")
                sliceNode.SetOrientationToCoronal()
                self.__resliceNode__(sliceNode, self.PLANE_CORONAL, self.currentOperation)

        # Make sure that the same volume is displayed in all 2D windows
        compNodes = slicer.util.getNodes("vtkMRMLSliceCompositeNode*")
        for compNode in compNodes.itervalues():
            compNode.SetLabelVolumeID(labelmapVolumeID)
            compNode.SetForegroundVolumeID(foregroundVolumeID)
            compNode.SetBackgroundVolumeID(backgroundVolumeID)

        # Relink all the controls
        compNodes = slicer.util.getNodes("vtkMRMLSliceCompositeNode*")
        for compNode in compNodes.itervalues():
            compNode.SetLinkedControl(True)

        # Refresh windows to show changes
        SlicerUtil.refreshActiveWindows()
        self.__refreshUI__()
예제 #39
0
    def setup(self):
        """This is called one time when the module GUI is initialized
        """
        ScriptedLoadableModuleWidget.setup(self)

        # Create objects that can be used anywhere in the module. Example: in most cases there should be just one
        # object of the logic class
        self.logic = CIP_PAARatioLogic()

        #
        # Create all the widgets. Example Area
        mainAreaCollapsibleButton = ctk.ctkCollapsibleButton()
        mainAreaCollapsibleButton.text = "Main parameters"
        self.layout.addWidget(mainAreaCollapsibleButton)
        self.mainAreaLayout = qt.QGridLayout(mainAreaCollapsibleButton)

        self.label = qt.QLabel("Select the volume")
        self.label.setStyleSheet("margin:10px 0 20px 7px")
        self.mainAreaLayout.addWidget(self.label, 0, 0)

        self.volumeSelector = slicer.qMRMLNodeComboBox()
        self.volumeSelector.nodeTypes = ("vtkMRMLScalarVolumeNode", "")
        # DEPRECATED. Now there is a new vtkMRMLLabelMapNode
        # self.volumeSelector.addAttribute( "vtkMRMLScalarVolumeNode", "LabelMap", "0" )  # No labelmaps
        self.volumeSelector.selectNodeUponCreation = True
        self.volumeSelector.autoFillBackground = True
        self.volumeSelector.addEnabled = True
        self.volumeSelector.noneEnabled = False
        self.volumeSelector.removeEnabled = False
        self.volumeSelector.showHidden = False
        self.volumeSelector.showChildNodeTypes = False
        self.volumeSelector.setMRMLScene(slicer.mrmlScene)
        self.volumeSelector.setStyleSheet("margin:0px 0 0px 0; padding:2px 0 2px 5px")
        self.mainAreaLayout.addWidget(self.volumeSelector, 0, 1)

        # self.label2 = qt.QLabel("Select the slice")
        # self.label2.setStyleSheet("margin:0px 0 20px 7px; padding-top:20px")
        # self.mainAreaLayout.addWidget(self.label2, 1, 0)

        self.placeDefaultRulersButton = ctk.ctkPushButton()
        self.placeDefaultRulersButton.text = "Place default rulers"
        # self.placeDefaultRulersSliceButton.toolTip = "Navigate to the best estimated slice to place the rulers"
        self.placeDefaultRulersButton.setIcon(qt.QIcon("{0}/next.png".format(SlicerUtil.CIP_ICON_DIR)))
        self.placeDefaultRulersButton.setIconSize(qt.QSize(20, 20))
        self.placeDefaultRulersButton.setStyleSheet("font-weight: bold;")
        # self.placeDefaultRulersButton.setFixedWidth(140)
        self.mainAreaLayout.addWidget(self.placeDefaultRulersButton, 1, 1)

        ### Structure Selector
        self.structuresGroupbox = qt.QGroupBox("Select the structure")
        self.groupboxLayout = qt.QVBoxLayout()
        self.structuresGroupbox.setLayout(self.groupboxLayout)
        self.mainAreaLayout.addWidget(self.structuresGroupbox, 2, 0)

        self.structuresButtonGroup = qt.QButtonGroup()
        # btn = qt.QRadioButton("None")
        # btn.visible = False
        # self.structuresButtonGroup.addButton(btn)
        # self.groupboxLayout.addWidget(btn)

        btn = qt.QRadioButton("Both")
        btn.checked = True
        self.structuresButtonGroup.addButton(btn, 0)
        self.groupboxLayout.addWidget(btn)

        btn = qt.QRadioButton("Pulmonary Arterial")
        self.structuresButtonGroup.addButton(btn, 1)
        self.groupboxLayout.addWidget(btn)

        btn = qt.QRadioButton("Aorta")
        self.structuresButtonGroup.addButton(btn, 2)
        self.groupboxLayout.addWidget(btn)

        ### Buttons toolbox
        self.buttonsToolboxFrame = qt.QFrame()
        self.buttonsToolboxLayout = qt.QGridLayout()
        self.buttonsToolboxFrame.setLayout(self.buttonsToolboxLayout)
        self.mainAreaLayout.addWidget(self.buttonsToolboxFrame, 2, 1)

        self.placeRulersButton = ctk.ctkPushButton()
        self.placeRulersButton.text = "Place ruler/s"
        self.placeRulersButton.toolTip = "Place the ruler/s for the selected structure/s in the current slice"
        self.placeRulersButton.setIcon(qt.QIcon("{0}/ruler.png".format(SlicerUtil.CIP_ICON_DIR)))
        self.placeRulersButton.setIconSize(qt.QSize(20, 20))
        self.placeRulersButton.setFixedWidth(105)
        self.placeRulersButton.setStyleSheet("font-weight:bold")
        self.buttonsToolboxLayout.addWidget(self.placeRulersButton, 0, 0)

        self.moveUpButton = ctk.ctkPushButton()
        self.moveUpButton.text = "Move up"
        self.moveUpButton.toolTip = "Move the selected ruler/s one slice up"
        self.moveUpButton.setIcon(qt.QIcon("{0}/move_up.png".format(SlicerUtil.CIP_ICON_DIR)))
        self.moveUpButton.setIconSize(qt.QSize(20, 20))
        self.moveUpButton.setFixedWidth(95)
        self.buttonsToolboxLayout.addWidget(self.moveUpButton, 0, 1)

        self.moveDownButton = ctk.ctkPushButton()
        self.moveDownButton.text = "Move down"
        self.moveDownButton.toolTip = "Move the selected ruler/s one slice down"
        self.moveDownButton.setIcon(qt.QIcon("{0}/move_down.png".format(SlicerUtil.CIP_ICON_DIR)))
        self.moveDownButton.setIconSize(qt.QSize(20, 20))
        self.moveDownButton.setFixedWidth(95)
        self.buttonsToolboxLayout.addWidget(self.moveDownButton, 0, 2)

        self.removeButton = ctk.ctkPushButton()
        self.removeButton.text = "Remove ALL rulers"
        self.removeButton.toolTip = "Remove all the rulers for this volume"
        self.removeButton.setIcon(qt.QIcon("{0}/delete.png".format(SlicerUtil.CIP_ICON_DIR)))
        self.removeButton.setIconSize(qt.QSize(20, 20))
        self.buttonsToolboxLayout.addWidget(self.removeButton, 1, 1, 1, 2, 2)

        ### Textboxes
        self.textboxesFrame = qt.QFrame()
        self.textboxesLayout = qt.QFormLayout()
        self.textboxesFrame.setLayout(self.textboxesLayout)
        self.textboxesFrame.setFixedWidth(190)
        self.mainAreaLayout.addWidget(self.textboxesFrame, 3, 0)

        self.paTextBox = qt.QLineEdit()
        self.paTextBox.setReadOnly(True)
        self.textboxesLayout.addRow("PA (mm):  ", self.paTextBox)

        self.aortaTextBox = qt.QLineEdit()
        self.aortaTextBox.setReadOnly(True)
        self.textboxesLayout.addRow("Aorta (mm):  ", self.aortaTextBox)

        self.ratioTextBox = qt.QLineEdit()
        self.ratioTextBox.setReadOnly(True)
        self.textboxesLayout.addRow("Ratio PA/A: ", self.ratioTextBox)

        # Save case data
        self.reportsCollapsibleButton = ctk.ctkCollapsibleButton()
        self.reportsCollapsibleButton.text = "Reporting"
        self.layout.addWidget(self.reportsCollapsibleButton)
        self.reportsLayout = qt.QHBoxLayout(self.reportsCollapsibleButton)

        self.storedColumnNames = [
            "caseId",
            "paDiameter_mm",
            "aortaDiameter_mm",
            "pa1r",
            "pa1a",
            "pa1s",
            "pa2r",
            "pa2a",
            "pa2s",
            "a1r",
            "a1a",
            "a1s",
            "a2r",
            "a2a",
            "a2s",
        ]
        self.reportsWidget = CaseReportsWidget(
            "CIP_PAARatio", columnNames=self.storedColumnNames, parentWidget=self.reportsCollapsibleButton
        )
        self.reportsWidget.setup()

        self.switchToRedView()

        #####
        # Case navigator
        if SlicerUtil.isSlicerACILLoaded():
            caseNavigatorAreaCollapsibleButton = ctk.ctkCollapsibleButton()
            caseNavigatorAreaCollapsibleButton.text = "Case navigator"
            self.layout.addWidget(caseNavigatorAreaCollapsibleButton, 0x0020)
            # caseNavigatorLayout = qt.QVBoxLayout(caseNavigatorAreaCollapsibleButton)

            # Add a case list navigator
            from ACIL.ui import CaseNavigatorWidget

            self.caseNavigatorWidget = CaseNavigatorWidget(self.moduleName, caseNavigatorAreaCollapsibleButton)
            self.caseNavigatorWidget.setup()

        self.layout.addStretch()

        # Connections
        self.observers = []
        self.__addSceneObservables__()

        self.volumeSelector.connect("currentNodeChanged(vtkMRMLNode*)", self.onVolumeSelectorChanged)
        self.placeDefaultRulersButton.connect("clicked()", self.oPlaceDefaultRulersClicked)
        self.placeRulersButton.connect("clicked()", self.onPlaceRulersClicked)
        self.moveUpButton.connect("clicked()", self.onMoveUpRulerClicked)
        self.moveDownButton.connect("clicked()", self.onMoveDownRulerClicked)
        self.removeButton.connect("clicked()", self.onRemoveRulerClicked)

        self.reportsWidget.addObservable(self.reportsWidget.EVENT_SAVE_BUTTON_CLICKED, self.onSaveReport)
예제 #40
0
    def setup(self):
        """Init the widget """
        self.modulePath = SlicerUtil.getModuleFolder("CIP_GetImage")
        
        self.resourcesPath = os.path.join(self.modulePath, "CIP_GetImage_Resources")
        self.StudyId = ""


        
        self.logic = CIP_GetImageLogic(self.modulePath)
        
        # Widget to load cases faster
        self.loadSaveDatabuttonsWidget = CIPUI.LoadSaveDataWidget(parentWidget=self.parent)
        self.loadSaveDatabuttonsWidget.setup(moduleName="CIP_GetImage")
        
        #
        # Obligatory parameters area
        #
        parametersCollapsibleButton = ctk.ctkCollapsibleButton()
        parametersCollapsibleButton.text = "Image data"
        self.layout.addWidget(parametersCollapsibleButton)        
        parametersFormLayout = qt.QFormLayout(parametersCollapsibleButton)
        
        # Study radio buttons
        label = qt.QLabel()
        label.text = "Select the study:"
        parametersFormLayout.addRow(label)        
        
        self.rbgStudy=qt.QButtonGroup() 
        
        for key in self.studyIds:
            rbStudyid = qt.QRadioButton(key)
            self.rbgStudy.addButton(rbStudyid)     
            parametersFormLayout.addWidget(rbStudyid)        
         
        self.txtOtherStudy = qt.QLineEdit()
        self.txtOtherStudy.hide()
        parametersFormLayout.addWidget(self.txtOtherStudy)

        
        # Case id 
        self.txtCaseId = qt.QLineEdit()        
        parametersFormLayout.addRow("Case ID     ", self.txtCaseId)
        
        # Image types
        label = qt.QLabel()
        label.text = "Select the images that you want to load:"
        parametersFormLayout.addRow(label)
        
        self.cbsImageTypes = []
        for key in self.imageTypes:            
            check = qt.QCheckBox()
            check.checked = True
            check.setText(key)
            parametersFormLayout.addWidget(check)
            self.cbsImageTypes.append(check) 
        
        # Label maps    
        label = qt.QLabel()
        label.text = "Select the label maps that you want to load:"
        parametersFormLayout.addRow(label)
        
        # Labelmap types checkboxes
        self.cbsLabelMapTypes = []
        for key in self.labelMapTypes:            
            check = qt.QCheckBox()
            check.setText(key)
            check.checked = self.labelMapTypes[key][0]            
            parametersFormLayout.addWidget(check)        
            self.cbsLabelMapTypes.append(check)         
        
        
        # Load image Button        
        self.downloadButton = qt.QPushButton("Download")                
        self.downloadButton.toolTip = "Load the image"        
        #self.downloadButton.enabled = False
        self.downloadButton.setStyleSheet("background-color: green; font-weight:bold; color:white" )
        parametersFormLayout.addRow(self.downloadButton)
        self.downloadButton.connect('clicked (bool)', self.onDownloadButton)
                

        # Information message
        self.lblDownloading = qt.QLabel()
        self.lblDownloading.text = "Downloading images. Please wait..."
        self.lblDownloading.hide()
        parametersFormLayout.addRow(self.lblDownloading)        
        
        
        #
        # Optional Parameters
        #
        optionalParametersCollapsibleButton = ctk.ctkCollapsibleButton()
        optionalParametersCollapsibleButton.text = "Optional parameters"
        self.layout.addWidget(optionalParametersCollapsibleButton)
        optionalParametersFormLayout = qt.QFormLayout(optionalParametersCollapsibleButton)
     
        # Local storage (Slicer temporary path)                
        self.localStoragePath = "{0}/CIP".format(slicer.app.temporaryPath)        
        if not os.path.exists(self.localStoragePath):            
            os.makedirs(self.localStoragePath)
            # Make sure that everybody has write permissions (sometimes there are problems because of umask)
            os.chmod(self.localStoragePath, 0777)
            
        self.storagePathButton = ctk.ctkDirectoryButton()
        self.storagePathButton.directory = self.localStoragePath

        optionalParametersFormLayout.addRow("Local directory: ", self.storagePathButton)     
        
        # Connection type (SSH, "normal")
        label = qt.QLabel()
        label.text = "Connection type:"
        optionalParametersFormLayout.addRow(label)
        
        self.rbgConnectionType=qt.QButtonGroup() 
        self.rbSSH = qt.QRadioButton("SSH (secure connection)")
        self.rbSSH.setChecked(True)
        self.rbgConnectionType.addButton(self.rbSSH)        
        optionalParametersFormLayout.addWidget(self.rbSSH)
        
        self.rbCP = qt.QRadioButton("Common")
        self.rbgConnectionType.addButton(self.rbCP)
        optionalParametersFormLayout.addWidget(self.rbCP)    
        
     
        
        # SSH Server login
        self.txtServer = qt.QLineEdit()
        s = SlicerUtil.settingGetOrSetDefault("CIP_GetImage", "server", "This is your ssh user and server. Example: [email protected]")
        self.txtServer.text = s     # This is your ssh user and server. Example: [email protected]"
        optionalParametersFormLayout.addRow("Server:", self.txtServer)

        # Server root path
        self.txtServerpath = qt.QLineEdit()
        s = SlicerUtil.settingGetOrSetDefault("CIP_GetImage", "serverRootPath", "This is your root path to search for files. Ex: /Cases/Processed")
        self.txtServerpath.text = s     # This is your root path to search for files. Ex: /Cases/Processed
        optionalParametersFormLayout.addRow("Server root path:", self.txtServerpath)
        
                
        # SSH Private key    
        self.txtPrivateKeySSH = qt.QLineEdit()        
        s = SlicerUtil.settingGetOrSetDefault("CIP_GetImage", "sshKey", "")
        self.txtPrivateKeySSH.text = s # this is the full path to your ssh key if you need it. Be aware of Unix/Windows comaptibility (hint: use os.path.join)
                                        # Please notice that you won't need a SSH key if your computer already has one locally installed"
        optionalParametersFormLayout.addRow("SSH private key (leave blank for computer's default):     ", self.txtPrivateKeySSH)
        
        # Cache mode 
        self.cbCacheMode = qt.QCheckBox("Cache mode activated")
        self.cbCacheMode.setChecked(True)     # Cache mode is activated by default
        optionalParametersFormLayout.addRow("", self.cbCacheMode)        
        
        # Clean cache Button        
        self.cleanCacheButton = qt.QPushButton("Clean cache")                
        self.cleanCacheButton.toolTip = "Remove all the local cached files"
        optionalParametersFormLayout.addRow(self.cleanCacheButton)
        optionalParametersCollapsibleButton.collapsed = True

        if SlicerUtil.IsDevelopment:
            # reload button
            self.reloadButton = qt.QPushButton("Reload (just development)")
            self.reloadButton.toolTip = "Reload this module (for development purposes)."
            self.reloadButton.name = "Reload"
            self.layout.addWidget(self.reloadButton)
            self.reloadButton.connect('clicked()', self.onReload)

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


        # Connections
        self.rbgStudy.connect("buttonClicked (QAbstractButton*)", self.onRbStudyClicked)
        self.txtOtherStudy.connect("textEdited (QString)", self.onTxtOtherStudyEdited)
        self.rbgConnectionType.connect("buttonClicked (QAbstractButton*)", self.onRbgConnectionType)         
        
        self.storagePathButton.connect("directorySelected(QString)", self.onTmpDirChanged)
        self.cleanCacheButton.connect('clicked (bool)', self.onCleanCacheButtonClicked)
예제 #41
0
 def getRootAnnotationsNode(self):
     """ Get the root annotations node global to the scene, creating it if necessary
     :return: "All Annotations" vtkMRMLAnnotationHierarchyNode
     """
     return SlicerUtil.getRootAnnotationsNode()
예제 #42
0
 def saveSettings(self):
     """Save the current values in settings to reuse it in future sessions"""
     SlicerUtil.setSetting("CIP_GetImage", "sshKey", self.txtPrivateKeySSH.text)
     SlicerUtil.setSetting("CIP_GetImage", "server", self.txtServer.text)
     SlicerUtil.setSetting("CIP_GetImage", "serverRootPath", self.txtServerpath.text)
 def __onSaveResultsDirectoryChanged__(self, directory):
     # f = qt.QFileDialog.getExistingDirectory()
     # if f:
     #     self.saveResultsDirectoryText.setText(f)
     SlicerUtil.setSetting(self.moduleName, "SaveResultsDirectory", directory)
예제 #44
0
    def setup(self):
        """This is called one time when the module GUI is initialized
        """
        # Declare ALL the GUI components (depending on the context we will add different ones to the layout)
        self.widgetMainFrame = qt.QFrame()
        self.widgetMainLayout = qt.QGridLayout()
        self.widgetMainFrame.setLayout(self.widgetMainLayout)
        self.layout.addWidget(self.widgetMainFrame)

        ## Context
        self.contextLabel = qt.QLabel("Context")
        self.contextComboBox = qt.QComboBox()
        for context in self.contexts.itervalues():
            self.contextComboBox.addItem(context)

        ## Operation
        self.operationLabel = qt.QLabel("Optimization")
        self.operationComboBox = qt.QComboBox()
        for operation in self.operations.itervalues():
            if operation != self.OPERATION_NONE:
                self.operationComboBox.addItem(operation)
        ## Plane
        self.planeLabel = qt.QLabel("Plane")
        # Buttons group
        self.planesButtonGroup = qt.QButtonGroup()
        # Axial
        self.axialButton = qt.QPushButton()
        self.axialButton.setCheckable(True)
        self.axialButton.toolTip = "Axial plane"
        self.axialButton.setFixedSize(40, 40)
        self.axialButton.setIcon(SlicerUtil.getIcon("axial.png"))
        self.planesButtonGroup.addButton(self.axialButton, self.PLANE_AXIAL)
        # Sagittal
        self.sagittalButton = qt.QPushButton()
        self.sagittalButton.setCheckable(True)
        self.sagittalButton.toolTip = "Sagittal plane"
        self.sagittalButton.setFixedSize(40, 40)
        self.sagittalButton.setIcon(SlicerUtil.getIcon("sagittal.png"))
        self.widgetMainLayout.addWidget(self.sagittalButton, 2, 2, SlicerUtil.ALIGNMENT_HORIZONTAL_CENTER)
        self.planesButtonGroup.addButton(self.sagittalButton, self.PLANE_SAGITTAL)
        # Coronal
        self.coronalButton = qt.QPushButton()
        self.coronalButton.setCheckable(True)
        self.coronalButton.toolTip = "coronal plane"
        self.coronalButton.setFixedSize(40, 40)
        self.coronalButton.setIcon(SlicerUtil.getIcon("coronal.png"))
        self.planesButtonGroup.addButton(self.coronalButton, self.PLANE_CORONAL)
        # Null button (to uncheck all)
        self.nullPlaneButton = qt.QPushButton()
        self.nullPlaneButton.setCheckable(True)
        self.planesButtonGroup.addButton(self.nullPlaneButton, -1)
        # Buttons labels
        self.axialButtonLabel = qt.QLabel("Axial")
        self.axialButtonLabel.setStyleSheet("margin-bottom: 10px")
        self.sagittalButtonLabel = qt.QLabel("Sagittal")
        self.sagittalButtonLabel.setStyleSheet("margin-bottom: 10px")
        self.coronalButtonLabel = qt.QLabel("Coronal")
        self.coronalButtonLabel.setStyleSheet("margin-bottom: 10px")

        ## Layout
        self.layoutLabel = qt.QLabel("Layout")
        # Buttons group
        self.layoutsButtonGroup = qt.QButtonGroup()
        # Single slice Button
        self.singleSlideViewButton = qt.QPushButton()
        self.singleSlideViewButton.setCheckable(True)
        self.singleSlideViewButton.toolTip = "Single slice view"
        self.singleSlideViewButton.setFixedSize(40, 40)
        self.singleSlideViewButton.setIcon(qt.QIcon(":/Icons/LayoutOneUpRedSliceView.png"))
        self.layoutsButtonGroup.addButton(self.singleSlideViewButton, self.LAYOUT_RED_ONLY)
        # Side by side Button
        self.sideBySideViewButton = qt.QPushButton()
        self.sideBySideViewButton.setCheckable(True)
        self.sideBySideViewButton.toolTip = "Side by side view"
        self.sideBySideViewButton.setFixedSize(40, 40)
        self.sideBySideViewButton.setIcon(qt.QIcon(":/Icons/LayoutSideBySideView.png"))
        self.layoutsButtonGroup.addButton(self.sideBySideViewButton, self.LAYOUT_SIDE_BY_SIDE)
        # Three over three button
        self.threeOverThreeViewButton = qt.QPushButton()
        self.threeOverThreeViewButton.setCheckable(True)
        self.threeOverThreeViewButton.toolTip = "Compare 2 images in their 3 planes"
        self.threeOverThreeViewButton.setFixedSize(40, 40)
        self.threeOverThreeViewButton.setIcon(qt.QIcon(":/Icons/LayoutThreeOverThreeView.png"))
        self.layoutsButtonGroup.addButton(self.threeOverThreeViewButton, self.LAYOUT_THREE_OVER_THREE)
        # Comparative MIP-MinIP button
        self.maxMinCompareViewButton = qt.QPushButton()
        self.maxMinCompareViewButton.setCheckable(True)
        self.maxMinCompareViewButton.toolTip = "MIP and MinIP comparison"
        self.maxMinCompareViewButton.setFixedSize(40, 40)
        self.maxMinCompareViewButton.setIcon(qt.QIcon(":/Icons/LayoutFourUpView.png"))
        self.layoutsButtonGroup.addButton(self.maxMinCompareViewButton, self.LAYOUT_COMPARE)
        # Null button (to uncheck all)
        self.nullLayoutButton = qt.QPushButton()
        self.nullLayoutButton.setCheckable(True)
        self.layoutsButtonGroup.addButton(self.nullLayoutButton, -2)
        # Reset Button
        self.resetViewButton = qt.QPushButton()
        self.resetViewButton.toolTip = "Go back to the original layout"
        self.resetViewButton.setFixedSize(40, 40)
        # self.resetViewButton.setIconSize(qt.QSize(24, 24))
        self.resetViewButton.setIcon(qt.QIcon(os.path.join(SlicerUtil.CIP_ICON_DIR, "Reload.png")))
        # Buttons labels
        self.singleSlideButtonLabel = qt.QLabel("Single")
        self.sideBySideButtonLabel = qt.QLabel("Side by side")
        self.threeOverThreeButtonLabel = qt.QLabel("3x3")
        self.maxMinCompareButtonLabel = qt.QLabel("MIP+MinIP")
        self.resetLabel = qt.QLabel("Reset")
        self.resetLabel.setStyleSheet("font-weight: bold")

        # Number of slices (different for each operation). The size of the slider also changes
        self.spacingSliderItems = OrderedDict()
        spacingLabel = qt.QLabel("Slice size " + self.operations[self.OPERATION_MIP])
        spacingSlider = qt.QSlider()
        spacingSlider.orientation = 1
        spacingSlider.setTickPosition(2)
        spacingSlider.minimum = 0
        spacingSlider.maximum = 1000
        spacingSlider.setPageStep(50)
        spacingMmLabel = qt.QLabel()
        self.spacingSliderItems[self.OPERATION_MIP] = (spacingLabel, spacingSlider, spacingMmLabel)
        self.setCurrentSpacingInMm(self.OPERATION_MIP, 20)

        spacingLabel = qt.QLabel("Slice size " + self.operations[self.OPERATION_MinIP])
        spacingSlider = qt.QSlider()
        spacingSlider.orientation = 1
        spacingSlider.setTickPosition(2)
        spacingSlider.minimum = 0
        spacingSlider.maximum = 200
        spacingSlider.setPageStep(50)
        spacingMmLabel = qt.QLabel()
        self.spacingSliderItems[self.OPERATION_MinIP] = (spacingLabel, spacingSlider, spacingMmLabel)
        self.setCurrentSpacingInMm(self.OPERATION_MinIP, 5)

        spacingLabel = qt.QLabel("Slice size " + self.operations[self.OPERATION_MEAN])
        spacingSlider = qt.QSlider()
        spacingSlider.orientation = 1
        spacingSlider.setTickPosition(2)
        spacingSlider.minimum = 0
        spacingSlider.maximum = 200
        spacingSlider.setPageStep(50)
        spacingMmLabel = qt.QLabel()
        self.spacingSliderItems[self.OPERATION_MEAN] = (spacingLabel, spacingSlider, spacingMmLabel)
        self.setCurrentSpacingInMm(self.OPERATION_MEAN, 20)

        # Crosshair
        self.crosshairCheckbox = qt.QCheckBox()
        self.crosshairCheckbox.setText("Crosshair cursor")
        self.crosshairCheckbox.toolTip = "Activate/Desactivate the crosshair cursor for a better visualization"
        self.crosshairCheckbox.setStyleSheet("margin-top:10px")

        # Center button
        self.centerButton = qt.QPushButton()
        self.centerButton.setText("Center volumes")
        self.centerButton.setFixedSize(100, 40)
        self.centerButton.setStyleSheet("margin-top:10px")

        if self.fullModeOn:
            ###### FULL MODE
            # Context
            self.widgetMainLayout.addWidget(self.contextLabel, 0, 0)
            self.widgetMainLayout.addWidget(self.contextComboBox, 0, 1, 1, 3)
            # Operation
            self.widgetMainLayout.addWidget(self.operationLabel, 1, 0)
            self.widgetMainLayout.addWidget(self.operationComboBox, 1, 1, 1, 3)
            # Plane
            self.widgetMainLayout.addWidget(self.planeLabel, 2, 0)
            self.widgetMainLayout.addWidget(self.axialButton, 2, 1, SlicerUtil.ALIGNMENT_HORIZONTAL_CENTER)
            self.widgetMainLayout.addWidget(self.coronalButton, 2, 3, SlicerUtil.ALIGNMENT_HORIZONTAL_CENTER)
            self.widgetMainLayout.addWidget(self.axialButtonLabel, 3, 1, SlicerUtil.ALIGNMENT_HORIZONTAL_CENTER)
            self.widgetMainLayout.addWidget(self.sagittalButtonLabel, 3, 2, SlicerUtil.ALIGNMENT_HORIZONTAL_CENTER)
            self.widgetMainLayout.addWidget(self.coronalButtonLabel, 3, 3, SlicerUtil.ALIGNMENT_HORIZONTAL_CENTER)
            # Layout
            self.widgetMainLayout.addWidget(self.layoutLabel, 4, 0)
            self.widgetMainLayout.addWidget(self.singleSlideViewButton, 4, 1, SlicerUtil.ALIGNMENT_HORIZONTAL_CENTER)
            self.widgetMainLayout.addWidget(self.sideBySideViewButton, 4, 2, SlicerUtil.ALIGNMENT_HORIZONTAL_CENTER)
            self.widgetMainLayout.addWidget(self.threeOverThreeViewButton, 4, 3, SlicerUtil.ALIGNMENT_HORIZONTAL_CENTER)
            self.widgetMainLayout.addWidget(self.maxMinCompareViewButton, 4, 4, SlicerUtil.ALIGNMENT_HORIZONTAL_CENTER)
            self.widgetMainLayout.addWidget(self.resetViewButton, 4, 5, SlicerUtil.ALIGNMENT_HORIZONTAL_CENTER)
            self.widgetMainLayout.addWidget(self.singleSlideButtonLabel, 5, 1, SlicerUtil.ALIGNMENT_HORIZONTAL_CENTER)
            self.widgetMainLayout.addWidget(self.sideBySideButtonLabel, 5, 2, SlicerUtil.ALIGNMENT_HORIZONTAL_CENTER)
            self.widgetMainLayout.addWidget(
                self.threeOverThreeButtonLabel, 5, 3, SlicerUtil.ALIGNMENT_HORIZONTAL_CENTER
            )
            self.widgetMainLayout.addWidget(self.maxMinCompareButtonLabel, 5, 4, SlicerUtil.ALIGNMENT_HORIZONTAL_CENTER)
            self.widgetMainLayout.addWidget(self.resetLabel, 5, 5, SlicerUtil.ALIGNMENT_HORIZONTAL_CENTER)
            # Number of slices
            row = 6
            for structure in self.spacingSliderItems.itervalues():
                self.widgetMainLayout.addWidget(structure[0], row, 0, 1, 2)
                self.widgetMainLayout.addWidget(structure[1], row, 2, 1, 3)
                self.widgetMainLayout.addWidget(structure[2], row, 5)
                row += 1
            self.widgetMainLayout.addWidget(self.crosshairCheckbox, row, 0, 1, 2)
            self.crosshairCheckbox.setChecked(True)
            self.widgetMainLayout.addWidget(self.centerButton, row, 2, 1, 2)

        else:
            ##### COLLAPSED MODE
            # Plane
            self.widgetMainLayout.addWidget(self.planeLabel, 0, 0)
            self.widgetMainLayout.addWidget(self.axialButton, 0, 1, SlicerUtil.ALIGNMENT_HORIZONTAL_CENTER)
            self.widgetMainLayout.addWidget(self.sagittalButton, 0, 2, SlicerUtil.ALIGNMENT_HORIZONTAL_CENTER)
            self.widgetMainLayout.addWidget(self.coronalButton, 0, 3, SlicerUtil.ALIGNMENT_HORIZONTAL_CENTER)
            self.widgetMainLayout.addWidget(self.threeOverThreeViewButton, 0, 4, SlicerUtil.ALIGNMENT_HORIZONTAL_CENTER)
            self.widgetMainLayout.addWidget(self.axialButtonLabel, 1, 1, SlicerUtil.ALIGNMENT_HORIZONTAL_CENTER)
            self.widgetMainLayout.addWidget(self.sagittalButtonLabel, 1, 2, SlicerUtil.ALIGNMENT_HORIZONTAL_CENTER)
            self.widgetMainLayout.addWidget(self.coronalButtonLabel, 1, 3, SlicerUtil.ALIGNMENT_HORIZONTAL_CENTER)
            self.widgetMainLayout.addWidget(
                self.threeOverThreeButtonLabel, 1, 4, SlicerUtil.ALIGNMENT_HORIZONTAL_CENTER
            )
            # Number of slices
            row = 2
            for structure in self.spacingSliderItems.itervalues():
                self.widgetMainLayout.addWidget(structure[0], row, 0)
                self.widgetMainLayout.addWidget(structure[1], row, 1, 1, 3)
                self.widgetMainLayout.addWidget(structure[2], row, 4)
                row += 1
            self.widgetMainLayout.addWidget(self.crosshairCheckbox, row, 0)
            self.widgetMainLayout.addWidget(self.centerButton, row, 1, 1, 2)

        self.layout.addStretch(1)

        self.__refreshUI__()

        # Connections
        self.contextComboBox.connect("currentIndexChanged (int)", self.__onContextIndexChanged__)
        self.operationComboBox.connect("currentIndexChanged (int)", self.__onOperationIndexChanged__)
        self.planesButtonGroup.connect("buttonClicked(int)", self.__onPlaneButtonClicked__)
        self.singleSlideViewButton.connect("clicked()", self.__onSingleSlideButtonClicked__)
        self.sideBySideViewButton.connect("clicked()", self.__onSideBySideButtonClicked__)
        self.threeOverThreeViewButton.connect("clicked()", self.__onThreeOverThreeViewButtonClicked__)
        self.maxMinCompareViewButton.connect("clicked()", self.__onMaxMinCompareViewButtonClicked__)
        self.resetViewButton.connect("clicked()", self.__onResetViewButtonClicked__)
        for slicer in (item[1] for item in self.spacingSliderItems.itervalues()):
            slicer.connect("valueChanged(int)", self.__onNumberOfSlicesChanged__)
        self.crosshairCheckbox.connect("stateChanged(int)", self.__onCrosshairCheckChanged__)
        self.centerButton.connect("clicked()", self.__onCenterButtonClicked__)
    def setup(self):
        """This is called one time when the module GUI is initialized
        """
        ScriptedLoadableModuleWidget.setup(self)

        # Create objects that can be used anywhere in the module. Example: in most cases there should be just one
        # object of the logic class
        self.logic = CIP_ParenchymaSubtypeTrainingLogic()
        self.currentVolumeLoaded = None
        self.blockNodeEvents = False

        ##########
        # Main area
        self.mainAreaCollapsibleButton = ctk.ctkCollapsibleButton()
        self.mainAreaCollapsibleButton.text = "Main area"
        self.layout.addWidget(self.mainAreaCollapsibleButton, SlicerUtil.ALIGNMENT_VERTICAL_TOP)
        self.mainLayout = qt.QGridLayout(self.mainAreaCollapsibleButton)

        # Node selector
        volumeLabel = qt.QLabel("Active volume: ")
        volumeLabel.setStyleSheet("margin-left:5px")
        self.mainLayout.addWidget(volumeLabel, 0, 0)
        self.volumeSelector = slicer.qMRMLNodeComboBox()
        self.volumeSelector.nodeTypes = ("vtkMRMLScalarVolumeNode", "")
        self.volumeSelector.selectNodeUponCreation = True
        self.volumeSelector.autoFillBackground = True
        self.volumeSelector.addEnabled = False
        self.volumeSelector.noneEnabled = False
        self.volumeSelector.removeEnabled = False
        self.volumeSelector.showHidden = False
        self.volumeSelector.showChildNodeTypes = False
        self.volumeSelector.setMRMLScene(slicer.mrmlScene)
        self.volumeSelector.setFixedWidth(250)
        self.volumeSelector.setStyleSheet("margin: 15px 0")
        #self.volumeSelector.selectNodeUponCreation = False
        self.mainLayout.addWidget(self.volumeSelector, 0, 1, 1, 3)

        labelsStyle = "font-weight: bold; margin: 0 0 5px 5px;"
        # Types Radio Buttons
        typesLabel = qt.QLabel("Select the type")
        typesLabel.setStyleSheet(labelsStyle)
        typesLabel.setFixedHeight(15)
        self.mainLayout.addWidget(typesLabel, 1, 0)
        self.typesFrame = qt.QFrame()
        self.typesLayout = qt.QVBoxLayout(self.typesFrame)
        self.mainLayout.addWidget(self.typesFrame, 2, 0, SlicerUtil.ALIGNMENT_VERTICAL_TOP)
        self.typesRadioButtonGroup = qt.QButtonGroup()
        for key in self.logic.params.mainTypes.iterkeys():
            rbitem = qt.QRadioButton(self.logic.params.getMainTypeLabel(key))
            self.typesRadioButtonGroup.addButton(rbitem, key)
            self.typesLayout.addWidget(rbitem)
        self.typesRadioButtonGroup.buttons()[0].setChecked(True)

        # Subtypes Radio buttons
        subtypesLabel = qt.QLabel("Select the subtype")
        subtypesLabel.setStyleSheet(labelsStyle)
        subtypesLabel.setFixedHeight(15)
        self.mainLayout.addWidget(subtypesLabel, 1, 1)
        self.subtypesRadioButtonGroup = qt.QButtonGroup()
        self.subtypesFrame = qt.QFrame()
        self.subtypesFrame.setMinimumHeight(275)
        self.subtypesLayout = qt.QVBoxLayout(self.subtypesFrame)
        self.subtypesLayout.setAlignment(SlicerUtil.ALIGNMENT_VERTICAL_TOP)
        self.subtypesLayout.setStretch(0, 0)
        self.mainLayout.addWidget(self.subtypesFrame, 2, 1, SlicerUtil.ALIGNMENT_VERTICAL_TOP)     # Put the frame in the top
        # The content will be loaded dynamically every time the main type is modified

        # Artifact radio buttons
        self.artifactsLabel = qt.QLabel("Artifact")
        self.artifactsLabel.setStyleSheet(labelsStyle)
        self.artifactsLabel.setFixedHeight(15)
        self.mainLayout.addWidget(self.artifactsLabel, 1, 2)
        #self.mainLayout.addWidget(qt.QLabel("Select the artifact"), 1, 1)
        self.artifactsRadioButtonGroup = qt.QButtonGroup()
        self.artifactsFrame = qt.QFrame()
        self.artifactsLayout = qt.QVBoxLayout(self.artifactsFrame)
        self.mainLayout.addWidget(self.artifactsFrame, 2, 2, SlicerUtil.ALIGNMENT_VERTICAL_TOP)
        self.artifactsRadioButtonGroup = qt.QButtonGroup()
        for artifactId in self.logic.params.artifacts.iterkeys():
            rbitem = qt.QRadioButton(self.logic.params.getArtifactLabel(artifactId))
            self.artifactsRadioButtonGroup.addButton(rbitem, artifactId)
            self.artifactsLayout.addWidget(rbitem)
        self.artifactsRadioButtonGroup.buttons()[0].setChecked(True)

        # Load caselist button
        self.loadButton = ctk.ctkPushButton()
        self.loadButton.text = "Load fiducials file"
        self.loadButton.setIcon(qt.QIcon("{0}/open_file.png".format(SlicerUtil.CIP_ICON_DIR)))
        self.loadButton.setIconSize(qt.QSize(20, 20))
        self.loadButton.setFixedWidth(135)
        self.mainLayout.addWidget(self.loadButton, 3, 0)

        # Remove fiducial button
        self.removeLastFiducialButton = ctk.ctkPushButton()
        self.removeLastFiducialButton.text = "Remove last fiducial"
        self.removeLastFiducialButton.toolTip = "Remove the last fiducial added"
        self.removeLastFiducialButton.setIcon(qt.QIcon("{0}/delete.png".format(SlicerUtil.CIP_ICON_DIR)))
        self.removeLastFiducialButton.setIconSize(qt.QSize(20, 20))
        self.removeLastFiducialButton.setFixedWidth(200)
        self.mainLayout.addWidget(self.removeLastFiducialButton, 3, 1)

        # Save results button
        self.saveResultsButton = ctk.ctkPushButton()
        self.saveResultsButton.setText("Save markups")
        self.saveResultsButton.toolTip = "Save the markups in the specified directory"
        self.saveResultsButton.setIcon(qt.QIcon("{0}/Save.png".format(SlicerUtil.CIP_ICON_DIR)))
        self.saveResultsButton.setIconSize(qt.QSize(20,20))
        self.mainLayout.addWidget(self.saveResultsButton, 4, 0)

        # Save results directory button
        defaultPath = os.path.join(SlicerUtil.getSettingsDataFolder(self.moduleName), "Results")     # Assign a default path for the results
        path = SlicerUtil.settingGetOrSetDefault(self.moduleName, "SaveResultsDirectory", defaultPath)
        self.saveResultsDirectoryButton = ctk.ctkDirectoryButton()
        self.saveResultsDirectoryButton.directory = path
        self.saveResultsDirectoryButton.setMaximumWidth(375)
        self.mainLayout.addWidget(self.saveResultsDirectoryButton, 4, 1, 1, 2)

        #####
        # Case navigator
        if SlicerUtil.isSlicerACILLoaded():
            caseNavigatorAreaCollapsibleButton = ctk.ctkCollapsibleButton()
            caseNavigatorAreaCollapsibleButton.text = "Case navigator"
            self.layout.addWidget(caseNavigatorAreaCollapsibleButton, 0x0020)
            # caseNavigatorLayout = qt.QVBoxLayout(caseNavigatorAreaCollapsibleButton)

            # Add a case list navigator
            from ACIL.ui import CaseNavigatorWidget
            self.caseNavigatorWidget = CaseNavigatorWidget(self.moduleName, caseNavigatorAreaCollapsibleButton)
            self.caseNavigatorWidget.setup()
            # Listen for the event of loading volume
            #self.caseNavigatorWidget.addObservable(self.caseNavigatorWidget.EVENT_VOLUME_LOADED, self.onNewVolumeLoaded)

        self.layout.addStretch()

        self.updateState()

        # Connections
        self.typesRadioButtonGroup.connect("buttonClicked (QAbstractButton*)", self.__onTypesRadioButtonClicked__)
        self.subtypesRadioButtonGroup.connect("buttonClicked (QAbstractButton*)", self.__onSubtypesRadioButtonClicked__)
        self.artifactsRadioButtonGroup.connect("buttonClicked (QAbstractButton*)", self.__onSubtypesRadioButtonClicked__)

        self.volumeSelector.connect('currentNodeChanged(vtkMRMLNode*)', self.__onCurrentNodeChanged__)
        self.loadButton.connect('clicked()', self.openFiducialsFile)
        self.removeLastFiducialButton.connect('clicked()', self.__onRemoveLastFiducialButtonClicked__)
        # self.saveResultsOpenDirectoryDialogButton.connect('clicked()', self.onOpenDirectoryDialogButtonClicked)
        self.saveResultsDirectoryButton.connect("directoryChanged (str)", self.__onSaveResultsDirectoryChanged__)
        self.saveResultsButton.connect('clicked()', self.__onSaveResultsButtonClicked__)

        self.observers = []
        self.observers.append(slicer.mrmlScene.AddObserver(slicer.vtkMRMLScene.NodeAddedEvent, self.__onNodeAddedObserver__))
        self.observers.append(slicer.mrmlScene.AddObserver(slicer.vtkMRMLScene.EndCloseEvent, self.__onSceneClosed__))
예제 #46
0
 def __onCenterButtonClicked__(self):
     SlicerUtil.centerAllVolumes()
예제 #47
0
 def __onCrosshairCheckChanged__(self, checkedState):
     SlicerUtil.setCrosshairCursor(self.crosshairCheckbox.isChecked())