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
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)
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
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
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
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)
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
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)
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()
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)
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()
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
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)
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)
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')
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)
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
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
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)
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")
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()
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)
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()
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
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())
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())
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
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
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
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')
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
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()
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__()
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)
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)
def getRootAnnotationsNode(self): """ Get the root annotations node global to the scene, creating it if necessary :return: "All Annotations" vtkMRMLAnnotationHierarchyNode """ return SlicerUtil.getRootAnnotationsNode()
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)
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__))
def __onCenterButtonClicked__(self): SlicerUtil.centerAllVolumes()
def __onCrosshairCheckChanged__(self, checkedState): SlicerUtil.setCrosshairCursor(self.crosshairCheckbox.isChecked())