def __init__(self, parent=None, parameterNode=None, parameter=None, colorNode=None, selectCommand=None): self.colorNode = colorNode self.parameterNode = parameterNode self.parameter = parameter self.selectCommand = selectCommand self.recents = [] self.label = None if not parent: self.parent = slicer.qMRMLWidget() self.parent.setObjectName('EditMRMLWidget') self.parent.setLayout(qt.QVBoxLayout()) self.parent.setMRMLScene(slicer.mrmlScene) self.create() p = qt.QCursor().pos() self.parent.setGeometry(p.x(), p.y(), 300, 700) self.parent.show() self.parent.raise_() else: self.parent = parent self.create()
def createReadOnlyLineEdit(): le = qt.QLineEdit() le.readOnly = True le.frame = False le.styleSheet = "QLineEdit { background:transparent; }" le.cursor = qt.QCursor(qt.Qt.IBeamCursor) return le
def cursorForEffect(self, effectName): """Return an instance of QCursor customized for the given effectName. TODO: this could be moved to the EffectTool class so that effects can manage per-widget cursors, possibly turning them off or making them dynamic """ if not effectName in self.effectCursors: baseImage = qt.QImage(":/Icons/AnnotationPointWithArrow.png") effectImage = qt.QImage(self.effectIconFiles[effectName]) width = max(baseImage.width(), effectImage.width()) pad = -9 height = pad + baseImage.height() + effectImage.height() width = height = max(width, height) center = int(width / 2) cursorImage = qt.QImage(width, height, qt.QImage().Format_ARGB32) painter = qt.QPainter() cursorImage.fill(0) painter.begin(cursorImage) point = qt.QPoint(center - (baseImage.width() / 2), 0) painter.drawImage(point, baseImage) point.setX(center - (effectImage.width() / 2)) point.setY(cursorImage.height() - effectImage.height()) painter.drawImage(point, effectImage) painter.end() cursorPixmap = qt.QPixmap() cursorPixmap = cursorPixmap.fromImage(cursorImage) self.effectCursors[effectName] = qt.QCursor( cursorPixmap, center, 0) return self.effectCursors[effectName]
def labelSelectDialog(self): """label table dialog""" if not self.labelSelect: self.labelSelect = qt.QFrame() self.labelSelect.setLayout( qt.QVBoxLayout() ) self.labelPromptLabel = qt.QLabel() self.labelSelect.layout().addWidget( self.labelPromptLabel ) self.labelSelectorFrame = qt.QFrame() self.labelSelectorFrame.setLayout( qt.QHBoxLayout() ) self.labelSelect.layout().addWidget( self.labelSelectorFrame ) self.labelSelectorLabel = qt.QLabel() self.labelPromptLabel.setText( "Label Map: " ) self.labelSelectorFrame.layout().addWidget( self.labelSelectorLabel ) self.labelSelector = slicer.qMRMLNodeComboBox() self.labelSelector.nodeTypes = ( "vtkMRMLScalarVolumeNode", "" ) self.labelSelector.addAttribute( "vtkMRMLScalarVolumeNode", "LabelMap", "1" ) # todo addAttribute self.labelSelector.selectNodeUponCreation = False self.labelSelector.addEnabled = False self.labelSelector.noneEnabled = False self.labelSelector.removeEnabled = False self.labelSelector.showHidden = False self.labelSelector.showChildNodeTypes = False self.labelSelector.setMRMLScene( slicer.mrmlScene ) self.labelSelector.setToolTip( "Pick the label map to edit" ) self.labelSelectorFrame.layout().addWidget( self.labelSelector ) self.labelButtonFrame = qt.QFrame() self.labelButtonFrame.setLayout( qt.QHBoxLayout() ) self.labelSelect.layout().addWidget( self.labelButtonFrame ) self.labelDialogApply = qt.QPushButton("Apply", self.labelButtonFrame) self.labelDialogApply.setToolTip( "Use currently selected label node." ) self.labelButtonFrame.layout().addWidget(self.labelDialogApply) self.labelDialogCancel = qt.QPushButton("Cancel", self.labelButtonFrame) self.labelDialogCancel.setToolTip( "Cancel current operation." ) self.labelButtonFrame.layout().addWidget(self.labelDialogCancel) self.labelButtonFrame.layout().addStretch(1) self.labelDialogCreate = qt.QPushButton("Create New...", self.labelButtonFrame) self.labelDialogCreate.setToolTip( "Cancel current operation." ) self.labelButtonFrame.layout().addWidget(self.labelDialogCreate) self.labelDialogApply.connect("clicked()", self.onLabelDialogApply) self.labelDialogCancel.connect("clicked()", self.labelSelect.hide) self.labelDialogCreate.connect("clicked()", self.onLabelDialogCreate) self.labelPromptLabel.setText( "Select existing label map volume to edit." ) p = qt.QCursor().pos() self.labelSelect.setGeometry(p.x(), p.y(), 400, 200) self.labelSelect.show()
def cursorOff(self, widget): """Turn off and save the current cursor so the user can see an overlay that tracks the mouse""" if self.savedWidget == widget: return else: self.cursorOn() self.savedWidget = widget self.savedCursor = widget.cursor qt_BlankCursor = 10 widget.setCursor(qt.QCursor(qt_BlankCursor))
def enterFloatingMode(self): self.mainFrame.setParent(None) cursorPosition = qt.QCursor().pos() w = self.mainFrame.width h = self.mainFrame.height self.mainFrame.pos = qt.QPoint(cursorPosition.x() - w/2, cursorPosition.y() - h/2) self.mainFrame.show() self.mainFrame.raise_() Key_Space = 0x20 # not in PythonQt self.toggleShortcut = qt.QShortcut(self.mainFrame) self.toggleShortcut.setKey( qt.QKeySequence(Key_Space) ) self.toggleShortcut.connect( 'activated()', self.toggleFloatingMode )
def registerPlanCtToCbctLandmark(self, planCtFiducialListID, cbctFiducialListID): try: qt.QApplication.setOverrideCursor(qt.QCursor(qt.Qt.BusyCursor)) parametersFiducial = {} parametersFiducial["fixedLandmarks"] = cbctFiducialListID parametersFiducial["movingLandmarks"] = planCtFiducialListID # Create linear transform which will store the registration transform try: cbctToPlanTransformNode = slicer.util.getNode( self.cbctToPlanTransformName) except: cbctToPlanTransformNode = slicer.vtkMRMLLinearTransformNode() slicer.mrmlScene.AddNode(cbctToPlanTransformNode) cbctToPlanTransformNode.SetName(self.cbctToPlanTransformName) parametersFiducial[ "saveTransform"] = cbctToPlanTransformNode.GetID() parametersFiducial["transformType"] = "Rigid" # Run fiducial registration fiducialRegistration = slicer.modules.fiducialregistration cliFiducialRegistrationRigidNode = None cliFiducialRegistrationRigidNode = slicer.cli.run( fiducialRegistration, None, parametersFiducial) waitCount = 0 while cliFiducialRegistrationRigidNode.GetStatusString( ) != 'Completed' and waitCount < 200: self.delayDisplay( "Register PLANCT to CBCT using fiducial registration... %d" % waitCount) waitCount += 1 self.delayDisplay( "Register PLANCT to CBCT using fiducial registration finished") qt.QApplication.restoreOverrideCursor() # Apply transform to PLANCT fiducials planCtFiducialsNode = slicer.mrmlScene.GetNodeByID( planCtFiducialListID) planCtFiducialsNode.SetAndObserveTransformNodeID( cbctToPlanTransformNode.GetID()) return [ cbctToPlanTransformNode, cliFiducialRegistrationRigidNode.GetParameterAsString('rms') ] except Exception as e: import traceback traceback.print_exc()
def registerPlanCtToCbctAutomatic(self, planCtVolumeID, cbctVolumeID): try: qt.QApplication.setOverrideCursor(qt.QCursor(qt.Qt.BusyCursor)) parametersRigid = {} parametersRigid["fixedVolume"] = cbctVolumeID parametersRigid["movingVolume"] = planCtVolumeID parametersRigid["useRigid"] = True parametersRigid["initializeTransformMode"] = "useGeometryAlign" parametersRigid["samplingPercentage"] = 0.0005 parametersRigid[ "maximumStepLength"] = 15 # Start with long-range translations parametersRigid["relaxationFactor"] = 0.8 # Relax quickly parametersRigid["translationScale"] = 1000000 # Suppress rotation # parametersRigid["backgroundFillValue"] = -1000.0 # Set output transform try: cbctToPlanTransformNode = slicer.util.getNode( self.cbctToPlanTransformName) except: cbctToPlanTransformNode = slicer.vtkMRMLLinearTransformNode() slicer.mrmlScene.AddNode(cbctToPlanTransformNode) cbctToPlanTransformNode.SetName(self.cbctToPlanTransformName) parametersRigid["linearTransform"] = cbctToPlanTransformNode.GetID( ) # Runs the brainsfit registration brainsFit = slicer.modules.brainsfit cliBrainsFitRigidNode = None cliBrainsFitRigidNode = slicer.cli.run(brainsFit, None, parametersRigid) waitCount = 0 while cliBrainsFitRigidNode.GetStatusString( ) != 'Completed' and waitCount < 200: self.delayDisplay( "Register PlanCT to CBCT using rigid registration... %d" % waitCount) waitCount += 1 self.delayDisplay( "Register PlanCT to CBCT using rigid registration finished") qt.QApplication.restoreOverrideCursor() # Invert output transform (planToCbct) to get the desired cbctToPlan transform cbctToPlanTransformNode.GetMatrixTransformToParent().Invert() return cbctToPlanTransformNode except Exception as e: import traceback traceback.print_exc()
def __init__(self, parent): print("Initializing paint") self.painting = False self.parent = parent self.crosshairNode = slicer.util.getNode('Crosshair') self.crosshairNode.AddObserver( slicer.vtkMRMLCrosshairNode.CursorPositionModifiedEvent, self.onMouseMoved) self.myArray = [] #slicer.util.array(self.parent.labelNode.GetID()) #self.editUtil = EditorLib.EditUtil.EditUtil() for e in [ "LeftButtonPressEvent", "LeftButtonReleaseEvent", "MouseMoveEvent" ]: print("Adding observer to interactor: " + e) self.parent.AddObserver(e, self.processEvent, 1.0) cursorPosition = qt.QCursor().pos() print(cursorPosition.x(), cursorPosition.y())
def __init__(self): ''' Constructor ''' """ path=slicer.modules.usguidedprocedure.path modulePath=os.path.dirname(path) loadedDataGUIfile=os.path.join(modulePath,"USGuidedWizard/loadedData.ui") f = qt.QFile(loadedDataGUIfile) #f = qt.QFile('C:/Users/Usuario/devel/slicelets/USGuidedProcedure/USGuidedWizard/fiducials.ui') f.open(qt.QFile.ReadOnly) loader = qt.QUiLoader() self.loadedDataWidget = loader.load(f) f.close() """ # UI from QtDesigner ----------------------------------------------------------------------------- path=slicer.modules.stylusbasedusprobecalibration.path modulePath=os.path.dirname(path) fiducialsStepGUIfile=os.path.join(modulePath,"GUI/fiducials.ui") f = qt.QFile(fiducialsStepGUIfile) #f = qt.QFile('C:/Users/Usuario/devel/slicelets/USGuidedProcedure/USGuidedWizard/fiducials.ui') f.open(qt.QFile.ReadOnly) loader = qt.QUiLoader() self.fiducialsWidget = loader.load(f) f.close() # connect signals and slots self.fiducialsWidget.fiducialsList.connect('cellChanged(int ,int )', self.onFiducialNameChanged) self.fiducialsWidget.placeFiducialButton.connect('clicked(bool)', self.onPlaceFiducialButtomClicked) self.fiducialsWidget.removeFiducialButton.connect('clicked(bool)', self.onRemoveFiducialButtonClicked) self.fiducialsWidget.clearFiducialsListButton.connect('clicked(bool)', self.onClearFiducialsListButtonClicked) self.fiducialsWidget.fiducialsList.itemClicked.connect(self.onFiducialsListClicked) #listeners #self.listenToAnnotations() self.updatingList = False self.placeImageFiducialStep=False pixmap=qt.QPixmap("Resources/Icons/AnnotationPointWithArrow.png") self.placeFiducialCursor= qt.QCursor(pixmap)
def calibrate(self, measuredVolumeID): qt.QApplication.setOverrideCursor(qt.QCursor(qt.Qt.BusyCursor)) import time start = time.time() measuredVolume = slicer.util.getNode(measuredVolumeID) calibratedVolume = slicer.vtkMRMLScalarVolumeNode() calibratedVolumeName = measuredVolume.GetName() + '_Calibrated' calibratedVolumeName = slicer.mrmlScene.GenerateUniqueName( calibratedVolumeName) calibratedVolume.SetName(calibratedVolumeName) slicer.mrmlScene.AddNode(calibratedVolume) measuredImageDataCopy = vtk.vtkImageData() measuredImageDataCopy.DeepCopy(measuredVolume.GetImageData()) calibratedVolume.SetAndObserveImageData(measuredImageDataCopy) calibratedVolume.CopyOrientation(measuredVolume) if measuredVolume.GetParentTransformNode() != None: calibratedVolume.SetAndObserveTransformNodeID( measuredVolume.GetParentTransformNode().GetID()) coefficients = numpy_support.numpy_to_vtk( self.calibrationPolynomialCoefficients) if slicer.modules.geldosimetryanalysisalgo.logic( ).ApplyPolynomialFunctionOnVolume(calibratedVolume, coefficients) == False: logging.error('Calibration failed') slicer.mrmlScene.RemoveNode(calibratedVolume) return None end = time.time() qt.QApplication.restoreOverrideCursor() logging.info( 'Calibration of MEASURED volume is successful (time: {0})'.format( end - start)) return calibratedVolume
def __init__(self, parent=None, parameterNode=None, parameter=None, colorNode=None, selectCommand=None): self.colorNode = colorNode self.parameterNode = parameterNode self.parameter = parameter self.selectCommand = selectCommand self.showRecents = False # TODO: make a group for recents for visual feedback (otherwise confusing) self.recents = [] self.label = None if not parent: self.parent = slicer.qMRMLWidget() self.parent.setLayout(qt.QVBoxLayout()) self.parent.setMRMLScene(slicer.mrmlScene) self.create() p = qt.QCursor().pos() self.parent.setGeometry(p.x(), p.y(), 300, 700) self.parent.show() else: self.parent = parent self.create()
def setup(self): # Instantiate and connect widgets ... self.RingOff = None self.RingOn = None # Tags to manage event observers self.tagSourceNode = None self.tagDestinationNode = None ##################### ## For debugging ## ## Reload and Test area reloadCollapsibleButton = ctk.ctkCollapsibleButton() reloadCollapsibleButton.text = "Reload && Test" self.layout.addWidget(reloadCollapsibleButton) reloadFormLayout = qt.QFormLayout(reloadCollapsibleButton) ## reload button ## (use this during development, but remove it when delivering ## your module to users) self.reloadButton = qt.QPushButton("Reload") self.reloadButton.toolTip = "Reload this module." self.reloadButton.name = "CurveMaker Reload" reloadFormLayout.addWidget(self.reloadButton) self.reloadButton.connect('clicked()', self.onReload) ## ##################### # # Parameters Area # parametersCollapsibleButton = ctk.ctkCollapsibleButton() parametersCollapsibleButton.text = "Parameters" self.layout.addWidget(parametersCollapsibleButton) # Layout within the dummy collapsible button parametersFormLayout = qt.QFormLayout(parametersCollapsibleButton) # # Source points (vtkMRMLMarkupsFiducialNode) # self.SourceSelector = slicer.qMRMLNodeComboBox() self.SourceSelector.nodeTypes = (("vtkMRMLMarkupsFiducialNode"), "") self.SourceSelector.addEnabled = True self.SourceSelector.removeEnabled = False self.SourceSelector.noneEnabled = True self.SourceSelector.showHidden = False self.SourceSelector.renameEnabled = True self.SourceSelector.showChildNodeTypes = False self.SourceSelector.setMRMLScene(slicer.mrmlScene) self.SourceSelector.setToolTip( "Pick up a Markups node listing fiducials.") parametersFormLayout.addRow("Source points: ", self.SourceSelector) # # Target point (vtkMRMLMarkupsFiducialNode) # self.DestinationSelector = slicer.qMRMLNodeComboBox() self.DestinationSelector.nodeTypes = (("vtkMRMLModelNode"), "") self.DestinationSelector.addEnabled = True self.DestinationSelector.removeEnabled = False self.DestinationSelector.noneEnabled = True self.DestinationSelector.showHidden = False self.DestinationSelector.renameEnabled = True self.DestinationSelector.selectNodeUponCreation = True self.DestinationSelector.showChildNodeTypes = False self.DestinationSelector.setMRMLScene(slicer.mrmlScene) self.DestinationSelector.setToolTip("Pick up or create a Model node.") parametersFormLayout.addRow("Curve model: ", self.DestinationSelector) # # Radius for the tube # self.RadiusSliderWidget = ctk.ctkSliderWidget() self.RadiusSliderWidget.singleStep = 1.0 self.RadiusSliderWidget.minimum = 1.0 self.RadiusSliderWidget.maximum = 50.0 self.RadiusSliderWidget.value = 5.0 self.RadiusSliderWidget.setToolTip("Set the raidus of the tube.") parametersFormLayout.addRow("Radius (mm): ", self.RadiusSliderWidget) # # Radio button to select interpolation method # self.InterpolationLayout = qt.QHBoxLayout() self.InterpolationNone = qt.QRadioButton("None") self.InterpolationCardinalSpline = qt.QRadioButton("Cardinal Spline") self.InterpolationHermiteSpline = qt.QRadioButton( "Hermite Spline (for Endoscopy)") self.InterpolationLayout.addWidget(self.InterpolationNone) self.InterpolationLayout.addWidget(self.InterpolationCardinalSpline) self.InterpolationLayout.addWidget(self.InterpolationHermiteSpline) self.InterpolationGroup = qt.QButtonGroup() self.InterpolationGroup.addButton(self.InterpolationNone) self.InterpolationGroup.addButton(self.InterpolationCardinalSpline) self.InterpolationGroup.addButton(self.InterpolationHermiteSpline) parametersFormLayout.addRow("Interpolation: ", self.InterpolationLayout) # # Interpolation Resolution # self.InterpResolutionSliderWidget = ctk.ctkSliderWidget() self.InterpResolutionSliderWidget.singleStep = 1.0 self.InterpResolutionSliderWidget.minimum = 3.0 self.InterpResolutionSliderWidget.maximum = 50.0 self.InterpResolutionSliderWidget.value = 25.0 self.InterpResolutionSliderWidget.setToolTip( "Number of interpolation points between control points. Default is 25." ) parametersFormLayout.addRow("Resolution: ", self.InterpResolutionSliderWidget) # # Radio button for ring mode # self.RingLayout = qt.QHBoxLayout() self.RingOff = qt.QRadioButton("Off") self.RingOn = qt.QRadioButton("On") self.RingLayout.addWidget(self.RingOff) self.RingLayout.addWidget(self.RingOn) self.RingGroup = qt.QButtonGroup() self.RingGroup.addButton(self.RingOff) self.RingGroup.addButton(self.RingOn) parametersFormLayout.addRow("Ring mode: ", self.RingLayout) # # Check box to start curve visualization # self.EnableAutoUpdateCheckBox = qt.QCheckBox() self.EnableAutoUpdateCheckBox.checked = 0 self.EnableAutoUpdateCheckBox.setToolTip( "If checked, the CurveMaker module keeps updating the model as the points are updated." ) parametersFormLayout.addRow("Auto update:", self.EnableAutoUpdateCheckBox) # # Button to generate a curve # self.GenerateButton = qt.QPushButton("Generate Curve") self.GenerateButton.toolTip = "Generate Curve" self.GenerateButton.enabled = True parametersFormLayout.addRow("", self.GenerateButton) # Connections self.InterpolationNone.connect('clicked(bool)', self.onSelectInterpolationNone) self.InterpolationCardinalSpline.connect( 'clicked(bool)', self.onSelectInterpolationCardinalSpline) self.InterpolationHermiteSpline.connect( 'clicked(bool)', self.onSelectInterpolationHermiteSpline) self.RingOff.connect('clicked(bool)', self.onRingOff) self.RingOn.connect('clicked(bool)', self.onRingOn) self.EnableAutoUpdateCheckBox.connect('toggled(bool)', self.onEnableAutoUpdate) self.SourceSelector.connect("currentNodeChanged(vtkMRMLNode*)", self.onSourceSelected) self.DestinationSelector.connect("currentNodeChanged(vtkMRMLNode*)", self.onDestinationSelected) self.RadiusSliderWidget.connect("valueChanged(double)", self.onTubeUpdated) self.InterpResolutionSliderWidget.connect( "valueChanged(double)", self.onInterpResolutionUpdated) self.GenerateButton.connect('clicked(bool)', self.onGenerateCurve) # Set default ## default interpolation method self.InterpolationCardinalSpline.setChecked(True) self.onSelectInterpolationCardinalSpline(True) ## default ring mode self.RingOff.setChecked(True) self.onRingOff(True) # # Curve Length area # lengthCollapsibleButton = ctk.ctkCollapsibleButton() lengthCollapsibleButton.text = "Length" self.layout.addWidget(lengthCollapsibleButton) lengthFormLayout = qt.QFormLayout(lengthCollapsibleButton) lengthCollapsibleButton.collapsed = True #-- Curve length self.lengthLineEdit = qt.QLineEdit() self.lengthLineEdit.text = '--' self.lengthLineEdit.readOnly = True self.lengthLineEdit.frame = True self.lengthLineEdit.styleSheet = "QLineEdit { background:transparent; }" self.lengthLineEdit.cursor = qt.QCursor(qt.Qt.IBeamCursor) lengthFormLayout.addRow("Curve Length (mm):", self.lengthLineEdit) # # Distance Area # distanceCollapsibleButton = ctk.ctkCollapsibleButton() distanceCollapsibleButton.text = "Distance" distanceCollapsibleButton.collapsed = True self.layout.addWidget(distanceCollapsibleButton) distanceFormLayout = qt.QFormLayout(distanceCollapsibleButton) #-- Point-to-curve distance # - Markups selector for input points distanceLayout = qt.QVBoxLayout() self.targetFiducialsSelector = slicer.qMRMLNodeComboBox() self.targetFiducialsSelector.nodeTypes = (( "vtkMRMLMarkupsFiducialNode"), "") self.targetFiducialsSelector.selectNodeUponCreation = True self.targetFiducialsSelector.addEnabled = True self.targetFiducialsSelector.removeEnabled = True self.targetFiducialsSelector.noneEnabled = True self.targetFiducialsSelector.showHidden = False self.targetFiducialsSelector.showChildNodeTypes = False self.targetFiducialsSelector.setMRMLScene(slicer.mrmlScene) self.targetFiducialsSelector.setToolTip("Select Markups for targets") distanceLayout.addWidget(self.targetFiducialsSelector) self.targetFiducialsNode = None self.tagDestinationDispNode = None self.targetFiducialsSelector.connect( "currentNodeChanged(vtkMRMLNode*)", self.onTargetFiducialsSelected) self.fiducialsTable = qt.QTableWidget(1, 3) self.fiducialsTable.setSelectionBehavior( qt.QAbstractItemView.SelectRows) self.fiducialsTable.setSelectionMode( qt.QAbstractItemView.SingleSelection) self.fiducialsTableHeaders = ["Name", "Position (mm)", "Distance (mm)"] self.fiducialsTable.setHorizontalHeaderLabels( self.fiducialsTableHeaders) self.fiducialsTable.horizontalHeader().setStretchLastSection(True) distanceLayout.addWidget(self.fiducialsTable) self.extrapolateCheckBox = qt.QCheckBox() self.extrapolateCheckBox.checked = 0 self.extrapolateCheckBox.setToolTip( "Extrapolate the first and last segment to calculate the distance") self.extrapolateCheckBox.connect('toggled(bool)', self.updateTargetFiducialsTable) self.extrapolateCheckBox.text = 'Extrapolate curves to measure the distances' self.showErrorVectorCheckBox = qt.QCheckBox() self.showErrorVectorCheckBox.checked = 0 self.showErrorVectorCheckBox.setToolTip( "Show error vectors, which is defined by the target point and the closest point on the curve. The vector is perpendicular to the curve, unless the closest point is one end of the curve." ) self.showErrorVectorCheckBox.connect('toggled(bool)', self.updateTargetFiducialsTable) self.showErrorVectorCheckBox.text = 'Show error vectors' distanceLayout.addWidget(self.extrapolateCheckBox) distanceLayout.addWidget(self.showErrorVectorCheckBox) distanceFormLayout.addRow("Distance from:", distanceLayout) # # Curvature Area # curvatureCollapsibleButton = ctk.ctkCollapsibleButton() curvatureCollapsibleButton.text = "Curvature" curvatureCollapsibleButton.collapsed = True self.layout.addWidget(curvatureCollapsibleButton) curvatureFormLayout = qt.QFormLayout(curvatureCollapsibleButton) #-- Curvature self.curvatureLayout = qt.QHBoxLayout() self.curvatureOff = qt.QRadioButton("Off") self.curvatureOff.connect('clicked(bool)', self.onCurvatureOff) self.curvatureOn = qt.QRadioButton("On") self.curvatureOn.connect('clicked(bool)', self.onCurvatureOn) self.curvatureLayout.addWidget(self.curvatureOff) self.curvatureLayout.addWidget(self.curvatureOn) self.curvatureGroup = qt.QButtonGroup() self.curvatureGroup.addButton(self.curvatureOff) self.curvatureGroup.addButton(self.curvatureOn) curvatureFormLayout.addRow("Curvature mode:", self.curvatureLayout) autoCurvatureRangeFormLayout = qt.QFormLayout( curvatureCollapsibleButton) self.autoCurvatureRangeLayout = qt.QHBoxLayout() self.autoCurvatureRangeOff = qt.QRadioButton("Manual") self.autoCurvatureRangeOff.connect('clicked(bool)', self.onAutoCurvatureRangeOff) self.autoCurvatureRangeOn = qt.QRadioButton("Auto") self.autoCurvatureRangeOn.connect('clicked(bool)', self.onAutoCurvatureRangeOn) self.autoCurvatureRangeLayout.addWidget(self.autoCurvatureRangeOff) self.autoCurvatureRangeLayout.addWidget(self.autoCurvatureRangeOn) self.autoCurvatureRangeGroup = qt.QButtonGroup() self.autoCurvatureRangeGroup.addButton(self.autoCurvatureRangeOff) self.autoCurvatureRangeGroup.addButton(self.autoCurvatureRangeOn) curvatureFormLayout.addRow("Color range:", self.autoCurvatureRangeLayout) #-- Color range self.curvatureColorRangeWidget = ctk.ctkRangeWidget() self.curvatureColorRangeWidget.setToolTip("Set color range") self.curvatureColorRangeWidget.setDecimals(3) self.curvatureColorRangeWidget.singleStep = 0.001 self.curvatureColorRangeWidget.minimumValue = 0.0 self.curvatureColorRangeWidget.maximumValue = 0.5 self.curvatureColorRangeWidget.minimum = 0.0 self.curvatureColorRangeWidget.maximum = 1.0 curvatureFormLayout.addRow("Color range: ", self.curvatureColorRangeWidget) self.curvatureColorRangeWidget.connect( 'valuesChanged(double, double)', self.onUpdateCurvatureColorRange) #-- Curvature data self.meanCurvatureLineEdit = qt.QLineEdit() self.meanCurvatureLineEdit.text = '--' self.meanCurvatureLineEdit.readOnly = True self.meanCurvatureLineEdit.frame = True self.meanCurvatureLineEdit.styleSheet = "QLineEdit { background:transparent; }" self.meanCurvatureLineEdit.cursor = qt.QCursor(qt.Qt.IBeamCursor) self.meanCurvatureLineEdit.enabled = False curvatureFormLayout.addRow("Mean (mm^-1):", self.meanCurvatureLineEdit) self.minCurvatureLineEdit = qt.QLineEdit() self.minCurvatureLineEdit.text = '--' self.minCurvatureLineEdit.readOnly = True self.minCurvatureLineEdit.frame = True self.minCurvatureLineEdit.styleSheet = "QLineEdit { background:transparent; }" self.minCurvatureLineEdit.cursor = qt.QCursor(qt.Qt.IBeamCursor) self.minCurvatureLineEdit.enabled = False curvatureFormLayout.addRow("Minimum (mm^-1):", self.minCurvatureLineEdit) self.maxCurvatureLineEdit = qt.QLineEdit() self.maxCurvatureLineEdit.text = '--' self.maxCurvatureLineEdit.readOnly = True self.maxCurvatureLineEdit.frame = True self.maxCurvatureLineEdit.styleSheet = "QLineEdit { background:transparent; }" self.maxCurvatureLineEdit.cursor = qt.QCursor(qt.Qt.IBeamCursor) self.maxCurvatureLineEdit.enabled = False curvatureFormLayout.addRow("Maximum (mm^-1):", self.maxCurvatureLineEdit) ## Create a scale for curvature self.scalarBarWidget = vtk.vtkScalarBarWidget() actor = self.scalarBarWidget.GetScalarBarActor() actor.SetOrientationToVertical() actor.SetNumberOfLabels(11) actor.SetTitle("Curvature (mm^-1)") actor.SetLabelFormat(" %#8.3f") actor.SetPosition(0.1, 0.1) actor.SetWidth(0.1) actor.SetHeight(0.8) self.scalarBarWidget.SetEnabled(0) layout = slicer.app.layoutManager() view = layout.threeDWidget(0).threeDView() renderer = layout.activeThreeDRenderer() self.scalarBarWidget.SetInteractor( renderer.GetRenderWindow().GetInteractor()) self.lookupTable = vtk.vtkLookupTable() self.lookupTable.SetRange(0.0, 100.0) self.scalarBarWidget.GetScalarBarActor().SetLookupTable( self.lookupTable) ## default curvature mode: off self.curvatureOff.setChecked(True) self.onCurvatureOff(True) self.autoCurvatureRangeOff.setChecked(True) self.onAutoCurvatureRangeOff(True) # Add vertical spacer self.layout.addStretch(1)
def setup(self): ScriptedLoadableModuleWidget.setup(self) # Instantiate and connect widgets ... #-------------------------------------------------- # For debugging # # Reload and Test area reloadCollapsibleButton = ctk.ctkCollapsibleButton() reloadCollapsibleButton.text = "Reload && Test" self.layout.addWidget(reloadCollapsibleButton) reloadFormLayout = qt.QFormLayout(reloadCollapsibleButton) reloadCollapsibleButton.collapsed = True # reload button # (use this during development, but remove it when delivering # your module to users) self.reloadButton = qt.QPushButton("Reload") self.reloadButton.toolTip = "Reload this module." self.reloadButton.name = "NeedleGuideTemlpate Reload" reloadFormLayout.addWidget(self.reloadButton) self.reloadButton.connect('clicked()', self.onReload) # #-------------------------------------------------- # # Fiducial Node # fiducialsCollapsibleButton = ctk.ctkCollapsibleButton() fiducialsCollapsibleButton.text = "Fiducials" self.layout.addWidget(fiducialsCollapsibleButton) # Layout within the dummy collapsible button fiducialsFormLayout = qt.QFormLayout(fiducialsCollapsibleButton) # # Fiducial node selector # self.fiducialSelector = slicer.qMRMLNodeComboBox() self.fiducialSelector.nodeTypes = (("vtkMRMLMarkupsFiducialNode"), "") self.fiducialSelector.selectNodeUponCreation = True self.fiducialSelector.addEnabled = True self.fiducialSelector.removeEnabled = True self.fiducialSelector.noneEnabled = False self.fiducialSelector.renameEnabled = True self.fiducialSelector.showHidden = False self.fiducialSelector.showChildNodeTypes = False self.fiducialSelector.setMRMLScene(slicer.mrmlScene) self.fiducialSelector.setToolTip("Pick the input to the algorithm.") fiducialsFormLayout.addRow("Input Volume: ", self.fiducialSelector) # # Reconfigure Button # self.radiusEdit = qt.QDoubleSpinBox() self.radiusEdit.setMinimum(0.0) self.radiusEdit.setMaximum(500.0) self.radiusEdit.setSingleStep(0.5) self.radiusEdit.setValue(50) self.numFiducialsEdit = qt.QSpinBox() self.numFiducialsEdit.setMinimum(0) self.numFiducialsEdit.setMaximum(100) self.numFiducialsEdit.setSingleStep(1) self.numFiducialsEdit.setValue(5) fiducialsFormLayout.addRow("Radius (mm):", self.radiusEdit) fiducialsFormLayout.addRow("# of fiducials:", self.numFiducialsEdit) self.reconfigureButton = qt.QPushButton("Reconfigure Fiducials") self.reconfigureButton.toolTip = "Reconfigure fiducial frame" self.reconfigureButton.enabled = False fiducialsFormLayout.addRow(self.reconfigureButton) # # Test Area # testCollapsibleButton = ctk.ctkCollapsibleButton() testCollapsibleButton.text = "Test" self.layout.addWidget(testCollapsibleButton) # Layout within the dummy collapsible button parametersFormLayout = qt.QFormLayout(testCollapsibleButton) # # input volume selector # self.inputSelector = slicer.qMRMLNodeComboBox() self.inputSelector.nodeTypes = (("vtkMRMLMarkupsFiducialNode"), "") self.inputSelector.selectNodeUponCreation = True self.inputSelector.addEnabled = False self.inputSelector.removeEnabled = False self.inputSelector.noneEnabled = False self.inputSelector.showHidden = False self.inputSelector.showChildNodeTypes = False self.inputSelector.setMRMLScene(slicer.mrmlScene) self.inputSelector.setToolTip("Pick the input to the algorithm.") parametersFormLayout.addRow("Input Fiducial: ", self.inputSelector) # # reference volume selector # self.referenceSelector = slicer.qMRMLNodeComboBox() self.referenceSelector.nodeTypes = (("vtkMRMLScalarVolumeNode"), "") self.referenceSelector.selectNodeUponCreation = False self.referenceSelector.addEnabled = True self.referenceSelector.removeEnabled = True self.referenceSelector.noneEnabled = False self.referenceSelector.showHidden = False self.referenceSelector.showChildNodeTypes = False self.referenceSelector.setMRMLScene(slicer.mrmlScene) self.referenceSelector.setToolTip( "Pick the reference to the algorithm.") parametersFormLayout.addRow("Reference Volume: ", self.referenceSelector) logFileLayout = qt.QHBoxLayout() self.logFileLineEdit = qt.QLineEdit() self.logFileLineEdit.text = '' self.logFileLineEdit.readOnly = True self.logFileLineEdit.frame = True self.logFileLineEdit.styleSheet = "QLineEdit { background:transparent; }" self.logFileLineEdit.cursor = qt.QCursor(qt.Qt.IBeamCursor) logFileLayout.addWidget(self.logFileLineEdit) self.logFileButton = qt.QPushButton("Choose File...") self.logFileButton.toolTip = "Choose log file from dialog box" logFileLayout.addWidget(self.logFileButton) parametersFormLayout.addRow("Log file:", logFileLayout) # # Apply Button # self.applyButton = qt.QPushButton("Apply") self.applyButton.toolTip = "Run the algorithm." self.applyButton.enabled = False parametersFormLayout.addRow(self.applyButton) # connections self.fiducialSelector.connect("currentNodeChanged(vtkMRMLNode*)", self.onFiducialSelect) self.reconfigureButton.connect('clicked(bool)', self.onReconfigureButton) self.logFileButton.connect('clicked(bool)', self.onLogFileButton) self.applyButton.connect('clicked(bool)', self.onApplyButton) self.inputSelector.connect("currentNodeChanged(vtkMRMLNode*)", self.onSelect) self.referenceSelector.connect("currentNodeChanged(vtkMRMLNode*)", self.onSelect) # Add vertical spacer self.layout.addStretch(1) # Create logic self.logic = FiducialRegistrationTestLogic(None) # Enable buttons, if nodes are selected self.onSelect() self.onFiducialSelect()
# # Curve Length area # lengthCollapsibleButton = ctk.ctkCollapsibleButton() lengthCollapsibleButton.text = "Length" self.layout.addWidget(lengthCollapsibleButton) lengthFormLayout = qt.QFormLayout(lengthCollapsibleButton) lengthCollapsibleButton.collapsed = True #-- Curve length self.lengthLineEdit = qt.QLineEdit() self.lengthLineEdit.text = '--' self.lengthLineEdit.readOnly = True self.lengthLineEdit.frame = True self.lengthLineEdit.styleSheet = "QLineEdit { background:transparent; }" self.lengthLineEdit.cursor = qt.QCursor(qt.Qt.IBeamCursor) def cleanup(self): pass def onSelect(self): self.applyButton.enabled = self.inputSelector.currentNode() and self.outputSelector.currentNode() def onApplyButton(self): logic = GeodesicPathSlicerLogic() inputVolume = self.inputSelector.currentNode() if not (inputVolume and fiducial): qt.QMessageBox.critical(slicer.util.mainWindow(), 'GeodesicPath', 'Input and two ficuial points are required for GeodesicPath') return
def setup(self): ScriptedLoadableModuleWidget.setup(self) # Instantiate and connect widgets ... self.logic = NeedleGuideTemplateLogic(None) #-------------------------------------------------- # For debugging # # Reload and Test area reloadCollapsibleButton = ctk.ctkCollapsibleButton() reloadCollapsibleButton.text = "Reload && Test" self.layout.addWidget(reloadCollapsibleButton) reloadFormLayout = qt.QFormLayout(reloadCollapsibleButton) reloadCollapsibleButton.collapsed = True # reload button # (use this during development, but remove it when delivering # your module to users) self.reloadButton = qt.QPushButton("Reload") self.reloadButton.toolTip = "Reload this module." self.reloadButton.name = "NeedleGuideTemlpate Reload" reloadFormLayout.addWidget(self.reloadButton) self.reloadButton.connect('clicked()', self.onReload) # #-------------------------------------------------- #-------------------------------------------------- # # Configuration # configCollapsibleButton = ctk.ctkCollapsibleButton() configCollapsibleButton.text = "Configuration" self.layout.addWidget(configCollapsibleButton) configFormLayout = qt.QFormLayout(configCollapsibleButton) configCollapsibleButton.collapsed = True templateConfigPathLayout = qt.QHBoxLayout() self.templateConfigPathEdit = qt.QLineEdit() self.templateConfigPathEdit.text = "" self.templateConfigPathEdit.readOnly = False self.templateConfigPathEdit.frame = True self.templateConfigPathEdit.styleSheet = "QLineEdit { background:transparent; }" self.templateConfigPathEdit.cursor = qt.QCursor(qt.Qt.IBeamCursor) templateConfigPathLayout.addWidget(self.templateConfigPathEdit) self.templateConfigButton = qt.QPushButton("...") self.templateConfigButton.toolTip = "Choose a template configuration file" self.templateConfigButton.enabled = True self.templateConfigButton.connect('clicked(bool)', self.onTemplateConfigButton) templateConfigPathLayout.addWidget(self.templateConfigButton) configFormLayout.addRow("Template Config File: ", templateConfigPathLayout) fiducialConfigPathLayout = qt.QHBoxLayout() self.fiducialConfigPathEdit = qt.QLineEdit() self.fiducialConfigPathEdit.text = "" self.fiducialConfigPathEdit.readOnly = False self.fiducialConfigPathEdit.frame = True self.fiducialConfigPathEdit.styleSheet = "QLineEdit { background:transparent; }" self.fiducialConfigPathEdit.cursor = qt.QCursor(qt.Qt.IBeamCursor) fiducialConfigPathLayout.addWidget(self.fiducialConfigPathEdit) self.fiducialConfigButton = qt.QPushButton("...") self.fiducialConfigButton.toolTip = "Choose a fiducial configuration file" self.fiducialConfigButton.enabled = True self.fiducialConfigButton.connect('clicked(bool)', self.onFiducialConfigButton) fiducialConfigPathLayout.addWidget(self.fiducialConfigButton) configFormLayout.addRow("Fiducial Config File: ", fiducialConfigPathLayout) # # Main Area # mainCollapsibleButton = ctk.ctkCollapsibleButton() mainCollapsibleButton.text = "Main" self.layout.addWidget(mainCollapsibleButton) # Layout within the dummy collapsible button #mainFormLayout = qt.QFormLayout(mainCollapsibleButton) mainLayout = qt.QVBoxLayout(mainCollapsibleButton) mainFormFrame = qt.QFrame() mainFormLayout = qt.QFormLayout(mainFormFrame) mainLayout.addWidget(mainFormFrame) self.showTemplateCheckBox = qt.QCheckBox() self.showTemplateCheckBox.checked = 0 self.showTemplateCheckBox.setToolTip("Show 3D model of the template") mainFormLayout.addRow("Show Template:", self.showTemplateCheckBox) self.showTemplateCheckBox.connect('toggled(bool)', self.onShowTemplate) self.showFiducialCheckBox = qt.QCheckBox() self.showFiducialCheckBox.checked = 0 self.showFiducialCheckBox.setToolTip("Show 3D model of the fiducial") mainFormLayout.addRow("Show Fiducial:", self.showFiducialCheckBox) self.showFiducialCheckBox.connect('toggled(bool)', self.onShowFiducial) self.showTrajectoriesCheckBox = qt.QCheckBox() self.showTrajectoriesCheckBox.checked = 0 self.showTrajectoriesCheckBox.setToolTip( "Show 3D model of the fiducial") mainFormLayout.addRow("Show Trajectories:", self.showTrajectoriesCheckBox) self.showTrajectoriesCheckBox.connect('toggled(bool)', self.onShowTrajectories) # # input volume selector # self.targetFiducialsSelector = slicer.qMRMLNodeComboBox() self.targetFiducialsSelector.nodeTypes = (( "vtkMRMLMarkupsFiducialNode"), "") self.targetFiducialsSelector.selectNodeUponCreation = True self.targetFiducialsSelector.addEnabled = True self.targetFiducialsSelector.removeEnabled = True self.targetFiducialsSelector.noneEnabled = False self.targetFiducialsSelector.showHidden = False self.targetFiducialsSelector.showChildNodeTypes = False self.targetFiducialsSelector.setMRMLScene(slicer.mrmlScene) self.targetFiducialsSelector.setToolTip("Select Markups for targets") mainFormLayout.addRow("Targets: ", self.targetFiducialsSelector) self.targetFiducialsNode = None self.targetFiducialsSelector.connect( "currentNodeChanged(vtkMRMLNode*)", self.onFiducialsSelected) # # Target List Table # self.table = qt.QTableWidget(1, 4) self.table.setSelectionBehavior(qt.QAbstractItemView.SelectRows) self.table.setSelectionMode(qt.QAbstractItemView.SingleSelection) #self.table.setSizePolicy(qt.QSizePolicy.Expanding, qt.QSizePolicy.Expanding) self.headers = ["Name", "Hole", "Depth (mm)", "Position (RAS)"] self.table.setHorizontalHeaderLabels(self.headers) self.table.horizontalHeader().setStretchLastSection(True) mainLayout.addWidget(self.table) self.table.connect('cellClicked(int, int)', self.onTableSelected) self.onFiducialsSelected() ## ## input volume selector ## #self.inputSelector = slicer.qMRMLNodeComboBox() #self.inputSelector.nodeTypes = ( ("vtkMRMLScalarVolumeNode"), "" ) #self.inputSelector.addAttribute( "vtkMRMLScalarVolumeNode", "LabelMap", 0 ) #self.inputSelector.selectNodeUponCreation = True #self.inputSelector.addEnabled = False #self.inputSelector.removeEnabled = False #self.inputSelector.noneEnabled = False #self.inputSelector.showHidden = False #self.inputSelector.showChildNodeTypes = False #self.inputSelector.setMRMLScene( slicer.mrmlScene ) #self.inputSelector.setToolTip( "Pick the input to the algorithm." ) #mainFormLayout.addRow("Input Volume: ", self.inputSelector) ## ## scale factor for screen shots ## #self.screenshotScaleFactorSliderWidget = ctk.ctkSliderWidget() #self.screenshotScaleFactorSliderWidget.singleStep = 1.0 #self.screenshotScaleFactorSliderWidget.minimum = 1.0 #self.screenshotScaleFactorSliderWidget.maximum = 50.0 #self.screenshotScaleFactorSliderWidget.value = 1.0 #self.screenshotScaleFactorSliderWidget.setToolTip("Set scale factor for the screen shots.") #mainFormLayout.addRow("Screenshot scale factor", self.screenshotScaleFactorSliderWidget) ## ## Apply Button ## #self.applyButton = qt.QPushButton("Apply") #self.applyButton.toolTip = "Run the algorithm." #self.applyButton.enabled = False #mainFormLayout.addRow(self.applyButton) # connections #self.applyButton.connect('clicked(bool)', self.onApplyButton) #self.inputSelector.connect("currentNodeChanged(vtkMRMLNode*)", self.onSelect) #-------------------------------------------------- # # Projection # projectionCollapsibleButton = ctk.ctkCollapsibleButton() projectionCollapsibleButton.text = "Projection" self.layout.addWidget(projectionCollapsibleButton) projectionLayout = qt.QVBoxLayout(projectionCollapsibleButton) projectionCollapsibleButton.collapsed = False self.openWindowButton = qt.QPushButton("OpenWindow") self.openWindowButton.toolTip = "Run the algorithm." self.openWindowButton.enabled = True projectionLayout.addWidget(self.openWindowButton) self.openWindowButton.connect('clicked(bool)', self.onOpenWindowButton) # Add vertical spacer self.layout.addStretch(1) self.ex = None
class EditBox(object): def __init__(self, parent=0, optionsFrame=None, embedded=False, suppliedEffects=[]): self.effects = [] self.effectButtons = {} self.effectMapper = qt.QSignalMapper() self.effectMapper.connect('mapped(const QString&)', self.selectEffect) self.editUtil = EditUtil.EditUtil() # check for extensions - if none have been registered, just create the empty dictionary try: slicer.modules.editorExtensions except AttributeError: slicer.modules.editorExtensions = {} # embedded boolean specifies whether or not this edit box is to be embedded # into another moduleWidget # - if it is, all effect buttons will be displayed in a single row self.embedded = embedded # save the list of supplied effects that the caller wants to use # (should be a subset of EditBox.availableMouseTools + EditBox.availableOperations) self.suppliedEffects = suppliedEffects if parent == 0: self.parent = qt.QFrame() self.parent.setLayout(qt.QVBoxLayout()) self.create() self.parent.show() else: self.parent = parent self.create() # frame that holds widgets specific for each effect if not optionsFrame: self.optionsFrame = qt.QFrame(self.parent) else: self.optionsFrame = optionsFrame # state variables for selected effect in the box # - currentOption is an instance of an option GUI # - currentTools is a list of EffectTool instances self.currentOption = None self.currentTools = [] # # Public lists of the available effects provided by the editor # # effects that change the mouse cursor availableMouseTools = ( "ChangeIsland", "ChooseColor", "ImplicitCube", "ImplicitEllipse", "ImplicitRectangle", "Draw", "RemoveIslands", "ConnectedComponents", "ThresholdBucket", "ThresholdPaintLabel", "SaveIsland", "SlurpColor", "Paint", "DefaultTool", "LevelTracing", "MakeModel", "Wand", "GrowCutSegment", ) # effects that operate from the menu availableOperations = ( "ErodeLabel", "DilateLabel", "DeleteFiducials", "LabelOpacity", "ChangeLabel", "FiducialVisibilityOff", "FiducialVisibilityOn", "GoToEditorModule", "IdentifyIslands", "LabelVisibilityOff", "LabelVisibilityOn", "NextFiducial", "SnapToGridOff", "SnapToGridOn", "EraseLabel", "Threshold", "PinOpen", "PreviousFiducial", "InterpolateLabels", "LabelOpacity", "ToggleLabelOutline", "Watershed", "PreviousCheckPoint", "NextCheckPoint", ) # these buttons do not switch you out of the current tool availableNonmodal = ("FiducialVisibilityOn", "LabelVisibilityOff", "LabelVisibilityOn", "NextFiducial", "PreviousFiducial", "DeleteFiducials", "SnapToGridOn", "SnapToGridOff", "EraseLabel", "PreviousCheckPoint", "NextCheckPoint", "ToggleLabelOutline", "SnapToGridOff", "SnapToGridOn", "LabelOpacity") # these buttons start disabled (check points will re-enable when circumstances are right) availableDisabled = ( "ChooseColor", "ImplicitCube", "ImplicitEllipse", "ConnectedComponents", "SlurpColor", "ThresholdPaintLabel", "ThresholdBucket", "DeleteFiducials", "LabelOpacity", "FiducialVisibilityOff", "FiducialVisibilityOn", "LabelVisibilityOff", "LabelVisibilityOn", "SnapToGridOff", "SnapToGridOn", "InterpolateLabels", "LabelOpacity", "ToggleLabelOutline", "Watershed", "Wand", ) # allow overriding the developers name of the tool for a more user-friendly label name displayNames = {} displayNames["PreviousCheckPoint"] = "Undo" displayNames["NextCheckPoint"] = "Redo" # calculates the intersection of two flat lists @classmethod def listIntersection(cls, inList1, inList2): outList = [val for val in inList1 if val in inList2] return outList # fill the _effects array bases on what you find in the interpreter # if a list of effects was supplied, then use that list instead of all of the effects def findEffects(self, path=""): # for now, the built in effects are hard-coded to facilitate # the icons and layout self.effects = [] # if a list of effects was supplied, then use that list instead of all of the effects # don't forget to check that the supplied effects are valid: ensure they exist in the lists of available effects if (self.suppliedEffects): self.mouseTools = tuple( self.listIntersection(self.suppliedEffects, EditBox.availableMouseTools)) self.operations = tuple( self.listIntersection(self.suppliedEffects, EditBox.availableOperations)) self.nonmodal = tuple( self.listIntersection(self.suppliedEffects, EditBox.availableNonmodal)) self.disabled = tuple( self.listIntersection(self.suppliedEffects, EditBox.availableDisabled)) # if a list of effects is not supplied, then provide all effects else: self.mouseTools = EditBox.availableMouseTools self.operations = EditBox.availableOperations self.nonmodal = EditBox.availableNonmodal self.disabled = EditBox.availableDisabled ''' for key in slicer.modules.editorExtensions.keys(): e = slicer.modules.editorExtensions[key]() if 'MouseTool' in e.attributes: self.mouseTools.append(key) if 'Nonmodal' in e.attributes: self.operations.append(key) if 'Disabled' in e.attributes: self.disabled.append(key) ''' # combined list of all effects self.effects = self.mouseTools + self.operations # add any extensions that have been registered self.effects = self.effects + tuple( slicer.modules.editorExtensions.keys()) # for each effect # - look for implementation class of pattern *Effect # - get an icon name for the pushbutton iconDir = os.environ['SLICER_HOME'] + '/' + os.environ[ 'SLICER_SHARE_DIR'] + '/Tcl/ImageData/' self.effectClasses = {} self.effectIconFiles = {} self.effectModes = {} self.icons = {} for effect in self.effects: tclclass = tcl('info command %sEffect' % effect) if tclclass != '': self.effectClasses[effect] = tclclass else: self.effectClasses[effect] = "EffectSWidget" for iconType in ("", "Selected", "Disabled"): self.effectIconFiles[ effect, iconType] = iconDir + effect + iconType + '.png' iconMode = "" if self.disabled.__contains__(effect): # - don't use the disabled icon for now - Qt's setEnabled method works fine #iconMode = "Disabled" pass self.effectModes[effect] = iconMode # # create a row of the edit box given a list of # effect names (items in _effects(list) # def createButtonRow(self, effects, rowLabel=""): f = qt.QFrame(self.parent) self.parent.layout().addWidget(f) self.rowFrames.append(f) hbox = qt.QHBoxLayout() f.setLayout(hbox) if rowLabel: label = qt.QLabel(rowLabel) hbox.addWidget(label) for effect in effects: # check that the effect belongs in our list of effects before including # (handles non-embedded widgets where the caller has supplied a custom list of effects) if (effect in self.effects): i = self.icons[effect] = qt.QIcon( self.effectIconFiles[effect, self.effectModes[effect]]) a = self.actions[effect] = qt.QAction(i, '', f) self.effectButtons[effect] = b = self.buttons[ effect] = qt.QToolButton() b.setDefaultAction(a) b.setToolTip(effect) if EditBox.displayNames.has_key(effect): b.setToolTip(EditBox.displayNames[effect]) hbox.addWidget(b) if self.disabled.__contains__(effect): b.setDisabled(1) # Setup the mapping between button and its associated effect name self.effectMapper.setMapping(self.buttons[effect], effect) # Connect button with signal mapper self.buttons[effect].connect('clicked()', self.effectMapper, 'map()') hbox.addStretch(1) # create the edit box def create(self): self.findEffects() # # the buttons # self.rowFrames = [] self.actions = {} self.buttons = {} self.icons = {} self.callbacks = {} # if not using embedded format: create all of the buttons # createButtonRow() ensures that only effects in self.effects are exposed, # so if the user supplied a list of effects only those in that list will be exposed if (not self.embedded): self.createButtonRow( ("DefaultTool", "EraseLabel", "Paint", "Draw", "LevelTracing", "ImplicitRectangle", "IdentifyIslands", "ChangeIsland", "RemoveIslands", "SaveIsland")) self.createButtonRow( ("ErodeLabel", "DilateLabel", "Threshold", "ChangeLabel", "MakeModel", "GrowCutSegment")) extensions = [] for k in slicer.modules.editorExtensions: extensions.append(k) self.createButtonRow(extensions) # TODO: add back prev/next fiducial #self.createButtonRow( ("PreviousFiducial", "NextFiducial") ) self.createButtonRow(("PreviousCheckPoint", "NextCheckPoint"), rowLabel="Undo/Redo: ") # if using embedded format: create all of the buttons in the effects list in a single row else: self.createButtonRow(self.effects) # # the labels (not shown in embedded format) # self.toolsActiveToolFrame = qt.QFrame(self.parent) self.toolsActiveToolFrame.setLayout(qt.QHBoxLayout()) self.parent.layout().addWidget(self.toolsActiveToolFrame) self.toolsActiveTool = qt.QLabel(self.toolsActiveToolFrame) self.toolsActiveTool.setText('Active Tool:') self.toolsActiveTool.setStyleSheet( "background-color: rgb(232,230,235)") self.toolsActiveToolFrame.layout().addWidget(self.toolsActiveTool) self.toolsActiveToolName = qt.QLabel(self.toolsActiveToolFrame) self.toolsActiveToolName.setText('') self.toolsActiveToolName.setStyleSheet( "background-color: rgb(232,230,235)") self.toolsActiveToolFrame.layout().addWidget(self.toolsActiveToolName) self.updateCheckPointButtons() def setActiveToolLabel(self, name): if EditBox.displayNames.has_key(name): name = EditBox.displayNames[name] self.toolsActiveToolName.setText(name) # needs to be a valid effect name and state of "", Disabled, or Selected TODO = """ itcl::body EditBox::setButtonState {effect state} { $::slicer3::ApplicationGUI SetIconImage \ $_effects($effect,icon) $_effects($effect,imageData$state) $o($effect,button) SetImageToIcon $_effects($effect,icon) switch $state { Selected - "" { $o($effect,button) SetState 1 } "Disabled" { $o($effect,button) SetState 0 } } } """ # # Pause running the current effect, reverting to the default tool # def pauseEffect(self): self.selectEffect("DefaultTool") # # Resume running the effect that was being used before a pause (TODO) # def resumeEffect(self): pass # # manage the editor effects # def selectEffect(self, effect): from slicer import app # # if a modal effect was selected, build an options GUI # - check to see if it is an extension effect, # if not, try to create it, else ignore it # For extensions, look for 'effect'Options and 'effect'Tool # in the editorExtensions map and use those to create the # effect # if not self.nonmodal.__contains__(effect): if self.currentOption: self.currentOption.__del__() self.currentOption = None for tool in self.currentTools: tool.cleanup() self.currentTools = [] if effect in slicer.modules.editorExtensions.keys(): extensionEffect = slicer.modules.editorExtensions[effect]() self.currentOption = extensionEffect.options(self.optionsFrame) layoutManager = slicer.app.layoutManager() sliceNodeCount = slicer.mrmlScene.GetNumberOfNodesByClass( 'vtkMRMLSliceNode') for nodeIndex in xrange(sliceNodeCount): # find the widget for each node in scene sliceNode = slicer.mrmlScene.GetNthNodeByClass( nodeIndex, 'vtkMRMLSliceNode') sliceWidget = layoutManager.sliceWidget( sliceNode.GetLayoutName()) if sliceWidget: tool = extensionEffect.tool(sliceWidget) self.currentTools.append(tool) else: try: options = eval("%sOptions" % effect) self.currentOption = options(self.optionsFrame) except NameError, AttributeError: # No options for this effect, skip it pass # # If there is no background volume or label map, do nothing # # TODO should do this regardless of whether or not there is an option if not self.editUtil.getBackgroundVolume(): return if not self.editUtil.getLabelVolume(): return app.restoreOverrideCursor() self.setActiveToolLabel(effect) if not self.nonmodal.__contains__(effect): tcl('EffectSWidget::RemoveAll') tcl('EditorSetActiveToolLabel %s' % effect) # mouse tool changes cursor, and dismisses popup/menu mouseTool = False if self.mouseTools.__contains__(effect): mouseTool = True if effect == "DefaultTool": # do nothing - this will reset cursor mode tcl('EditorSetActiveToolLabel DefaultTool') elif effect == "GoToEditorModule": tcl('EditorSelectModule') tcl('EditorSetActiveToolLabel DefaultTool') elif effect == "LabelCheckPoint": # save a copy of the current label layer into the scene tcl('EditorLabelCheckPoint') tcl('EditorSetActiveToolLabel DefaultTool') elif effect == "PreviousFiducial": tcl('::FiducialsSWidget::JumpAllToNextFiducial -1') tcl('EditorSetActiveToolLabel DefaultTool') elif effect == "NextFiducial": tcl('::FiducialsSWidget::JumpAllToNextFiducial 1') tcl('EditorSetActiveToolLabel DefaultTool') elif effect == "EraseLabel": tcl('EditorToggleErasePaintLabel') elif effect == "PreviousCheckPoint": tcl('EditorPerformPreviousCheckPoint') elif effect == "NextCheckPoint": tcl('EditorPerformNextCheckPoint') else: if effect == "GrowCutSegment": self.editorGestureCheckPoint() #volumesLogic = slicer.modules.volumes.logic() #print ("VolumesLogic is %s " % volumesLogic) #tcl('EditorGestureCheckPoint $%s' % volumesLogic) if mouseTool: # TODO: make some nice custom cursor shapes # - for now use the built in override cursor #pix = qt.QPixmap() #pix.load(self.effectIconFiles[effect,""]) #cursor = qt.QCursor(pix) #app.setOverrideCursor(cursor, 0, 0) cursor = qt.QCursor(1) app.setOverrideCursor(cursor) else: app.restoreOverrideCursor() # # create an instance of the effect for each of the active sliceGUIs # - have the effect reset the tool label when completed # ret = tcl('catch "EffectSWidget::Add %s" res' % self.effectClasses[effect]) if ret != '0': dialog = qt.QErrorMessage(self.parent) dialog.showMessage( "Could not select effect.\n\nError was:\n%s" % tcl('set res')) else: tcl('EffectSWidget::ConfigureAll %s -exitCommand "EditorSetActiveToolLabel DefaultTool"' % self.effectClasses[effect])
def setup(self): ScriptedLoadableModuleWidget.setup(self) # Instantiate and connect widgets ... #-------------------------------------------------- # For debugging # # Reload and Test area reloadCollapsibleButton = ctk.ctkCollapsibleButton() reloadCollapsibleButton.text = "Reload && Test" self.layout.addWidget(reloadCollapsibleButton) reloadFormLayout = qt.QFormLayout(reloadCollapsibleButton) reloadCollapsibleButton.collapsed = True # reload button # (use this during development, but remove it when delivering # your module to users) self.reloadButton = qt.QPushButton("Reload") self.reloadButton.toolTip = "Reload this module." self.reloadButton.name = "NeedleGuideTemlpate Reload" reloadFormLayout.addWidget(self.reloadButton) self.reloadButton.connect('clicked()', self.onReload) # #-------------------------------------------------- # # Fiducial Node # fiducialsCollapsibleButton = ctk.ctkCollapsibleButton() fiducialsCollapsibleButton.text = "Fiducials" self.layout.addWidget(fiducialsCollapsibleButton) # Layout within the dummy collapsible button fiducialsFormLayout = qt.QFormLayout(fiducialsCollapsibleButton) # # Fiducial node selector # self.fiducial1Selector = slicer.qMRMLNodeComboBox() self.fiducial1Selector.nodeTypes = (("vtkMRMLMarkupsFiducialNode"), "") self.fiducial1Selector.selectNodeUponCreation = True self.fiducial1Selector.addEnabled = True self.fiducial1Selector.removeEnabled = True self.fiducial1Selector.noneEnabled = True self.fiducial1Selector.renameEnabled = True self.fiducial1Selector.showHidden = False self.fiducial1Selector.showChildNodeTypes = False self.fiducial1Selector.setMRMLScene(slicer.mrmlScene) self.fiducial1Selector.setToolTip("Pick the input to the algorithm.") fiducialsFormLayout.addRow("Fiducial 1: ", self.fiducial1Selector) self.fiducial2Selector = slicer.qMRMLNodeComboBox() self.fiducial2Selector.nodeTypes = (("vtkMRMLMarkupsFiducialNode"), "") self.fiducial2Selector.selectNodeUponCreation = True self.fiducial2Selector.addEnabled = True self.fiducial2Selector.removeEnabled = True self.fiducial2Selector.noneEnabled = True self.fiducial2Selector.renameEnabled = True self.fiducial2Selector.showHidden = False self.fiducial2Selector.showChildNodeTypes = False self.fiducial2Selector.setMRMLScene(slicer.mrmlScene) self.fiducial2Selector.setToolTip("Pick the input to the algorithm.") fiducialsFormLayout.addRow("Fiducial 2: ", self.fiducial2Selector) # # Apply Button # self.applyButton = qt.QPushButton("Apply") self.applyButton.toolTip = "Run the algorithm." self.applyButton.enabled = False fiducialsFormLayout.addRow(self.applyButton) # # Result # self.TREEdit = qt.QLineEdit() self.TREEdit.text = '--' self.TREEdit.readOnly = True self.TREEdit.frame = True self.TREEdit.styleSheet = "QLineEdit { background:transparent; }" self.TREEdit.cursor = qt.QCursor(qt.Qt.IBeamCursor) fiducialsFormLayout.addRow("TRE (mm):", self.TREEdit) self.errorRAEdit = qt.QLineEdit() self.errorRAEdit.text = '--' self.errorRAEdit.readOnly = True self.errorRAEdit.frame = True self.errorRAEdit.styleSheet = "QLineEdit { background:transparent; }" self.errorRAEdit.cursor = qt.QCursor(qt.Qt.IBeamCursor) fiducialsFormLayout.addRow("Error RA (mm):", self.errorRAEdit) self.errorAPEdit = qt.QLineEdit() self.errorAPEdit.text = '--' self.errorAPEdit.readOnly = True self.errorAPEdit.frame = True self.errorAPEdit.styleSheet = "QLineEdit { background:transparent; }" self.errorAPEdit.cursor = qt.QCursor(qt.Qt.IBeamCursor) fiducialsFormLayout.addRow("Error AP (mm):", self.errorAPEdit) self.errorSIEdit = qt.QLineEdit() self.errorSIEdit.text = '--' self.errorSIEdit.readOnly = True self.errorSIEdit.frame = True self.errorSIEdit.styleSheet = "QLineEdit { background:transparent; }" self.errorSIEdit.cursor = qt.QCursor(qt.Qt.IBeamCursor) fiducialsFormLayout.addRow("Error SI (mm):", self.errorSIEdit) # connections self.fiducial1Selector.connect("currentNodeChanged(vtkMRMLNode*)", self.onFiducialSelect) self.fiducial2Selector.connect("currentNodeChanged(vtkMRMLNode*)", self.onFiducialSelect) self.applyButton.connect('clicked(bool)', self.onApplyButton) # Add vertical spacer self.layout.addStretch(1) # Create logic self.logic = TargetRegistrationErrorLogic(None) # Enable buttons, if nodes are selected self.onFiducialSelect()
class EditBox(object): def __init__(self, parent=None, optionsFrame=None): self.effects = [] self.effectButtons = {} self.effectMapper = qt.QSignalMapper() self.effectMapper.connect('mapped(const QString&)', self.selectEffect) self.editUtil = EditUtil.EditUtil() self.undoRedo = EditUtil.UndoRedo() self.undoRedo.stateChangedCallback = self.updateUndoRedoButtons # check for extensions - if none have been registered, just create the empty dictionary try: slicer.modules.editorExtensions except AttributeError: slicer.modules.editorExtensions = {} # register the builtin extensions self.editorBuiltins = {} self.editorBuiltins["PaintEffect"] = EditorLib.PaintEffect self.editorBuiltins["DrawEffect"] = EditorLib.DrawEffect self.editorBuiltins["ThresholdEffect"] = EditorLib.ThresholdEffect self.editorBuiltins["RectangleEffect"] = EditorLib.RectangleEffect self.editorBuiltins[ "LevelTracingEffect"] = EditorLib.LevelTracingEffect self.editorBuiltins["MakeModelEffect"] = EditorLib.MakeModelEffect self.editorBuiltins["ErodeEffect"] = EditorLib.ErodeEffect self.editorBuiltins["DilateEffect"] = EditorLib.DilateEffect self.editorBuiltins["ChangeLabelEffect"] = EditorLib.ChangeLabelEffect self.editorBuiltins[ "RemoveIslandsEffect"] = EditorLib.RemoveIslandsEffect self.editorBuiltins[ "IdentifyIslandsEffect"] = EditorLib.IdentifyIslandsEffect self.editorBuiltins["SaveIslandEffect"] = EditorLib.SaveIslandEffect self.editorBuiltins[ "ChangeIslandEffect"] = EditorLib.ChangeIslandEffect self.editorBuiltins["GrowCutEffect"] = EditorLib.GrowCutEffect if not parent: self.parent = qt.QFrame() self.parent.setLayout(qt.QVBoxLayout()) self.create() self.parent.show() else: self.parent = parent self.create() # frame that holds widgets specific for each effect if not optionsFrame: self.optionsFrame = qt.QFrame(self.parent) else: self.optionsFrame = optionsFrame # state variables for selected effect in the box # - currentOption is an instance of an option GUI # - currentTools is a list of EffectTool instances self.currentOption = None self.currentTools = [] # # Public lists of the available effects provided by the editor # # effects that change the mouse cursor availableMouseTools = ( "ChangeIsland", "ChooseColor", "ImplicitCube", "ImplicitEllipse", "ImplicitRectangle", "Draw", "RemoveIslands", "ConnectedComponents", "ThresholdBucket", "ThresholdPaintLabel", "SaveIsland", "SlurpColor", "Paint", "DefaultTool", "LevelTracing", "MakeModel", "Wand", "GrowCutSegment", ) # effects that operate from the menu availableOperations = ( "ErodeLabel", "DilateLabel", "DeleteFiducials", "LabelOpacity", "ChangeLabel", "FiducialVisibilityOff", "FiducialVisibilityOn", "GoToEditorModule", "IdentifyIslands", "LabelVisibilityOff", "LabelVisibilityOn", "NextFiducial", "SnapToGridOff", "SnapToGridOn", "EraseLabel", "Threshold", "PinOpen", "PreviousFiducial", "InterpolateLabels", "LabelOpacity", "ToggleLabelOutline", "Watershed", "PreviousCheckPoint", "NextCheckPoint", ) # these buttons do not switch you out of the current tool availableNonmodal = ("FiducialVisibilityOn", "LabelVisibilityOff", "LabelVisibilityOn", "NextFiducial", "PreviousFiducial", "DeleteFiducials", "SnapToGridOn", "SnapToGridOff", "EraseLabel", "PreviousCheckPoint", "NextCheckPoint", "ToggleLabelOutline", "SnapToGridOff", "SnapToGridOn", "LabelOpacity") # these buttons start disabled (check points will re-enable when circumstances are right) availableDisabled = ( "ChooseColor", "ImplicitCube", "ImplicitEllipse", "ConnectedComponents", "SlurpColor", "ThresholdPaintLabel", "ThresholdBucket", "DeleteFiducials", "LabelOpacity", "FiducialVisibilityOff", "FiducialVisibilityOn", "LabelVisibilityOff", "LabelVisibilityOn", "SnapToGridOff", "SnapToGridOn", "InterpolateLabels", "LabelOpacity", "ToggleLabelOutline", "Watershed", "Wand", ) # allow overriding the developers name of the tool for a more user-friendly label name displayNames = {} displayNames["PreviousCheckPoint"] = "Undo" displayNames["NextCheckPoint"] = "Redo" # calculates the intersection of two flat lists @classmethod def listIntersection(cls, inList1, inList2): outList = [val for val in inList1 if val in inList2] return outList # fill the _effects array bases on what you find in the interpreter def findEffects(self, path=""): # for now, the built in effects are hard-coded to facilitate # the icons and layout self.effects = [] self.mouseTools = EditBox.availableMouseTools self.operations = EditBox.availableOperations self.nonmodal = EditBox.availableNonmodal self.disabled = EditBox.availableDisabled # combined list of all effects self.effects = self.mouseTools + self.operations # add builtins that have been registered self.effects = self.effects + tuple(self.editorBuiltins.keys()) # add any extensions that have been registered self.effects = self.effects + tuple( slicer.modules.editorExtensions.keys()) # for each effect # - look for implementation class of pattern *Effect # - get an icon name for the pushbutton iconDir = os.environ['SLICER_HOME'] + '/' + os.environ[ 'SLICER_SHARE_DIR'] + '/Tcl/ImageData/' self.effectIconFiles = {} self.effectModes = {} self.icons = {} for effect in self.effects: for iconType in ("", "Selected", "Disabled"): self.effectIconFiles[ effect, iconType] = iconDir + effect + iconType + '.png' iconMode = "" if self.disabled.__contains__(effect): # - don't use the disabled icon for now - Qt's setEnabled method works fine #iconMode = "Disabled" pass self.effectModes[effect] = iconMode if effect in slicer.modules.editorExtensions.keys(): extensionEffect = slicer.modules.editorExtensions[effect]() module = eval('slicer.modules.%s' % effect.lower()) iconPath = os.path.join(os.path.dirname(module.path), "%s.png" % effect) self.effectIconFiles[effect, ""] = iconPath self.effectModes[effect] = "" # TOOD: add icons for builtins as resource or installed image directory self.effectIconFiles["PaintEffect", ""] = self.effectIconFiles["Paint", ""] self.effectIconFiles["DrawEffect", ""] = self.effectIconFiles["Draw", ""] self.effectIconFiles["ThresholdEffect", ""] = self.effectIconFiles["Threshold", ""] self.effectIconFiles["RectangleEffect", ""] = self.effectIconFiles["ImplicitRectangle", ""] self.effectIconFiles["LevelTracingEffect", ""] = self.effectIconFiles["LevelTracing", ""] self.effectIconFiles["MakeModelEffect", ""] = self.effectIconFiles["MakeModel", ""] self.effectIconFiles["ErodeEffect", ""] = self.effectIconFiles["ErodeLabel", ""] self.effectIconFiles["DilateEffect", ""] = self.effectIconFiles["DilateLabel", ""] self.effectIconFiles["IdentifyIslandsEffect", ""] = self.effectIconFiles["IdentifyIslands", ""] self.effectIconFiles["ChangeIslandEffect", ""] = self.effectIconFiles["ChangeIsland", ""] self.effectIconFiles["RemoveIslandsEffect", ""] = self.effectIconFiles["RemoveIslands", ""] self.effectIconFiles["SaveIslandEffect", ""] = self.effectIconFiles["SaveIsland", ""] self.effectIconFiles["ChangeIslandEffect", ""] = self.effectIconFiles["ChangeIsland", ""] self.effectIconFiles["ChangeLabelEffect", ""] = self.effectIconFiles["ChangeLabel", ""] self.effectIconFiles["GrowCutEffect", ""] = self.effectIconFiles["GrowCutSegment", ""] # # create a row of the edit box given a list of # effect names (items in _effects(list) # def createButtonRow(self, effects, rowLabel=""): f = qt.QFrame(self.parent) self.parent.layout().addWidget(f) self.rowFrames.append(f) hbox = qt.QHBoxLayout() f.setLayout(hbox) if rowLabel: label = qt.QLabel(rowLabel) hbox.addWidget(label) for effect in effects: # check that the effect belongs in our list of effects before including if (effect in self.effects): i = self.icons[effect] = qt.QIcon( self.effectIconFiles[effect, self.effectModes[effect]]) a = self.actions[effect] = qt.QAction(i, '', f) self.effectButtons[effect] = b = self.buttons[ effect] = qt.QToolButton() b.setDefaultAction(a) b.setToolTip(effect) if EditBox.displayNames.has_key(effect): b.setToolTip(EditBox.displayNames[effect]) hbox.addWidget(b) if self.disabled.__contains__(effect): b.setDisabled(1) # Setup the mapping between button and its associated effect name self.effectMapper.setMapping(self.buttons[effect], effect) # Connect button with signal mapper self.buttons[effect].connect('clicked()', self.effectMapper, 'map()') hbox.addStretch(1) # create the edit box def create(self): self.findEffects() # # the buttons # self.rowFrames = [] self.actions = {} self.buttons = {} self.icons = {} self.callbacks = {} # create all of the buttons # createButtonRow() ensures that only effects in self.effects are exposed, self.createButtonRow( ("DefaultTool", "EraseLabel", "PaintEffect", "DrawEffect", "LevelTracingEffect", "RectangleEffect", "IdentifyIslandsEffect", "ChangeIslandEffect", "RemoveIslandsEffect", "SaveIslandEffect")) self.createButtonRow( ("ErodeEffect", "DilateEffect", "GrowCutEffect", "ThresholdEffect", "ChangeLabelEffect", "MakeModelEffect")) extensions = [] for k in slicer.modules.editorExtensions: extensions.append(k) self.createButtonRow(extensions) # TODO: add back prev/next fiducial #self.createButtonRow( ("PreviousFiducial", "NextFiducial") ) self.createButtonRow(("PreviousCheckPoint", "NextCheckPoint"), rowLabel="Undo/Redo: ") # # the labels # self.toolsActiveToolFrame = qt.QFrame(self.parent) self.toolsActiveToolFrame.setLayout(qt.QHBoxLayout()) self.parent.layout().addWidget(self.toolsActiveToolFrame) self.toolsActiveTool = qt.QLabel(self.toolsActiveToolFrame) self.toolsActiveTool.setText('Active Tool:') self.toolsActiveTool.setStyleSheet( "background-color: rgb(232,230,235)") self.toolsActiveToolFrame.layout().addWidget(self.toolsActiveTool) self.toolsActiveToolName = qt.QLabel(self.toolsActiveToolFrame) self.toolsActiveToolName.setText('') self.toolsActiveToolName.setStyleSheet( "background-color: rgb(232,230,235)") self.toolsActiveToolFrame.layout().addWidget(self.toolsActiveToolName) self.updateUndoRedoButtons() def setActiveToolLabel(self, name): if EditBox.displayNames.has_key(name): name = EditBox.displayNames[name] self.toolsActiveToolName.setText(name) # # switch to the default tool # def defaultEffect(self): self.selectEffect("DefaultTool") # # manage the editor effects # def selectEffect(self, effectName): # # If there is no background volume or label map, do nothing # if not self.editUtil.getBackgroundVolume(): return if not self.editUtil.getLabelVolume(): return # # if a modal effect was selected, build an options GUI # - check to see if it is an extension effect, # if not, try to create it, else ignore it # For extensions, look for 'effect'Options and 'effect'Tool # in the editorExtensions map and use those to create the # effect # if not self.nonmodal.__contains__(effectName): if self.currentOption: # clean up any existing effect self.currentOption.__del__() self.currentOption = None for tool in self.currentTools: tool.cleanup() self.currentTools = [] # look at builtins and extensions # - TODO: other effect styles are deprecated effectClass = None if effectName in slicer.modules.editorExtensions.keys(): effectClass = slicer.modules.editorExtensions[effectName]() elif effectName in self.editorBuiltins.keys(): effectClass = self.editorBuiltins[effectName]() if effectClass: # for effects, create an options gui and an # instance for every slice view self.currentOption = effectClass.options(self.optionsFrame) self.currentOption.undoRedo = self.undoRedo self.currentOption.defaultEffect = self.defaultEffect self.currentOption.create() self.currentOption.updateGUI() layoutManager = slicer.app.layoutManager() sliceNodeCount = slicer.mrmlScene.GetNumberOfNodesByClass( 'vtkMRMLSliceNode') for nodeIndex in xrange(sliceNodeCount): # find the widget for each node in scene sliceNode = slicer.mrmlScene.GetNthNodeByClass( nodeIndex, 'vtkMRMLSliceNode') sliceWidget = layoutManager.sliceWidget( sliceNode.GetLayoutName()) if sliceWidget: tool = effectClass.tool(sliceWidget) tool.undoRedo = self.undoRedo self.currentTools.append(tool) self.currentOption.tools = self.currentTools else: # fallback to internal classes try: options = eval("%sOptions" % effectName) self.currentOption = options(self.optionsFrame) except NameError, AttributeError: # No options for this effect, skip it pass slicer.app.restoreOverrideCursor() self.setActiveToolLabel(effectName) # mouse tool changes cursor, and dismisses popup/menu mouseTool = False if self.mouseTools.__contains__(effectName): mouseTool = True if effectName == "DefaultTool": # do nothing - this will reset cursor mode pass elif effectName == "EraseLabel": self.editUtil.toggleLabel() elif effectName == "PreviousCheckPoint": self.undoRedo.undo() elif effectName == "NextCheckPoint": self.undoRedo.redo() else: if mouseTool: # TODO: make some nice custom cursor shapes # - for now use the built in override cursor #pix = qt.QPixmap() #pix.load(self.effectIconFiles[effectName,""]) #cursor = qt.QCursor(pix) #app.setOverrideCursor(cursor, 0, 0) cursor = qt.QCursor(1) slicer.app.setOverrideCursor(cursor) else: slicer.app.restoreOverrideCursor()
def paintLabelMap(self, labelNode): cursorPosition = qt.QCursor().pos() #w = self.mainFrame.width #h = self.mainFrame.height # self.mainFrame.pos = qt.QPoint(cursorPosition.x() - w/2, cursorPosition.y() - h/2) print(cursorPosition.x(), cursorPosition.y())
def getMeanOpticalAttenuationOfCentralCylinder(self, calibrationVolumeNodeID, centralRadiusMm): # Format of output array: the following values are provided for each slice: # depth (cm), mean optical attenuation on the slice at depth, std.dev. of optical attenuation qt.QApplication.setOverrideCursor(qt.QCursor(qt.Qt.BusyCursor)) calibrationVolume = slicer.util.getNode(calibrationVolumeNodeID) calibrationVolumeImageData = calibrationVolume.GetImageData() # Get image properties needed for the calculation calibrationVolumeSliceThicknessCm = calibrationVolume.GetSpacing( )[2] / 10.0 if calibrationVolume.GetSpacing()[0] != calibrationVolume.GetSpacing( )[1]: logging.warning( 'Image data X and Y spacing differ! This is not supported, the mean optical attenuation data may be skewed' ) calibrationVolumeInPlaneSpacing = calibrationVolume.GetSpacing()[0] centralRadiusPixel = int( numpy.ceil(centralRadiusMm / calibrationVolumeInPlaneSpacing)) if centralRadiusPixel != centralRadiusMm / calibrationVolumeInPlaneSpacing: logging.info( 'Central radius has been rounded up to {0} (original radius is {1}mm = {2}px)' .format(centralRadiusPixel, centralRadiusMm, centralRadiusMm / calibrationVolumeInPlaneSpacing)) numberOfSlices = calibrationVolumeImageData.GetExtent( )[5] - calibrationVolumeImageData.GetExtent()[4] + 1 centerXCoordinate = (calibrationVolumeImageData.GetExtent()[1] - calibrationVolumeImageData.GetExtent()[0]) / 2 centerYCoordinate = (calibrationVolumeImageData.GetExtent()[3] - calibrationVolumeImageData.GetExtent()[2]) / 2 # Get image data in numpy array calibrationVolumeImageDataAsScalars = calibrationVolumeImageData.GetPointData( ).GetScalars() numpyImageDataArray = numpy_support.vtk_to_numpy( calibrationVolumeImageDataAsScalars) numpyImageDataArray = numpy.reshape( numpyImageDataArray, (calibrationVolumeImageData.GetExtent()[1] + 1, calibrationVolumeImageData.GetExtent()[3] + 1, calibrationVolumeImageData.GetExtent()[5] + 1), 'F') opticalAttenuationOfCentralCylinderTable = numpy.zeros( (numberOfSlices, 3)) sliceNumber = 0 z = calibrationVolumeImageData.GetExtent()[5] zMin = calibrationVolumeImageData.GetExtent()[4] while z >= zMin: totalPixels = 0 totalOpticalAttenuation = 0 listOfOpticalDensities = [] meanOpticalAttenuation = 0 for y in range(floor(centerYCoordinate - centralRadiusPixel + 0.5), ceil(centerYCoordinate + centralRadiusPixel + 0.5)): for x in range( floor(centerXCoordinate - centralRadiusPixel + 0.5), ceil(centerXCoordinate + centralRadiusPixel + 0.5)): distanceOfX = abs(x - centerXCoordinate) distanceOfY = abs(y - centerYCoordinate) if ((distanceOfX + distanceOfY) <= centralRadiusPixel) or ( (pow(distanceOfX, 2) + pow(distanceOfY, 2)) <= pow( centralRadiusPixel, 2)): currentOpticalAttenuation = numpyImageDataArray[x, y, z] listOfOpticalDensities.append( currentOpticalAttenuation) totalOpticalAttenuation = totalOpticalAttenuation + currentOpticalAttenuation totalPixels += 1 meanOpticalAttenuation = totalOpticalAttenuation / totalPixels standardDeviationOpticalAttenuation = 0 for currentOpticalAttenuationValue in range(totalPixels): standardDeviationOpticalAttenuation += pow( (listOfOpticalDensities[currentOpticalAttenuationValue] - meanOpticalAttenuation), 2) standardDeviationOpticalAttenuation = sqrt( standardDeviationOpticalAttenuation / totalPixels) opticalAttenuationOfCentralCylinderTable[ sliceNumber, 0] = sliceNumber * calibrationVolumeSliceThicknessCm opticalAttenuationOfCentralCylinderTable[ sliceNumber, 1] = meanOpticalAttenuation opticalAttenuationOfCentralCylinderTable[ sliceNumber, 2] = standardDeviationOpticalAttenuation # logging.debug('Slice (cm): ' + repr(sliceNumber*calibrationVolumeSliceThicknessCm)) # logging.debug(' Mean: ' + repr(meanOpticalAttenuation) + ' StdDev: ' + repr(standardDeviationOpticalAttenuation)) sliceNumber += 1 z -= 1 qt.QApplication.restoreOverrideCursor() logging.info( 'CALIBRATION data has been successfully parsed with averaging radius {0}mm ({1}px)' .format(centralRadiusMm, centralRadiusPixel)) self.calibrationDataArray = opticalAttenuationOfCentralCylinderTable return True
def cursorOff(self): """Turn off and save the current cursor so the user can see the background image during editing""" self.savedCursor = self.sliceWidget.cursor qt_BlankCursor = 10 self.sliceWidget.setCursor(qt.QCursor(qt_BlankCursor))
def alignPddToCalibration(self): qt.QApplication.setOverrideCursor(qt.QCursor(qt.Qt.BusyCursor)) error = -1.0 # Check the input arrays if self.pddDataArray.size == 0 or self.calibrationDataArray.size == 0: logging.error('Pdd or calibration data is empty') return error # Discard values of 0 from both ends of the data (it is considered invalid) self.calibrationDataCleanedArray = self.calibrationDataArray calibrationCleanedNumberOfRows = self.calibrationDataCleanedArray.shape[ 0] while self.calibrationDataCleanedArray[0, 1] == 0: self.calibrationDataCleanedArray = numpy.delete( self.calibrationDataCleanedArray, 0, 0) calibrationCleanedNumberOfRows = self.calibrationDataCleanedArray.shape[ 0] while self.calibrationDataCleanedArray[calibrationCleanedNumberOfRows - 1, 1] == 0: self.calibrationDataCleanedArray = numpy.delete( self.calibrationDataCleanedArray, calibrationCleanedNumberOfRows - 1, 0) calibrationCleanedNumberOfRows = self.calibrationDataCleanedArray.shape[ 0] # Remove outliers from calibration array self.calibrationDataCleanedArray = self.removeOutliersFromArray( self.calibrationDataCleanedArray, 5, 10, 0.0075)[0] # Do initial scaling of the calibration array based on the maximum values maxPdd = self.findMaxValueInArray(self.pddDataArray) maxCalibration = self.findMaxValueInArray( self.calibrationDataCleanedArray) initialScaling = maxPdd / maxCalibration # logging.debug('Initial scaling factor {0:.4f}'.format(initialScaling)) # Create the working structures self.minimizer = vtk.vtkAmoebaMinimizer() self.minimizer.SetFunction(curveAlignmentCalibrationFunction) self.minimizer.SetParameterValue("xTrans", 0) self.minimizer.SetParameterScale("xTrans", 2) self.minimizer.SetParameterValue("yScale", initialScaling) self.minimizer.SetParameterScale("yScale", 0.1) self.minimizer.SetParameterValue("yTrans", 0) self.minimizer.SetParameterScale("yTrans", 0.2) self.minimizer.SetMaxIterations(50) self.minimizer.Minimize() error = self.minimizer.GetFunctionValue() xTrans = self.minimizer.GetParameterValue("xTrans") yScale = self.minimizer.GetParameterValue("yScale") yTrans = self.minimizer.GetParameterValue("yTrans") # Create aligned array self.createAlignedCalibrationArray(xTrans, yScale, yTrans) qt.QApplication.restoreOverrideCursor() logging.info( 'CALIBRATION successfully aligned with PDD with error={0:.2f} and parameters xTrans={1:.2f}, yScale={2:.2f}, yTrans={3:.2f}' .format(error, xTrans, yScale, yTrans)) return [error, xTrans, yScale, yTrans]