def onCreatePresetPressed(self): if self.registrationPresetSelector.currentIndex != self.newPresetIndex: return self.newPresetBox = qt.QDialog() self.customPresetLayout = qt.QVBoxLayout() self.addParameterFile() addPresetButton = qt.QPushButton("Add more presets...") addPresetButton.connect("clicked(bool)", self.addParameterFile) self.customPresetLayout.addWidget(addPresetButton) self.newPresetBox.setLayout(self.customPresetLayout) # Add fields to specify descriptions, etc... for that preset (to be included in the XML file) groupBox = qt.QGroupBox() formLayout = qt.QFormLayout() self.contentBox = qt.QLineEdit() formLayout.addRow("Content: ", self.contentBox) self.descriptionBox = qt.QLineEdit() formLayout.addRow("Description: ", self.descriptionBox) self.idBox = qt.QLineEdit() formLayout.addRow("Id: ", self.idBox) self.modalityBox = qt.QLineEdit() formLayout.addRow("Modality: ", self.modalityBox) self.publicationsBox = qt.QPlainTextEdit() formLayout.addRow("Publications: ", self.publicationsBox) groupBox.setLayout(formLayout) self.customPresetLayout.addWidget(groupBox) # Add Ok/Cancel buttons and connect them to the main dialog buttonBox = qt.QDialogButtonBox() buttonBox.setStandardButtons(qt.QDialogButtonBox.Ok | qt.QDialogButtonBox.Cancel) buttonBox.setCenterButtons(True) buttonBox.connect("accepted()", self.newPresetBox.accept) buttonBox.connect("rejected()", self.newPresetBox.reject) self.customPresetLayout.addWidget(buttonBox) response = self.newPresetBox.exec_() if response: self.createPreset()
def setup(self): ScriptedLoadableModuleWidget.setup(self) self.logic = EAMapReaderLogic() self.logic.logCallback = self.addLog self.logic.progressCallback = self.updateProgress self.loadingInProgress = False # Instantiate and connect widgets ... self.buttonVelocity = qt.QPushButton("Ensite Velocity / Precision") self.buttonVelocity.toolTip = "Import Ensite map." self.buttonVelocity.enabled = True self.layout.addWidget(self.buttonVelocity) self.buttonCarto = qt.QPushButton("CARTO 3") self.buttonCarto.toolTip = "Import CARTO 3 map." self.buttonCarto.enabled = True self.layout.addWidget(self.buttonCarto) self.buttonRhythmia = qt.QPushButton("RHYTHMIA") self.buttonRhythmia.toolTip = "Import RHYTHMIA Map." self.buttonRhythmia.enabled = True self.layout.addWidget(self.buttonRhythmia) self.statusLabel = qt.QPlainTextEdit() self.statusLabel.setTextInteractionFlags(qt.Qt.TextSelectableByMouse) self.statusLabel.setCenterOnScroll(True) self.layout.addWidget(self.statusLabel) self.progressBar=qt.QProgressBar() self.progressBar.setRange(0, 100) self.progressBar.setValue(0) self.layout.addWidget(self.progressBar) # connections self.buttonVelocity.connect('clicked(bool)', self.onButtonVelocity) self.buttonCarto.connect('clicked(bool)', self.onButtonCarto) self.buttonRhythmia.connect('clicked(bool)', self.onButtonRhythmia)
def setup(self): ScriptedLoadableModuleWidget.setup(self) self.logic = ElastixLogic() self.logic.logCallback = self.addLog self.registrationInProgress = False # Instantiate and connect widgets ... # Parameter sets defaultinputParametersCollapsibleButton = ctk.ctkCollapsibleButton() defaultinputParametersCollapsibleButton.text = "Parameter set" defaultinputParametersCollapsibleButton.collapsed = True self.layout.addWidget(defaultinputParametersCollapsibleButton) defaultParametersLayout = qt.QFormLayout(defaultinputParametersCollapsibleButton) self.parameterNodeSelector = slicer.qMRMLNodeComboBox() self.parameterNodeSelector.nodeTypes = ["vtkMRMLScriptedModuleNode"] self.parameterNodeSelector.addAttribute( "vtkMRMLScriptedModuleNode", "ModuleName", "Elastix" ) self.parameterNodeSelector.selectNodeUponCreation = True self.parameterNodeSelector.addEnabled = True self.parameterNodeSelector.renameEnabled = True self.parameterNodeSelector.removeEnabled = True self.parameterNodeSelector.noneEnabled = False self.parameterNodeSelector.showHidden = True self.parameterNodeSelector.showChildNodeTypes = False self.parameterNodeSelector.baseName = "General Registration (Elastix)" self.parameterNodeSelector.setMRMLScene( slicer.mrmlScene ) self.parameterNodeSelector.setToolTip( "Pick parameter set" ) defaultParametersLayout.addRow("Parameter set: ", self.parameterNodeSelector) # # Inputs # inputParametersCollapsibleButton = ctk.ctkCollapsibleButton() inputParametersCollapsibleButton.text = "Inputs" self.layout.addWidget(inputParametersCollapsibleButton) # Layout within the dummy collapsible button inputParametersFormLayout = qt.QFormLayout(inputParametersCollapsibleButton) # # fixed volume selector # self.fixedVolumeSelector = slicer.qMRMLNodeComboBox() self.fixedVolumeSelector.nodeTypes = ["vtkMRMLScalarVolumeNode"] self.fixedVolumeSelector.selectNodeUponCreation = True self.fixedVolumeSelector.addEnabled = False self.fixedVolumeSelector.removeEnabled = False self.fixedVolumeSelector.noneEnabled = False self.fixedVolumeSelector.showHidden = False self.fixedVolumeSelector.showChildNodeTypes = False self.fixedVolumeSelector.setMRMLScene( slicer.mrmlScene ) self.fixedVolumeSelector.setToolTip( "The moving volume will be transformed into this image space." ) inputParametersFormLayout.addRow("Fixed volume: ", self.fixedVolumeSelector) # # moving volume selector # self.movingVolumeSelector = slicer.qMRMLNodeComboBox() self.movingVolumeSelector.nodeTypes = ["vtkMRMLScalarVolumeNode"] self.movingVolumeSelector.selectNodeUponCreation = True self.movingVolumeSelector.addEnabled = False self.movingVolumeSelector.removeEnabled = False self.movingVolumeSelector.noneEnabled = False self.movingVolumeSelector.showHidden = False self.movingVolumeSelector.showChildNodeTypes = False self.movingVolumeSelector.setMRMLScene( slicer.mrmlScene ) self.movingVolumeSelector.setToolTip( "This volume will be transformed into the fixed image space" ) inputParametersFormLayout.addRow("Moving volume: ", self.movingVolumeSelector) self.registrationPresetSelector = qt.QComboBox() for preset in self.logic.getRegistrationPresets(): self.registrationPresetSelector.addItem("{0} ({1})".format(preset[RegistrationPresets_Modality], preset[RegistrationPresets_Content])) inputParametersFormLayout.addRow("Preset: ", self.registrationPresetSelector) # # Outputs # maskingParametersCollapsibleButton = ctk.ctkCollapsibleButton() maskingParametersCollapsibleButton.text = "Masking" maskingParametersCollapsibleButton.collapsed = True self.layout.addWidget(maskingParametersCollapsibleButton) # Layout within the dummy collapsible button maskingParametersFormLayout = qt.QFormLayout(maskingParametersCollapsibleButton) # # fixed volume mask selector # self.fixedVolumeMaskSelector = slicer.qMRMLNodeComboBox() self.fixedVolumeMaskSelector.nodeTypes = ["vtkMRMLLabelMapVolumeNode"] self.fixedVolumeMaskSelector.addEnabled = False self.fixedVolumeMaskSelector.removeEnabled = False self.fixedVolumeMaskSelector.noneEnabled = True self.fixedVolumeMaskSelector.showHidden = False self.fixedVolumeMaskSelector.showChildNodeTypes = False self.fixedVolumeMaskSelector.setMRMLScene( slicer.mrmlScene ) self.fixedVolumeMaskSelector.setToolTip("Areas of the fixed volume where mask label is 0 will be ignored in the registration.") maskingParametersFormLayout.addRow("Fixed volume mask: ", self.fixedVolumeMaskSelector) # # moving volume mask selector # self.movingVolumeMaskSelector = slicer.qMRMLNodeComboBox() self.movingVolumeMaskSelector.nodeTypes = ["vtkMRMLLabelMapVolumeNode"] self.movingVolumeMaskSelector.selectNodeUponCreation = True self.movingVolumeMaskSelector.addEnabled = False self.movingVolumeMaskSelector.removeEnabled = False self.movingVolumeMaskSelector.noneEnabled = True self.movingVolumeMaskSelector.showHidden = False self.movingVolumeMaskSelector.showChildNodeTypes = False self.movingVolumeMaskSelector.setMRMLScene( slicer.mrmlScene ) self.movingVolumeMaskSelector.setToolTip("Areas of the moving volume where mask label is 0 will be ignored in the registration") maskingParametersFormLayout.addRow("Moving volume mask: ", self.movingVolumeMaskSelector) # # Outputs # outputParametersCollapsibleButton = ctk.ctkCollapsibleButton() outputParametersCollapsibleButton.text = "Outputs" self.layout.addWidget(outputParametersCollapsibleButton) # Layout within the dummy collapsible button outputParametersFormLayout = qt.QFormLayout(outputParametersCollapsibleButton) # # output volume selector # self.outputVolumeSelector = slicer.qMRMLNodeComboBox() self.outputVolumeSelector.nodeTypes = ["vtkMRMLScalarVolumeNode"] self.outputVolumeSelector.selectNodeUponCreation = True self.outputVolumeSelector.addEnabled = True self.outputVolumeSelector.renameEnabled = True self.outputVolumeSelector.removeEnabled = True self.outputVolumeSelector.noneEnabled = True self.outputVolumeSelector.showHidden = False self.outputVolumeSelector.showChildNodeTypes = False self.outputVolumeSelector.setMRMLScene( slicer.mrmlScene ) self.outputVolumeSelector.setToolTip( "(optional) The moving image warped to the fixed image space. NOTE: You must set at least one output object (transform and/or output volume)" ) outputParametersFormLayout.addRow("Output volume: ", self.outputVolumeSelector) # # output transform selector # self.outputTransformSelector = slicer.qMRMLNodeComboBox() self.outputTransformSelector.nodeTypes = ["vtkMRMLTransformNode"] self.outputTransformSelector.selectNodeUponCreation = True self.outputTransformSelector.addEnabled = True self.outputTransformSelector.renameEnabled = True self.outputTransformSelector.removeEnabled = True self.outputTransformSelector.noneEnabled = True self.outputTransformSelector.showHidden = False self.outputTransformSelector.showChildNodeTypes = False self.outputTransformSelector.setMRMLScene( slicer.mrmlScene ) self.outputTransformSelector.setToolTip( "(optional) Computed displacement field that transform nodes from moving volume space to fixed volume space. NOTE: You must set at least one output object (transform and/or output volume)." ) outputParametersFormLayout.addRow("Output transform: ", self.outputTransformSelector) # # Advanced area # self.advancedCollapsibleButton = ctk.ctkCollapsibleButton() self.advancedCollapsibleButton.text = "Advanced" self.advancedCollapsibleButton.collapsed = True self.layout.addWidget(self.advancedCollapsibleButton) advancedFormLayout = qt.QFormLayout(self.advancedCollapsibleButton) self.showDetailedLogDuringExecutionCheckBox = qt.QCheckBox(" ") self.showDetailedLogDuringExecutionCheckBox.checked = False self.showDetailedLogDuringExecutionCheckBox.setToolTip("Show detailed log during registration.") advancedFormLayout.addRow("Show detailed log during registration:", self.showDetailedLogDuringExecutionCheckBox) self.keepTemporaryFilesCheckBox = qt.QCheckBox(" ") self.keepTemporaryFilesCheckBox.checked = False self.keepTemporaryFilesCheckBox.setToolTip("Keep temporary files (inputs, computed outputs, logs) after the registration is completed.") self.showTemporaryFilesFolderButton = qt.QPushButton("Show temp folder") self.showTemporaryFilesFolderButton.toolTip = "Open the folder where temporary files are stored." self.showTemporaryFilesFolderButton.setSizePolicy(qt.QSizePolicy.MinimumExpanding, qt.QSizePolicy.Preferred) hbox = qt.QHBoxLayout() hbox.addWidget(self.keepTemporaryFilesCheckBox) hbox.addWidget(self.showTemporaryFilesFolderButton) advancedFormLayout.addRow("Keep temporary files:", hbox) self.showRegistrationParametersDatabaseFolderButton = qt.QPushButton("Show database folder") self.showRegistrationParametersDatabaseFolderButton.toolTip = "Open the folder where temporary files are stored." self.showRegistrationParametersDatabaseFolderButton.setSizePolicy(qt.QSizePolicy.MinimumExpanding, qt.QSizePolicy.Preferred) advancedFormLayout.addRow("Registration presets:", self.showRegistrationParametersDatabaseFolderButton) customElastixBinDir = self.logic.getCustomElastixBinDir() self.customElastixBinDirSelector = ctk.ctkPathLineEdit() self.customElastixBinDirSelector.filters = ctk.ctkPathLineEdit.Dirs self.customElastixBinDirSelector.setCurrentPath(customElastixBinDir) self.customElastixBinDirSelector.setSizePolicy(qt.QSizePolicy.MinimumExpanding, qt.QSizePolicy.Preferred) self.customElastixBinDirSelector.setToolTip("Set bin directory of an Elastix installation (where elastix executable is located). " "If value is empty then default elastix (bundled with SlicerElastix extension) will be used.") advancedFormLayout.addRow("Custom Elastix toolbox location:", self.customElastixBinDirSelector) # # Apply Button # self.applyButton = qt.QPushButton("Apply") self.applyButton.toolTip = "Run the algorithm." self.applyButton.enabled = False self.layout.addWidget(self.applyButton) self.statusLabel = qt.QPlainTextEdit() self.statusLabel.setTextInteractionFlags(qt.Qt.TextSelectableByMouse) self.statusLabel.setCenterOnScroll(True) self.layout.addWidget(self.statusLabel) # connections self.applyButton.connect('clicked(bool)', self.onApplyButton) self.showTemporaryFilesFolderButton.connect('clicked(bool)', self.onShowTemporaryFilesFolder) self.showRegistrationParametersDatabaseFolderButton.connect('clicked(bool)', self.onShowRegistrationParametersDatabaseFolder) self.fixedVolumeSelector.connect("currentNodeChanged(vtkMRMLNode*)", self.onSelect) self.movingVolumeSelector.connect("currentNodeChanged(vtkMRMLNode*)", self.onSelect) self.outputVolumeSelector.connect("currentNodeChanged(vtkMRMLNode*)", self.onSelect) self.outputTransformSelector.connect("currentNodeChanged(vtkMRMLNode*)", self.onSelect) # Immediately update deleteTemporaryFiles in the logic to make it possible to decide to # keep the temporary file while the registration is running self.keepTemporaryFilesCheckBox.connect("toggled(bool)", self.onKeepTemporaryFilesToggled) # Add vertical spacer self.layout.addStretch(1) # Refresh Apply button state self.onSelect()
def setup(self): ScriptedLoadableModuleWidget.setup(self) self.logic = SegmentMesherLogic() self.logic.logCallback = self.addLog self.modelGenerationInProgress = False # Instantiate and connect widgets ... # Parameter sets defaultinputParametersCollapsibleButton = ctk.ctkCollapsibleButton() defaultinputParametersCollapsibleButton.text = "Parameter set" defaultinputParametersCollapsibleButton.collapsed = True self.layout.addWidget(defaultinputParametersCollapsibleButton) defaultParametersLayout = qt.QFormLayout(defaultinputParametersCollapsibleButton) self.parameterNodeSelector = slicer.qMRMLNodeComboBox() self.parameterNodeSelector.nodeTypes = ["vtkMRMLScriptedModuleNode"] self.parameterNodeSelector.addAttribute( "vtkMRMLScriptedModuleNode", "ModuleName", "SegmentMesher" ) self.parameterNodeSelector.selectNodeUponCreation = True self.parameterNodeSelector.addEnabled = True self.parameterNodeSelector.renameEnabled = True self.parameterNodeSelector.removeEnabled = True self.parameterNodeSelector.noneEnabled = False self.parameterNodeSelector.showHidden = True self.parameterNodeSelector.showChildNodeTypes = False self.parameterNodeSelector.baseName = "SegmentMesher" self.parameterNodeSelector.setMRMLScene( slicer.mrmlScene ) self.parameterNodeSelector.setToolTip( "Pick parameter set" ) defaultParametersLayout.addRow("Parameter set: ", self.parameterNodeSelector) # # Inputs # inputParametersCollapsibleButton = ctk.ctkCollapsibleButton() inputParametersCollapsibleButton.text = "Inputs" self.layout.addWidget(inputParametersCollapsibleButton) # Layout within the dummy collapsible button inputParametersFormLayout = qt.QFormLayout(inputParametersCollapsibleButton) self.inputModelSelector = slicer.qMRMLNodeComboBox() self.inputModelSelector.nodeTypes = ["vtkMRMLSegmentationNode"] self.inputModelSelector.selectNodeUponCreation = True self.inputModelSelector.addEnabled = False self.inputModelSelector.removeEnabled = False self.inputModelSelector.noneEnabled = False self.inputModelSelector.showHidden = False self.inputModelSelector.showChildNodeTypes = False self.inputModelSelector.setMRMLScene( slicer.mrmlScene ) self.inputModelSelector.setToolTip( "Volumetric mesh will be generated for all visible segments in this segmentation node." ) inputParametersFormLayout.addRow("Input segmentation: ", self.inputModelSelector) self.methodSelectorComboBox = qt.QComboBox() self.methodSelectorComboBox.addItem("Cleaver", METHOD_CLEAVER) self.methodSelectorComboBox.addItem("TetGen", METHOD_TETGEN) inputParametersFormLayout.addRow("Meshing method: ", self.methodSelectorComboBox) # # Outputs # outputParametersCollapsibleButton = ctk.ctkCollapsibleButton() outputParametersCollapsibleButton.text = "Outputs" self.layout.addWidget(outputParametersCollapsibleButton) outputParametersFormLayout = qt.QFormLayout(outputParametersCollapsibleButton) # # output volume selector # self.outputModelSelector = slicer.qMRMLNodeComboBox() self.outputModelSelector.nodeTypes = ["vtkMRMLModelNode"] self.outputModelSelector.selectNodeUponCreation = True self.outputModelSelector.addEnabled = True self.outputModelSelector.renameEnabled = True self.outputModelSelector.removeEnabled = True self.outputModelSelector.noneEnabled = False self.outputModelSelector.showHidden = False self.outputModelSelector.showChildNodeTypes = False self.outputModelSelector.setMRMLScene( slicer.mrmlScene ) self.outputModelSelector.setToolTip( "Created volumetric mesh" ) outputParametersFormLayout.addRow("Output model: ", self.outputModelSelector) # # Advanced area # self.advancedCollapsibleButton = ctk.ctkCollapsibleButton() self.advancedCollapsibleButton.text = "Advanced" self.advancedCollapsibleButton.collapsed = True self.layout.addWidget(self.advancedCollapsibleButton) advancedFormLayout = qt.QFormLayout(self.advancedCollapsibleButton) self.cleaverAdditionalParametersWidget = qt.QLineEdit() self.cleaverAdditionalParametersWidget.setToolTip('Increase --scale parameter value to generate a finer resolution mesh. See description of all parameters in module documentation (Help & Acknowledgment section).') advancedFormLayout.addRow("Cleaver meshing options:", self.cleaverAdditionalParametersWidget) self.cleaverAdditionalParametersWidget.text = "--scale 0.2 --multiplier 2 --grading 5" self.cleaverRemoveBackgroundMeshCheckBox = qt.QCheckBox(" ") self.cleaverRemoveBackgroundMeshCheckBox.checked = True self.cleaverRemoveBackgroundMeshCheckBox.setToolTip("Remove background mesh (filling segmentation reference geometry box).") advancedFormLayout.addRow("Cleaver remove background mesh:", self.cleaverRemoveBackgroundMeshCheckBox) self.cleaverPaddingPercentSpinBox = qt.QSpinBox() self.cleaverPaddingPercentSpinBox.maximum = 200 self.cleaverPaddingPercentSpinBox.value = 10 self.cleaverPaddingPercentSpinBox.suffix=" %" self.cleaverPaddingPercentSpinBox.setToolTip("Add padding around the segments to ensure some minimum thickness to the background mesh. Increase value if segments have extrusions towards the edge of the padded bounding box.") advancedFormLayout.addRow("Cleaver background padding:", self.cleaverPaddingPercentSpinBox) customCleaverPath = self.logic.getCustomCleaverPath() self.customCleaverPathSelector = ctk.ctkPathLineEdit() self.customCleaverPathSelector.setCurrentPath(customCleaverPath) self.customCleaverPathSelector.nameFilters = [self.logic.cleaverFilename] self.customCleaverPathSelector.setSizePolicy(qt.QSizePolicy.MinimumExpanding, qt.QSizePolicy.Preferred) self.customCleaverPathSelector.setToolTip("Set cleaver-cli executable path. " "If value is empty then cleaver-cli bundled with this extension will be used.") advancedFormLayout.addRow("Custom Cleaver executable path:", self.customCleaverPathSelector) self.tetGenAdditionalParametersWidget = qt.QLineEdit() self.tetGenAdditionalParametersWidget.setToolTip('See description of parameters in module documentation (Help & Acknowledgment section).') advancedFormLayout.addRow("TetGen meshing options:", self.tetGenAdditionalParametersWidget) self.tetGenAdditionalParametersWidget.text = "" customTetGenPath = self.logic.getCustomTetGenPath() self.customTetGenPathSelector = ctk.ctkPathLineEdit() self.customTetGenPathSelector.setCurrentPath(customTetGenPath) self.customTetGenPathSelector.nameFilters = [self.logic.tetGenFilename] self.customTetGenPathSelector.setSizePolicy(qt.QSizePolicy.MinimumExpanding, qt.QSizePolicy.Preferred) self.customTetGenPathSelector.setToolTip("Set tetgen executable path. " "If value is empty then tetgen bundled with this extension will be used.") advancedFormLayout.addRow("Custom TetGen executable path:", self.customTetGenPathSelector) self.showDetailedLogDuringExecutionCheckBox = qt.QCheckBox(" ") self.showDetailedLogDuringExecutionCheckBox.checked = False self.showDetailedLogDuringExecutionCheckBox.setToolTip("Show detailed log during model generation.") advancedFormLayout.addRow("Show detailed log:", self.showDetailedLogDuringExecutionCheckBox) self.keepTemporaryFilesCheckBox = qt.QCheckBox(" ") self.keepTemporaryFilesCheckBox.checked = False self.keepTemporaryFilesCheckBox.setToolTip("Keep temporary files (inputs, computed outputs, logs) after the model generation is completed.") self.showTemporaryFilesFolderButton = qt.QPushButton("Show temp folder") self.showTemporaryFilesFolderButton.toolTip = "Open the folder where temporary files are stored." self.showTemporaryFilesFolderButton.setSizePolicy(qt.QSizePolicy.MinimumExpanding, qt.QSizePolicy.Preferred) hbox = qt.QHBoxLayout() hbox.addWidget(self.keepTemporaryFilesCheckBox) hbox.addWidget(self.showTemporaryFilesFolderButton) advancedFormLayout.addRow("Keep temporary files:", hbox) # # Display # displayParametersCollapsibleButton = ctk.ctkCollapsibleButton() displayParametersCollapsibleButton.text = "Display" displayParametersCollapsibleButton.collapsed = True self.layout.addWidget(displayParametersCollapsibleButton) displayParametersFormLayout = qt.QFormLayout(displayParametersCollapsibleButton) self.clipNodeWidget=slicer.qMRMLClipNodeWidget() clipNode = slicer.mrmlScene.GetFirstNodeByClass("vtkMRMLClipModelsNode") self.clipNodeWidget.setMRMLClipNode(clipNode) displayParametersFormLayout.addRow(self.clipNodeWidget) # # Apply Button # self.applyButton = qt.QPushButton("Apply") self.applyButton.toolTip = "Run the algorithm." self.applyButton.enabled = False self.layout.addWidget(self.applyButton) self.statusLabel = qt.QPlainTextEdit() self.statusLabel.setTextInteractionFlags(qt.Qt.TextSelectableByMouse) self.statusLabel.setCenterOnScroll(True) self.layout.addWidget(self.statusLabel) # connections self.applyButton.connect('clicked(bool)', self.onApplyButton) self.showTemporaryFilesFolderButton.connect('clicked(bool)', self.onShowTemporaryFilesFolder) self.inputModelSelector.connect("currentNodeChanged(vtkMRMLNode*)", self.updateMRMLFromGUI) self.outputModelSelector.connect("currentNodeChanged(vtkMRMLNode*)", self.updateMRMLFromGUI) self.methodSelectorComboBox.connect("currentIndexChanged(int)", self.updateMRMLFromGUI) # Immediately update deleteTemporaryFiles in the logic to make it possible to decide to # keep the temporary file while the model generation is running self.keepTemporaryFilesCheckBox.connect("toggled(bool)", self.onKeepTemporaryFilesToggled) # Add vertical spacer self.layout.addStretch(1) # Refresh Apply button state self.updateMRMLFromGUI()
def setup(self): ScriptedLoadableModuleWidget.setup(self) # Instantiate and connect widgets ... # # Parameters Area # parametersCollapsibleButton = ctk.ctkCollapsibleButton() parametersCollapsibleButton.text = "Input Parameters" self.layout.addWidget(parametersCollapsibleButton) # Layout within the dummy collapsible button parametersFormLayout = qt.QFormLayout(parametersCollapsibleButton) # # Select base mesh # self.modelSelector = slicer.qMRMLNodeComboBox() self.modelSelector.nodeTypes = (("vtkMRMLModelNode"), "") self.modelSelector.selectNodeUponCreation = False self.modelSelector.addEnabled = False self.modelSelector.removeEnabled = False self.modelSelector.noneEnabled = True self.modelSelector.showHidden = False self.modelSelector.setMRMLScene(slicer.mrmlScene) parametersFormLayout.addRow("Base mesh: ", self.modelSelector) # # Set spacing tolerance # self.spacingTolerance = ctk.ctkSliderWidget() self.spacingTolerance.singleStep = .1 self.spacingTolerance.minimum = 0 self.spacingTolerance.maximum = 10 self.spacingTolerance.value = 4 self.spacingTolerance.setToolTip( "Set tolerance of spacing as a percentage of the image diagonal") parametersFormLayout.addRow("Spacing tolerance: ", self.spacingTolerance) # # Parameters Area # templateCollapsibleButton = ctk.ctkCollapsibleButton() templateCollapsibleButton.text = "Template Geometry" self.layout.addWidget(templateCollapsibleButton) # Layout within the dummy collapsible button templateFormLayout = qt.QFormLayout(templateCollapsibleButton) # # Select geometry of template # self.OriginalType = qt.QRadioButton() self.OriginalType.setChecked(True) self.EllipseType = qt.QRadioButton() self.SphereType = qt.QRadioButton() templateFormLayout.addRow("Original Geometry", self.OriginalType) templateFormLayout.addRow("Ellipse", self.EllipseType) templateFormLayout.addRow("Sphere", self.SphereType) # # Specify plane of symmetry # self.planeSelector = slicer.qMRMLNodeComboBox() self.planeSelector.nodeTypes = (("vtkMRMLMarkupsPlaneNode"), "") self.planeSelector.enabled = True self.planeSelector.selectNodeUponCreation = False self.planeSelector.addEnabled = False self.planeSelector.removeEnabled = False self.planeSelector.noneEnabled = True self.planeSelector.showHidden = False self.planeSelector.setMRMLScene(slicer.mrmlScene) templateFormLayout.addRow("Symmetry plane: ", self.planeSelector) # # Set template scale factor # self.scaleFactor = ctk.ctkSliderWidget() self.scaleFactor.enabled = False self.scaleFactor.singleStep = 1 self.scaleFactor.minimum = 75 self.scaleFactor.maximum = 150 self.scaleFactor.value = 110 self.scaleFactor.setToolTip( "Set template scale factor as a percentage of the image diagonal") templateFormLayout.addRow("Template scale factor : ", self.scaleFactor) # # Set max projection factor # self.projectionFactor = ctk.ctkSliderWidget() self.projectionFactor.enabled = False self.projectionFactor.singleStep = 1 self.projectionFactor.minimum = 1 self.projectionFactor.maximum = 200 self.projectionFactor.value = 200 self.projectionFactor.setToolTip( "Set maximum projection as a percentage of the image diagonal") templateFormLayout.addRow("Maximum projection factor : ", self.projectionFactor) # # Run Area # samplingCollapsibleButton = ctk.ctkCollapsibleButton() samplingCollapsibleButton.text = "Run Sampling" self.layout.addWidget(samplingCollapsibleButton) # Layout within the dummy collapsible button samplingFormLayout = qt.QFormLayout(samplingCollapsibleButton) # # Get Subsample Rate Button # self.getPointNumberButton = qt.QPushButton("Get subsample number") self.getPointNumberButton.toolTip = "Output the number of points sampled on the template shape." self.getPointNumberButton.enabled = False samplingFormLayout.addRow(self.getPointNumberButton) # # Subsample Information # self.subsampleInfo = qt.QPlainTextEdit() self.subsampleInfo.setPlaceholderText("Subsampling information") self.subsampleInfo.setReadOnly(True) samplingFormLayout.addRow(self.subsampleInfo) # # Apply sphere button # self.applySphereButton = qt.QPushButton("Generate template") self.applySphereButton.toolTip = "Generate sampled template shape." self.applySphereButton.enabled = False samplingFormLayout.addRow(self.applySphereButton) # # Project Points button # self.projectPointsButton = qt.QPushButton("Project points to surface") self.projectPointsButton.toolTip = "Project the points from the sampled template to the model surface." self.projectPointsButton.enabled = False samplingFormLayout.addRow(self.projectPointsButton) # # Clean Points button # self.cleanButton = qt.QPushButton("Enforce spatial sampling rate") self.cleanButton.toolTip = "Remove points spaced closer than the user-specified tolerance." self.cleanButton.enabled = False samplingFormLayout.addRow(self.cleanButton) # connections self.modelSelector.connect('currentNodeChanged(vtkMRMLNode*)', self.onSelect) self.OriginalType.connect('toggled(bool)', self.onToggleModel) self.getPointNumberButton.connect('clicked(bool)', self.onGetPointNumberButton) self.applySphereButton.connect('clicked(bool)', self.onApplySphereButton) self.projectPointsButton.connect('clicked(bool)', self.onProjectPointsButton) self.cleanButton.connect('clicked(bool)', self.onCleanButton) # Add vertical spacer self.layout.addStretch(1)
def setup(self): ScriptedLoadableModuleWidget.setup(self) # Set up tabs to split workflow tabsWidget = qt.QTabWidget() alignSingleTab = qt.QWidget() alignSingleTabLayout = qt.QFormLayout(alignSingleTab) alignMultiTab = qt.QWidget() alignMultiTabLayout = qt.QFormLayout(alignMultiTab) tabsWidget.addTab(alignSingleTab, "Single Alignment") tabsWidget.addTab(alignMultiTab, "Batch processing") self.layout.addWidget(tabsWidget) # Layout within the tab alignSingleWidget = ctk.ctkCollapsibleButton() alignSingleWidgetLayout = qt.QFormLayout(alignSingleWidget) alignSingleWidget.text = "Align and subsample a source and reference mesh " alignSingleTabLayout.addRow(alignSingleWidget) # # Select source mesh # self.sourceModelSelector = ctk.ctkPathLineEdit() self.sourceModelSelector.filters = ctk.ctkPathLineEdit().Files self.sourceModelSelector.nameFilters = ["*.ply"] alignSingleWidgetLayout.addRow("Source mesh: ", self.sourceModelSelector) # # Select source landmarks # self.sourceFiducialSelector = ctk.ctkPathLineEdit() self.sourceFiducialSelector.filters = ctk.ctkPathLineEdit().Files self.sourceFiducialSelector.nameFilters = ["*.fcsv"] alignSingleWidgetLayout.addRow("Source landmarks: ", self.sourceFiducialSelector) # Select target mesh # self.targetModelSelector = ctk.ctkPathLineEdit() self.targetModelSelector.filters = ctk.ctkPathLineEdit().Files self.targetModelSelector.nameFilters = ["*.ply"] alignSingleWidgetLayout.addRow("Reference mesh: ", self.targetModelSelector) self.skipScalingCheckBox = qt.QCheckBox() self.skipScalingCheckBox.checked = 0 self.skipScalingCheckBox.setToolTip( "If checked, PointCloudRegistration will skip scaling during the alignment (Not recommended)." ) alignSingleWidgetLayout.addRow("Skip scaling", self.skipScalingCheckBox) [ self.pointDensity, self.normalSearchRadius, self.FPFHSearchRadius, self.distanceThreshold, self.maxRANSAC, self.maxRANSACValidation, self.ICPDistanceThreshold ] = self.addAdvancedMenu(alignSingleWidgetLayout) # Advanced tab connections self.pointDensity.connect('valueChanged(double)', self.onChangeAdvanced) self.normalSearchRadius.connect('valueChanged(double)', self.onChangeAdvanced) self.FPFHSearchRadius.connect('valueChanged(double)', self.onChangeAdvanced) self.distanceThreshold.connect('valueChanged(double)', self.onChangeAdvanced) self.maxRANSAC.connect('valueChanged(double)', self.onChangeAdvanced) self.maxRANSACValidation.connect('valueChanged(double)', self.onChangeAdvanced) self.ICPDistanceThreshold.connect('valueChanged(double)', self.onChangeAdvanced) # # Subsample Button # self.subsampleButton = qt.QPushButton("Run subsampling") self.subsampleButton.toolTip = "Run subsampling of the source and reference meshes" self.subsampleButton.enabled = False alignSingleWidgetLayout.addRow(self.subsampleButton) # # Subsample Information # self.subsampleInfo = qt.QPlainTextEdit() self.subsampleInfo.setPlaceholderText("Subsampling information") self.subsampleInfo.setReadOnly(True) alignSingleWidgetLayout.addRow(self.subsampleInfo) # # Align Button # self.alignButton = qt.QPushButton("Run rigid alignment") self.alignButton.toolTip = "Run rigid alignment of the source and reference meshes" self.alignButton.enabled = False alignSingleWidgetLayout.addRow(self.alignButton) # # Plot Aligned Mesh Button # self.displayMeshButton = qt.QPushButton("Display alignment") self.displayMeshButton.toolTip = "Display rigid alignment of the source and references meshes" self.displayMeshButton.enabled = False alignSingleWidgetLayout.addRow(self.displayMeshButton) # connections self.sourceModelSelector.connect('validInputChanged(bool)', self.onSelect) self.sourceFiducialSelector.connect('validInputChanged(bool)', self.onSelect) self.targetModelSelector.connect('validInputChanged(bool)', self.onSelect) self.subsampleButton.connect('clicked(bool)', self.onSubsampleButton) self.alignButton.connect('clicked(bool)', self.onAlignButton) self.displayMeshButton.connect('clicked(bool)', self.onDisplayMeshButton) # Layout within the multiprocessing tab alignMultiWidget = ctk.ctkCollapsibleButton() alignMultiWidgetLayout = qt.QFormLayout(alignMultiWidget) alignMultiWidget.text = "Alings landmarks from multiple specimens to a reference 3d model (mesh)" alignMultiTabLayout.addRow(alignMultiWidget) # # Select source mesh # self.sourceModelMultiSelector = ctk.ctkPathLineEdit() self.sourceModelMultiSelector.filters = ctk.ctkPathLineEdit.Dirs self.sourceModelMultiSelector.toolTip = "Select the directory containing the source meshes" alignMultiWidgetLayout.addRow("Source mesh directory: ", self.sourceModelMultiSelector) # # Select source landmark file # self.sourceFiducialMultiSelector = ctk.ctkPathLineEdit() self.sourceFiducialMultiSelector.filters = ctk.ctkPathLineEdit.Dirs self.sourceFiducialMultiSelector.toolTip = "Select the directory containing the source landmarks" alignMultiWidgetLayout.addRow("Source landmark directory: ", self.sourceFiducialMultiSelector) # Select target mesh directory # self.targetModelMultiSelector = ctk.ctkPathLineEdit() self.targetModelMultiSelector.filters = ctk.ctkPathLineEdit().Files self.targetModelMultiSelector.nameFilters = ["*.ply"] alignMultiWidgetLayout.addRow("Reference mesh: ", self.targetModelMultiSelector) # Select output landmark directory # self.landmarkOutputSelector = ctk.ctkPathLineEdit() self.landmarkOutputSelector.filters = ctk.ctkPathLineEdit.Dirs self.landmarkOutputSelector.toolTip = "Select the output directory where the landmarks will be saved" alignMultiWidgetLayout.addRow("Output landmark directory: ", self.landmarkOutputSelector) self.skipScalingMultiCheckBox = qt.QCheckBox() self.skipScalingMultiCheckBox.checked = 0 self.skipScalingMultiCheckBox.setToolTip( "If checked, PointCloudRegistration will skip scaling during the alignment." ) alignMultiWidgetLayout.addRow("Skip scaling", self.skipScalingMultiCheckBox) [ self.pointDensityMulti, self.normalSearchRadiusMulti, self.FPFHSearchRadiusMulti, self.distanceThresholdMulti, self.maxRANSACMulti, self.maxRANSACValidationMulti, self.ICPDistanceThresholdMulti ] = self.addAdvancedMenu(alignMultiWidgetLayout) # # Run landmarking Button # self.applyLandmarkMultiButton = qt.QPushButton( "Run PointCloud Registration") self.applyLandmarkMultiButton.toolTip = "Align the source meshes and landmarks with a reference mesh" self.applyLandmarkMultiButton.enabled = False alignMultiWidgetLayout.addRow(self.applyLandmarkMultiButton) # connections self.sourceModelMultiSelector.connect('validInputChanged(bool)', self.onSelectMultiProcess) self.sourceFiducialMultiSelector.connect('validInputChanged(bool)', self.onSelectMultiProcess) self.targetModelMultiSelector.connect('validInputChanged(bool)', self.onSelectMultiProcess) self.landmarkOutputSelector.connect('validInputChanged(bool)', self.onSelectMultiProcess) self.skipScalingMultiCheckBox.connect('validInputChanged(bool)', self.onSelectMultiProcess) self.applyLandmarkMultiButton.connect('clicked(bool)', self.onApplyLandmarkMulti) # Add vertical spacer self.layout.addStretch(1) # Advanced tab connections self.pointDensityMulti.connect('valueChanged(double)', self.updateParameterDictionary) self.normalSearchRadiusMulti.connect('valueChanged(double)', self.updateParameterDictionary) self.FPFHSearchRadiusMulti.connect('valueChanged(double)', self.updateParameterDictionary) self.distanceThresholdMulti.connect('valueChanged(double)', self.updateParameterDictionary) self.maxRANSACMulti.connect('valueChanged(double)', self.updateParameterDictionary) self.maxRANSACValidationMulti.connect('valueChanged(double)', self.updateParameterDictionary) self.ICPDistanceThresholdMulti.connect('valueChanged(double)', self.updateParameterDictionary) # initialize the parameter dictionary from single run parameters self.parameterDictionary = { "pointDensity": self.pointDensity.value, "normalSearchRadius": self.normalSearchRadius.value, "FPFHSearchRadius": self.FPFHSearchRadius.value, "distanceThreshold": self.distanceThreshold.value, "maxRANSAC": int(self.maxRANSAC.value), "maxRANSACValidation": int(self.maxRANSACValidation.value), "ICPDistanceThreshold": self.ICPDistanceThreshold.value } # initialize the parameter dictionary from multi run parameters self.parameterDictionaryMulti = { "pointDensity": self.pointDensityMulti.value, "normalSearchRadius": self.normalSearchRadiusMulti.value, "FPFHSearchRadius": self.FPFHSearchRadiusMulti.value, "distanceThreshold": self.distanceThresholdMulti.value, "maxRANSAC": int(self.maxRANSACMulti.value), "maxRANSACValidation": int(self.maxRANSACValidationMulti.value), "ICPDistanceThreshold": self.ICPDistanceThresholdMulti.value }
def setup(self): ScriptedLoadableModuleWidget.setup(self) # Instantiate and connect widgets ... # # Parameters Area # parametersCollapsibleButton = ctk.ctkCollapsibleButton() parametersCollapsibleButton.text = "Parameters" self.layout.addWidget(parametersCollapsibleButton) # Layout within the dummy collapsible button parametersFormLayout = qt.QFormLayout(parametersCollapsibleButton) self.inputDirSelector = ctk.ctkPathLineEdit() self.inputDirSelector.filters = ctk.ctkPathLineEdit.Dirs self.inputDirSelector.settingKey = 'DICOMPatcherInputDir' parametersFormLayout.addRow("Input DICOM directory:", self.inputDirSelector) self.outputDirSelector = ctk.ctkPathLineEdit() self.outputDirSelector.filters = ctk.ctkPathLineEdit.Dirs self.outputDirSelector.settingKey = 'DICOMPatcherOutputDir' parametersFormLayout.addRow("Output DICOM directory:", self.outputDirSelector) self.normalizeFileNamesCheckBox = qt.QCheckBox() self.normalizeFileNamesCheckBox.checked = True self.normalizeFileNamesCheckBox.setToolTip("Replace file and folder names with automatically generated names." " Fixes errors caused by file path containins special characters or being too long.") parametersFormLayout.addRow("Normalize file names", self.normalizeFileNamesCheckBox) self.forceSamePatientNameIdInEachDirectoryCheckBox = qt.QCheckBox() self.forceSamePatientNameIdInEachDirectoryCheckBox.checked = False self.forceSamePatientNameIdInEachDirectoryCheckBox.setToolTip("Generate patient name and ID from the first file in a directory" " and force all other files in the same directory to have the same patient name and ID." " Enable this option if a separate patient directory is created for each patched file.") parametersFormLayout.addRow("Force same patient name and ID in each directory", self.forceSamePatientNameIdInEachDirectoryCheckBox) self.forceSameSeriesInstanceUidInEachDirectoryCheckBox = qt.QCheckBox() self.forceSameSeriesInstanceUidInEachDirectoryCheckBox.checked = False self.forceSameSeriesInstanceUidInEachDirectoryCheckBox.setToolTip("Generate a new series instance UID for each directory" " and set it in all files in that same directory." " Enable this option to force placing all frames in a folder into a single volume.") parametersFormLayout.addRow("Force same series instance UID in each directory", self.forceSameSeriesInstanceUidInEachDirectoryCheckBox) self.generateMissingIdsCheckBox = qt.QCheckBox() self.generateMissingIdsCheckBox.checked = True self.generateMissingIdsCheckBox.setToolTip("Generate missing patient, study, series IDs. It is assumed that" " all files in a directory belong to the same series. Fixes error caused by too aggressive anonymization" " or incorrect DICOM image converters.") parametersFormLayout.addRow("Generate missing patient/study/series IDs", self.generateMissingIdsCheckBox) self.generateImagePositionFromSliceThicknessCheckBox = qt.QCheckBox() self.generateImagePositionFromSliceThicknessCheckBox.checked = True self.generateImagePositionFromSliceThicknessCheckBox.setToolTip("Generate 'image position sequence' for" " multi-frame files that only have 'SliceThickness' field. Fixes error in Dolphin 3D CBCT scanners.") parametersFormLayout.addRow("Generate slice position for multi-frame volumes", self.generateImagePositionFromSliceThicknessCheckBox) self.anonymizeDicomCheckBox = qt.QCheckBox() self.anonymizeDicomCheckBox.checked = False self.anonymizeDicomCheckBox.setToolTip("If checked, then some patient identifiable information will be removed" " from the patched DICOM files. There are many fields that can identify a patient, this function does not remove all of them.") parametersFormLayout.addRow("Partially anonymize", self.anonymizeDicomCheckBox) # # Patch Button # self.patchButton = qt.QPushButton("Patch") self.patchButton.toolTip = "Fix DICOM files in input directory and write them to output directory" parametersFormLayout.addRow(self.patchButton) # # Import Button # self.importButton = qt.QPushButton("Import to DICOM database") self.importButton.toolTip = "Import DICOM files in output directory into the application's DICOM database" parametersFormLayout.addRow(self.importButton) # connections self.patchButton.connect('clicked(bool)', self.onPatchButton) self.importButton.connect('clicked(bool)', self.onImportButton) self.statusLabel = qt.QPlainTextEdit() self.statusLabel.setTextInteractionFlags(qt.Qt.TextSelectableByMouse) parametersFormLayout.addRow(self.statusLabel) # Add vertical spacer self.layout.addStretch(1) self.logic = DICOMPatcherLogic() self.logic.logCallback = self.addLog
def setup(self): ScriptedLoadableModuleWidget.setup(self) self.logic = ScreenCaptureLogic() self.logic.logCallback = self.addLog self.viewNodeType = None self.animationMode = None # Instantiate and connect widgets ... # # Input area # inputCollapsibleButton = ctk.ctkCollapsibleButton() inputCollapsibleButton.text = "Input" self.layout.addWidget(inputCollapsibleButton) inputFormLayout = qt.QFormLayout(inputCollapsibleButton) # Input view selector self.viewNodeSelector = slicer.qMRMLNodeComboBox() self.viewNodeSelector.nodeTypes = [ "vtkMRMLSliceNode", "vtkMRMLViewNode" ] self.viewNodeSelector.addEnabled = False self.viewNodeSelector.removeEnabled = False self.viewNodeSelector.noneEnabled = False self.viewNodeSelector.showHidden = False self.viewNodeSelector.showChildNodeTypes = False self.viewNodeSelector.setMRMLScene(slicer.mrmlScene) self.viewNodeSelector.setToolTip( "Contents of this slice or 3D view will be captured.") inputFormLayout.addRow("View to capture: ", self.viewNodeSelector) # Mode self.animationModeWidget = qt.QComboBox() self.animationModeWidget.setToolTip( "Select the property that will be adjusted") inputFormLayout.addRow("Animation mode:", self.animationModeWidget) # Slice start offset position self.sliceStartOffsetSliderLabel = qt.QLabel("Start sweep offset:") self.sliceStartOffsetSliderWidget = ctk.ctkSliderWidget() self.sliceStartOffsetSliderWidget.singleStep = 30 self.sliceStartOffsetSliderWidget.minimum = -100 self.sliceStartOffsetSliderWidget.maximum = 100 self.sliceStartOffsetSliderWidget.value = 0 self.sliceStartOffsetSliderWidget.setToolTip( "Start slice sweep offset.") inputFormLayout.addRow(self.sliceStartOffsetSliderLabel, self.sliceStartOffsetSliderWidget) # Slice end offset position self.sliceEndOffsetSliderLabel = qt.QLabel("End sweep offset:") self.sliceEndOffsetSliderWidget = ctk.ctkSliderWidget() self.sliceEndOffsetSliderWidget.singleStep = 5 self.sliceEndOffsetSliderWidget.minimum = -100 self.sliceEndOffsetSliderWidget.maximum = 100 self.sliceEndOffsetSliderWidget.value = 0 self.sliceEndOffsetSliderWidget.setToolTip("End slice sweep offset.") inputFormLayout.addRow(self.sliceEndOffsetSliderLabel, self.sliceEndOffsetSliderWidget) # 3D start rotation self.startRotationSliderLabel = qt.QLabel("Start rotation angle:") self.startRotationSliderWidget = ctk.ctkSliderWidget() self.startRotationSliderWidget.singleStep = 5 self.startRotationSliderWidget.minimum = 0 self.startRotationSliderWidget.maximum = 180 self.startRotationSliderWidget.value = 180 self.startRotationSliderWidget.setToolTip( "Rotation angle for the first image, relative to current orientation." ) inputFormLayout.addRow(self.startRotationSliderLabel, self.startRotationSliderWidget) # 3D end rotation self.endRotationSliderLabel = qt.QLabel("End rotation angle:") self.endRotationSliderWidget = ctk.ctkSliderWidget() self.endRotationSliderWidget.singleStep = 5 self.endRotationSliderWidget.minimum = 0 self.endRotationSliderWidget.maximum = 180 self.endRotationSliderWidget.value = 180 self.endRotationSliderWidget.setToolTip( "Rotation angle for the last image, relative to current orientation." ) inputFormLayout.addRow(self.endRotationSliderLabel, self.endRotationSliderWidget) # Sequence browser node selector self.sequenceBrowserNodeSelectorLabel = qt.QLabel( "End rotation angle:") self.sequenceBrowserNodeSelectorWidget = slicer.qMRMLNodeComboBox() self.sequenceBrowserNodeSelectorWidget.nodeTypes = [ "vtkMRMLSequenceBrowserNode" ] self.sequenceBrowserNodeSelectorWidget.addEnabled = False self.sequenceBrowserNodeSelectorWidget.removeEnabled = False self.sequenceBrowserNodeSelectorWidget.noneEnabled = False self.sequenceBrowserNodeSelectorWidget.showHidden = False self.sequenceBrowserNodeSelectorWidget.setMRMLScene(slicer.mrmlScene) self.sequenceBrowserNodeSelectorWidget.setToolTip( "Items defined by this sequence browser will be replayed.") inputFormLayout.addRow(self.sequenceBrowserNodeSelectorLabel, self.sequenceBrowserNodeSelectorWidget) # Sequence start index self.sequenceStartItemIndexLabel = qt.QLabel("Start index:") self.sequenceStartItemIndexWidget = ctk.ctkSliderWidget() self.sequenceStartItemIndexWidget.minimum = 0 self.sequenceStartItemIndexWidget.decimals = 0 self.sequenceStartItemIndexWidget.setToolTip( "First item in the sequence to capture.") inputFormLayout.addRow(self.sequenceStartItemIndexLabel, self.sequenceStartItemIndexWidget) # Sequence end index self.sequenceEndItemIndexLabel = qt.QLabel("End index:") self.sequenceEndItemIndexWidget = ctk.ctkSliderWidget() self.sequenceEndItemIndexWidget.singleStep = 10 self.sequenceEndItemIndexWidget.minimum = 0 self.sequenceEndItemIndexWidget.decimals = 0 self.sequenceEndItemIndexWidget.setToolTip( "Last item in the sequence to capture.") inputFormLayout.addRow(self.sequenceEndItemIndexLabel, self.sequenceEndItemIndexWidget) # # Output area # outputCollapsibleButton = ctk.ctkCollapsibleButton() outputCollapsibleButton.text = "Output" self.layout.addWidget(outputCollapsibleButton) outputFormLayout = qt.QFormLayout(outputCollapsibleButton) # Number of steps value self.numberOfStepsSliderWidget = ctk.ctkSliderWidget() self.numberOfStepsSliderWidget.singleStep = 10 self.numberOfStepsSliderWidget.minimum = 2 self.numberOfStepsSliderWidget.maximum = 150 self.numberOfStepsSliderWidget.value = 31 self.numberOfStepsSliderWidget.decimals = 0 self.numberOfStepsSliderWidget.setToolTip( "Number of images extracted between start and stop positions.") outputFormLayout.addRow("Number of images:", self.numberOfStepsSliderWidget) # Output directory selector self.outputDirSelector = ctk.ctkPathLineEdit() self.outputDirSelector.filters = ctk.ctkPathLineEdit.Dirs self.outputDirSelector.settingKey = 'ScreenCaptureOutputDir' outputFormLayout.addRow("Output directory:", self.outputDirSelector) if not self.outputDirSelector.currentPath: defaultOutputPath = os.path.abspath( os.path.join(slicer.app.defaultScenePath, 'SlicerCapture')) self.outputDirSelector.setCurrentPath(defaultOutputPath) self.videoExportCheckBox = qt.QCheckBox() self.videoExportCheckBox.checked = False self.videoExportCheckBox.setToolTip( "If checked, exported images will be written as a video file." " Requires setting of ffmpeg executable path in Advanced section.") outputFormLayout.addRow("Video export:", self.videoExportCheckBox) self.videoFileNameWidget = qt.QLineEdit() self.videoFileNameWidget.setToolTip( "String that defines file name, type, and numbering scheme. Default: capture.avi." ) self.videoFileNameWidget.text = "SlicerCapture.avi" self.videoFileNameWidget.setEnabled(False) outputFormLayout.addRow("Video file name:", self.videoFileNameWidget) self.videoLengthSliderWidget = ctk.ctkSliderWidget() self.videoLengthSliderWidget.singleStep = 0.1 self.videoLengthSliderWidget.minimum = 0.1 self.videoLengthSliderWidget.maximum = 30 self.videoLengthSliderWidget.value = 5 self.videoLengthSliderWidget.suffix = "s" self.videoLengthSliderWidget.decimals = 1 self.videoLengthSliderWidget.setToolTip( "Length of the exported video in seconds.") self.videoLengthSliderWidget.setEnabled(False) outputFormLayout.addRow("Video length:", self.videoLengthSliderWidget) # # Advanced area # self.advancedCollapsibleButton = ctk.ctkCollapsibleButton() self.advancedCollapsibleButton.text = "Advanced" self.advancedCollapsibleButton.collapsed = True outputFormLayout.addRow(self.advancedCollapsibleButton) advancedFormLayout = qt.QFormLayout(self.advancedCollapsibleButton) self.fileNamePatternWidget = qt.QLineEdit() self.fileNamePatternWidget.setToolTip( "String that defines file name, type, and numbering scheme. Default: image%05d.png." ) self.fileNamePatternWidget.text = "image_%05d.png" advancedFormLayout.addRow("Image file name pattern:", self.fileNamePatternWidget) ffmpegPath = self.logic.getFfmpegPath() self.ffmpegPathSelector = ctk.ctkPathLineEdit() self.ffmpegPathSelector.setCurrentPath(ffmpegPath) self.ffmpegPathSelector.nameFilters = ['ffmpeg.exe', 'ffmpeg'] self.ffmpegPathSelector.setMaximumWidth(300) self.ffmpegPathSelector.setToolTip( "Set the path to ffmpeg executable. Download from: https://www.ffmpeg.org/" ) advancedFormLayout.addRow("ffmpeg executable:", self.ffmpegPathSelector) self.extraVideoOptionsWidget = qt.QComboBox() self.extraVideoOptionsWidget.addItem("-c:v mpeg4 -qscale:v 5") self.extraVideoOptionsWidget.addItem( "-c:v libx264 -preset veryslow -qp 0") self.extraVideoOptionsWidget.addItem( "-f mp4 -vcodec libx264 -pix_fmt yuv420p") self.extraVideoOptionsWidget.setEditable(True) self.extraVideoOptionsWidget.setToolTip( '<html>\n' ' <p>Additional video conversion options passed to ffmpeg.</p>' ' <p><b>Examples:</b>' ' <ul>' ' <li><b>MPEG4: </b>-c:v mpeg4 -qscale:v 5</li>' ' <li><b>H264: </b>-c:v libx264 -preset veryslow -qp 0</li>' ' <li><b>Quicktime: </b>-f mp4 -vcodec libx264 -pix_fmt yuv420p</li>' ' </ul></p>' ' <p>See more encoding options at:' ' <i>https://trac.ffmpeg.org/wiki/Encode/H.264</i> and' ' <i>https://trac.ffmpeg.org/wiki/Encode/MPEG-4</i></p>' '</html>') advancedFormLayout.addRow("Video extra options:", self.extraVideoOptionsWidget) # Capture button self.captureButton = qt.QPushButton("Capture") self.captureButton.toolTip = "Capture slice sweep to image sequence." outputFormLayout.addRow(self.captureButton) self.statusLabel = qt.QPlainTextEdit() self.statusLabel.setTextInteractionFlags(qt.Qt.TextSelectableByMouse) self.statusLabel.setCenterOnScroll(True) outputFormLayout.addRow(self.statusLabel) # # Add vertical spacer #self.layout.addStretch(1) # connections self.captureButton.connect('clicked(bool)', self.onCaptureButton) self.viewNodeSelector.connect("currentNodeChanged(vtkMRMLNode*)", self.updateViewOptions) self.animationModeWidget.connect("currentIndexChanged(int)", self.updateViewOptions) self.sliceStartOffsetSliderWidget.connect('valueChanged(double)', self.setSliceOffset) self.sliceEndOffsetSliderWidget.connect('valueChanged(double)', self.setSliceOffset) self.sequenceBrowserNodeSelectorWidget.connect( "currentNodeChanged(vtkMRMLNode*)", self.updateViewOptions) self.sequenceStartItemIndexWidget.connect('valueChanged(double)', self.setSequenceItemIndex) self.sequenceEndItemIndexWidget.connect('valueChanged(double)', self.setSequenceItemIndex) self.videoExportCheckBox.connect('toggled(bool)', self.fileNamePatternWidget, 'setDisabled(bool)') self.videoExportCheckBox.connect('toggled(bool)', self.videoFileNameWidget, 'setEnabled(bool)') self.videoExportCheckBox.connect('toggled(bool)', self.videoLengthSliderWidget, 'setEnabled(bool)') self.updateViewOptions()
def setup(self): ScriptedLoadableModuleWidget.setup(self) self.logic = ScreenCaptureLogic() self.logic.logCallback = self.addLog self.viewNodeType = None self.animationMode = None self.createdOutputFile = None # Instantiate and connect widgets ... # # Input area # inputCollapsibleButton = ctk.ctkCollapsibleButton() inputCollapsibleButton.text = "Input" self.layout.addWidget(inputCollapsibleButton) inputFormLayout = qt.QFormLayout(inputCollapsibleButton) # Input view selector self.viewNodeSelector = slicer.qMRMLNodeComboBox() self.viewNodeSelector.nodeTypes = [ "vtkMRMLSliceNode", "vtkMRMLViewNode" ] self.viewNodeSelector.addEnabled = False self.viewNodeSelector.removeEnabled = False self.viewNodeSelector.noneEnabled = False self.viewNodeSelector.showHidden = False self.viewNodeSelector.showChildNodeTypes = False self.viewNodeSelector.setMRMLScene(slicer.mrmlScene) self.viewNodeSelector.setToolTip( "Contents of this slice or 3D view will be captured.") inputFormLayout.addRow("View to capture: ", self.viewNodeSelector) # Mode self.animationModeWidget = qt.QComboBox() self.animationModeWidget.setToolTip( "Select the property that will be adjusted") inputFormLayout.addRow("Animation mode:", self.animationModeWidget) # Slice start offset position self.sliceStartOffsetSliderLabel = qt.QLabel("Start sweep offset:") self.sliceStartOffsetSliderWidget = ctk.ctkSliderWidget() self.sliceStartOffsetSliderWidget.singleStep = 30 self.sliceStartOffsetSliderWidget.minimum = -100 self.sliceStartOffsetSliderWidget.maximum = 100 self.sliceStartOffsetSliderWidget.value = 0 self.sliceStartOffsetSliderWidget.setToolTip( "Start slice sweep offset.") inputFormLayout.addRow(self.sliceStartOffsetSliderLabel, self.sliceStartOffsetSliderWidget) # Slice end offset position self.sliceEndOffsetSliderLabel = qt.QLabel("End sweep offset:") self.sliceEndOffsetSliderWidget = ctk.ctkSliderWidget() self.sliceEndOffsetSliderWidget.singleStep = 5 self.sliceEndOffsetSliderWidget.minimum = -100 self.sliceEndOffsetSliderWidget.maximum = 100 self.sliceEndOffsetSliderWidget.value = 0 self.sliceEndOffsetSliderWidget.setToolTip("End slice sweep offset.") inputFormLayout.addRow(self.sliceEndOffsetSliderLabel, self.sliceEndOffsetSliderWidget) # 3D start rotation self.rotationSliderLabel = qt.QLabel("Rotation range:") self.rotationSliderWidget = ctk.ctkRangeWidget() self.rotationSliderWidget.singleStep = 5 self.rotationSliderWidget.minimum = -180 self.rotationSliderWidget.maximum = 180 self.rotationSliderWidget.minimumValue = -180 self.rotationSliderWidget.maximumValue = 180 self.rotationSliderWidget.setToolTip( "View rotation range, relative to current view orientation.") inputFormLayout.addRow(self.rotationSliderLabel, self.rotationSliderWidget) # Sequence browser node selector self.sequenceBrowserNodeSelectorLabel = qt.QLabel("Sequence:") self.sequenceBrowserNodeSelectorWidget = slicer.qMRMLNodeComboBox() self.sequenceBrowserNodeSelectorWidget.nodeTypes = [ "vtkMRMLSequenceBrowserNode" ] self.sequenceBrowserNodeSelectorWidget.addEnabled = False self.sequenceBrowserNodeSelectorWidget.removeEnabled = False self.sequenceBrowserNodeSelectorWidget.noneEnabled = False self.sequenceBrowserNodeSelectorWidget.showHidden = False self.sequenceBrowserNodeSelectorWidget.setMRMLScene(slicer.mrmlScene) self.sequenceBrowserNodeSelectorWidget.setToolTip( "Items defined by this sequence browser will be replayed.") inputFormLayout.addRow(self.sequenceBrowserNodeSelectorLabel, self.sequenceBrowserNodeSelectorWidget) # Sequence start index self.sequenceStartItemIndexLabel = qt.QLabel("Start index:") self.sequenceStartItemIndexWidget = ctk.ctkSliderWidget() self.sequenceStartItemIndexWidget.minimum = 0 self.sequenceStartItemIndexWidget.decimals = 0 self.sequenceStartItemIndexWidget.setToolTip( "First item in the sequence to capture.") inputFormLayout.addRow(self.sequenceStartItemIndexLabel, self.sequenceStartItemIndexWidget) # Sequence end index self.sequenceEndItemIndexLabel = qt.QLabel("End index:") self.sequenceEndItemIndexWidget = ctk.ctkSliderWidget() self.sequenceEndItemIndexWidget.minimum = 0 self.sequenceEndItemIndexWidget.decimals = 0 self.sequenceEndItemIndexWidget.setToolTip( "Last item in the sequence to capture.") inputFormLayout.addRow(self.sequenceEndItemIndexLabel, self.sequenceEndItemIndexWidget) # # Output area # outputCollapsibleButton = ctk.ctkCollapsibleButton() outputCollapsibleButton.text = "Output" self.layout.addWidget(outputCollapsibleButton) outputFormLayout = qt.QFormLayout(outputCollapsibleButton) # Number of steps value self.numberOfStepsSliderWidget = ctk.ctkSliderWidget() self.numberOfStepsSliderWidget.singleStep = 10 self.numberOfStepsSliderWidget.minimum = 2 self.numberOfStepsSliderWidget.maximum = 600 self.numberOfStepsSliderWidget.value = 31 self.numberOfStepsSliderWidget.decimals = 0 self.numberOfStepsSliderWidget.setToolTip( "Number of images extracted between start and stop positions.") outputFormLayout.addRow("Number of images:", self.numberOfStepsSliderWidget) # Output directory selector self.outputDirSelector = ctk.ctkPathLineEdit() self.outputDirSelector.filters = ctk.ctkPathLineEdit.Dirs self.outputDirSelector.settingKey = 'ScreenCaptureOutputDir' outputFormLayout.addRow("Output directory:", self.outputDirSelector) if not self.outputDirSelector.currentPath: defaultOutputPath = os.path.abspath( os.path.join(slicer.app.defaultScenePath, 'SlicerCapture')) self.outputDirSelector.setCurrentPath(defaultOutputPath) self.videoExportCheckBox = qt.QCheckBox(" ") self.videoExportCheckBox.checked = False self.videoExportCheckBox.setToolTip( "If checked, exported images will be written as a video file." " Requires setting of ffmpeg executable path in Advanced section.") self.videoFormatWidget = qt.QComboBox() self.videoFormatWidget.enabled = False self.videoFormatWidget.setSizePolicy(qt.QSizePolicy.Expanding, qt.QSizePolicy.Preferred) for videoFormatPreset in self.logic.videoFormatPresets: self.videoFormatWidget.addItem(videoFormatPreset["name"]) hbox = qt.QHBoxLayout() hbox.addWidget(self.videoExportCheckBox) hbox.addWidget(self.videoFormatWidget) outputFormLayout.addRow("Video export:", hbox) self.videoFileNameWidget = qt.QLineEdit() self.videoFileNameWidget.setToolTip( "String that defines file name and type.") self.videoFileNameWidget.text = "SlicerCapture.avi" self.videoFileNameWidget.setEnabled(False) outputFormLayout.addRow("Video file name:", self.videoFileNameWidget) self.videoLengthSliderWidget = ctk.ctkSliderWidget() self.videoLengthSliderWidget.singleStep = 0.1 self.videoLengthSliderWidget.minimum = 0.1 self.videoLengthSliderWidget.maximum = 30 self.videoLengthSliderWidget.value = 5 self.videoLengthSliderWidget.suffix = "s" self.videoLengthSliderWidget.decimals = 1 self.videoLengthSliderWidget.setToolTip( "Length of the exported video in seconds.") self.videoLengthSliderWidget.setEnabled(False) outputFormLayout.addRow("Video length:", self.videoLengthSliderWidget) # # Advanced area # self.advancedCollapsibleButton = ctk.ctkCollapsibleButton() self.advancedCollapsibleButton.text = "Advanced" self.advancedCollapsibleButton.collapsed = True outputFormLayout.addRow(self.advancedCollapsibleButton) advancedFormLayout = qt.QFormLayout(self.advancedCollapsibleButton) ffmpegPath = self.logic.getFfmpegPath() self.ffmpegPathSelector = ctk.ctkPathLineEdit() self.ffmpegPathSelector.setCurrentPath(ffmpegPath) self.ffmpegPathSelector.nameFilters = [ self.logic.getFfmpegExecutableFilename() ] self.ffmpegPathSelector.setSizePolicy(qt.QSizePolicy.MinimumExpanding, qt.QSizePolicy.Preferred) self.ffmpegPathSelector.setToolTip( "Set the path to ffmpeg executable. Download from: https://www.ffmpeg.org/" ) advancedFormLayout.addRow("ffmpeg executable:", self.ffmpegPathSelector) self.videoExportFfmpegWarning = qt.QLabel( '<qt><b><font color="red">Set valid ffmpeg executable path! ' + '<a href="http://wiki.slicer.org/slicerWiki/index.php/Documentation/Nightly/Modules/ScreenCapture#Setting_up_ffmpeg">Help...</a></font></b></qt>' ) self.videoExportFfmpegWarning.connect('linkActivated(QString)', self.openURL) self.videoExportFfmpegWarning.setVisible(False) advancedFormLayout.addRow("", self.videoExportFfmpegWarning) self.extraVideoOptionsWidget = qt.QLineEdit() self.extraVideoOptionsWidget.setToolTip( 'Additional video conversion options passed to ffmpeg. Parameters -i (input files), -y' + '(overwrite without asking), -r (frame rate), -start_number are specified by the module and therefore' + 'should not be included in this list.') advancedFormLayout.addRow("Video extra options:", self.extraVideoOptionsWidget) self.fileNamePatternWidget = qt.QLineEdit() self.fileNamePatternWidget.setToolTip( "String that defines file name, type, and numbering scheme. Default: image%05d.png." ) self.fileNamePatternWidget.text = "image_%05d.png" advancedFormLayout.addRow("Image file name pattern:", self.fileNamePatternWidget) # Capture button self.captureButton = qt.QPushButton("Capture") self.captureButton.toolTip = "Capture slice sweep to image sequence." self.showCreatedOutputFileButton = qt.QPushButton() self.showCreatedOutputFileButton.setIcon(qt.QIcon(':Icons/Go.png')) self.showCreatedOutputFileButton.setMaximumWidth(60) self.showCreatedOutputFileButton.enabled = False self.showCreatedOutputFileButton.toolTip = "Show created output file." hbox = qt.QHBoxLayout() hbox.addWidget(self.captureButton) hbox.addWidget(self.showCreatedOutputFileButton) outputFormLayout.addRow(hbox) self.statusLabel = qt.QPlainTextEdit() self.statusLabel.setTextInteractionFlags(qt.Qt.TextSelectableByMouse) self.statusLabel.setCenterOnScroll(True) outputFormLayout.addRow(self.statusLabel) # # Add vertical spacer # self.layout.addStretch(1) # connections self.captureButton.connect('clicked(bool)', self.onCaptureButton) self.showCreatedOutputFileButton.connect('clicked(bool)', self.onShowCreatedOutputFile) self.viewNodeSelector.connect("currentNodeChanged(vtkMRMLNode*)", self.updateViewOptions) self.animationModeWidget.connect("currentIndexChanged(int)", self.updateViewOptions) self.sliceStartOffsetSliderWidget.connect('valueChanged(double)', self.setSliceOffset) self.sliceEndOffsetSliderWidget.connect('valueChanged(double)', self.setSliceOffset) self.sequenceBrowserNodeSelectorWidget.connect( "currentNodeChanged(vtkMRMLNode*)", self.updateViewOptions) self.sequenceStartItemIndexWidget.connect('valueChanged(double)', self.setSequenceItemIndex) self.sequenceEndItemIndexWidget.connect('valueChanged(double)', self.setSequenceItemIndex) self.videoExportCheckBox.connect('toggled(bool)', self.fileNamePatternWidget, 'setDisabled(bool)') self.videoExportCheckBox.connect('toggled(bool)', self.videoFileNameWidget, 'setEnabled(bool)') self.videoExportCheckBox.connect('toggled(bool)', self.videoLengthSliderWidget, 'setEnabled(bool)') self.videoExportCheckBox.connect('toggled(bool)', self.videoFormatWidget, 'setEnabled(bool)') self.videoFormatWidget.connect("currentIndexChanged(int)", self.updateVideoFormat) self.updateVideoFormat(0) self.updateViewOptions()
def setup(self): ScriptedLoadableModuleWidget.setup(self) # Instantiate and connect widgets ... # # Parameters Area # parametersCollapsibleButton = ctk.ctkCollapsibleButton() parametersCollapsibleButton.text = "Parameters" self.layout.addWidget(parametersCollapsibleButton) # Layout within the dummy collapsible button parametersFormLayout = qt.QFormLayout(parametersCollapsibleButton) # directory selection self.inputDirectoryButton = qt.QPushButton("Select a Directory") self.inputDirectory = None parametersFormLayout.addRow("DICOM Input:", self.inputDirectoryButton) # phantom type selection self.phantomModelSelector = qt.QGroupBox() vbox = qt.QVBoxLayout() self.phantom_radios = [] for name in sorted(phantom_definitions.PHANTOM_CATALOG.keys()): rb = qt.QRadioButton(name) self.phantom_radios.append(rb) vbox.addWidget(rb) self.phantomModelSelector.setLayout(vbox) parametersFormLayout.addRow("Select phantom model: ", self.phantomModelSelector) # # output DWI volume selector # self.outputDWISelector = slicer.qMRMLNodeComboBox() self.outputDWISelector.nodeTypes = [ "vtkMRMLDiffusionWeightedVolumeNode" ] self.outputDWISelector.selectNodeUponCreation = True self.outputDWISelector.addEnabled = True self.outputDWISelector.removeEnabled = True self.outputDWISelector.renameEnabled = True self.outputDWISelector.noneEnabled = False self.outputDWISelector.showHidden = False self.outputDWISelector.showChildNodeTypes = False self.outputDWISelector.setMRMLScene(slicer.mrmlScene) self.outputDWISelector.setToolTip("Pick the output to the algorithm.") parametersFormLayout.addRow("Output DWI Volume: ", self.outputDWISelector) # # output scalar volume selector # self.outputSelector = slicer.qMRMLNodeComboBox() self.outputSelector.nodeTypes = ["vtkMRMLScalarVolumeNode"] self.outputSelector.selectNodeUponCreation = True self.outputSelector.addEnabled = True self.outputSelector.removeEnabled = True self.outputSelector.renameEnabled = True self.outputSelector.noneEnabled = False self.outputSelector.showHidden = False self.outputSelector.showChildNodeTypes = False self.outputSelector.setMRMLScene(slicer.mrmlScene) self.outputSelector.setToolTip("Pick the output to the algorithm.") parametersFormLayout.addRow("Output Scalar Volume: ", self.outputSelector) # # output VOI selector # self.outputVOISelector = slicer.qMRMLNodeComboBox() self.outputVOISelector.nodeTypes = ["vtkMRMLLabelMapVolumeNode"] self.outputVOISelector.selectNodeUponCreation = True self.outputVOISelector.addEnabled = True self.outputVOISelector.removeEnabled = True self.outputVOISelector.renameEnabled = True self.outputVOISelector.noneEnabled = False self.outputVOISelector.showHidden = False self.outputVOISelector.showChildNodeTypes = False self.outputVOISelector.setMRMLScene(slicer.mrmlScene) self.outputVOISelector.setToolTip( "Pick the output VOI to the algorithm.") parametersFormLayout.addRow("Output VOI: ", self.outputVOISelector) # # Apply Button # self.applyButton = qt.QPushButton("Apply") self.applyButton.toolTip = "Run the algorithm." self.applyButton.enabled = False parametersFormLayout.addRow(self.applyButton) # connections self.applyButton.connect('clicked(bool)', self.onApplyButton) self.inputDirectoryButton.connect('clicked(bool)', self.onInputDirectory) self.phantomModelSelector.connect('clicked(bool)', self.onSelect) self.outputSelector.connect("currentNodeChanged(vtkMRMLNode*)", self.onSelect) self.outputDWISelector.connect("currentNodeChanged(vtkMRMLNode*)", self.onSelect) self.outputVOISelector.connect("currentNodeChanged(vtkMRMLNode*)", self.onSelect) # Refresh Apply button state self.onSelect() # Add space to display feedback from program self.statusLabel = qt.QPlainTextEdit() self.statusLabel.setTextInteractionFlags(qt.Qt.TextSelectableByMouse) parametersFormLayout.addRow(self.statusLabel) # Add vertical spacer self.layout.addStretch(1)
def setup(self): ScriptedLoadableModuleWidget.setup(self) # Instantiate and connect widgets ... self.registrationInProgress = False self.logic = SequenceRegistrationLogic() self.logic.logCallback = self.addLog # # Parameters Area # parametersCollapsibleButton = ctk.ctkCollapsibleButton() parametersCollapsibleButton.text = "Parameters" self.layout.addWidget(parametersCollapsibleButton) # Layout within the dummy collapsible button parametersFormLayout = qt.QFormLayout(parametersCollapsibleButton) # # input volume selector # self.inputSelector = slicer.qMRMLNodeComboBox() self.inputSelector.nodeTypes = ["vtkMRMLSequenceNode"] 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 input volume sequence. Each time point will be registered to the fixed frame." ) parametersFormLayout.addRow("Input volume sequence:", self.inputSelector) # # output volume selector # self.outputVolumesSelector = slicer.qMRMLNodeComboBox() self.outputVolumesSelector.nodeTypes = ["vtkMRMLSequenceNode"] self.outputVolumesSelector.baseName = "OutputVolumes" self.outputVolumesSelector.selectNodeUponCreation = True self.outputVolumesSelector.addEnabled = True self.outputVolumesSelector.removeEnabled = True self.outputVolumesSelector.renameEnabled = True self.outputVolumesSelector.noneEnabled = True self.outputVolumesSelector.showHidden = False self.outputVolumesSelector.showChildNodeTypes = False self.outputVolumesSelector.setMRMLScene(slicer.mrmlScene) self.outputVolumesSelector.setToolTip( "Select a node for storing computed motion-compensated volume sequence." ) parametersFormLayout.addRow("Output volume sequence:", self.outputVolumesSelector) # # output transform selector # self.outputTransformSelector = slicer.qMRMLNodeComboBox() self.outputTransformSelector.nodeTypes = ["vtkMRMLSequenceNode"] self.outputTransformSelector.baseName = "OutputTransforms" self.outputTransformSelector.selectNodeUponCreation = True self.outputTransformSelector.addEnabled = True self.outputTransformSelector.removeEnabled = True self.outputTransformSelector.renameEnabled = True self.outputTransformSelector.noneEnabled = True self.outputTransformSelector.showHidden = False self.outputTransformSelector.showChildNodeTypes = False self.outputTransformSelector.setMRMLScene(slicer.mrmlScene) self.outputTransformSelector.setToolTip( "Computed displacement field that transform nodes from moving volume space to fixed volume space. NOTE: You must set at least one output sequence (transform and/or volume)." ) parametersFormLayout.addRow("Output transform sequence:", self.outputTransformSelector) # # Output transform mode # import Elastix self.registrationPresetSelector = qt.QComboBox() self.registrationPresetSelector.setToolTip( "Pick preset to register with.") for preset in self.logic.elastixLogic.getRegistrationPresets(): self.registrationPresetSelector.addItem("{0} ({1})".format( preset[Elastix.RegistrationPresets_Modality], preset[Elastix.RegistrationPresets_Content])) self.registrationPresetSelector.addItem("*NEW*") self.newPresetIndex = self.registrationPresetSelector.count - 1 parametersFormLayout.addRow("Preset:", self.registrationPresetSelector) # # Advanced Area # advancedCollapsibleButton = ctk.ctkCollapsibleButton() advancedCollapsibleButton.text = "Advanced" advancedCollapsibleButton.collapsed = 1 self.layout.addWidget(advancedCollapsibleButton) # Layout within the dummy collapsible button advancedFormLayout = qt.QFormLayout(advancedCollapsibleButton) # Fixed frame index self.sequenceFixedItemIndexWidget = ctk.ctkSliderWidget() self.sequenceFixedItemIndexWidget.decimals = 0 self.sequenceFixedItemIndexWidget.singleStep = 1 self.sequenceFixedItemIndexWidget.minimum = 0 self.sequenceFixedItemIndexWidget.value = 0 self.sequenceFixedItemIndexWidget.setToolTip( "Set the frame of the input sequence to use as the fixed volume (that all other volumes will be registered to." ) advancedFormLayout.addRow("Fixed frame index:", self.sequenceFixedItemIndexWidget) # Sequence start index self.sequenceStartItemIndexWidget = ctk.ctkSliderWidget() self.sequenceStartItemIndexWidget.minimum = 0 self.sequenceStartItemIndexWidget.decimals = 0 self.sequenceStartItemIndexWidget.setToolTip( "First item in the sequence to register.") advancedFormLayout.addRow("Start frame index:", self.sequenceStartItemIndexWidget) # Sequence end index self.sequenceEndItemIndexWidget = ctk.ctkSliderWidget() self.sequenceEndItemIndexWidget.minimum = 0 self.sequenceEndItemIndexWidget.decimals = 0 self.sequenceEndItemIndexWidget.setToolTip( "Last item in the sequence to register.") advancedFormLayout.addRow("End frame index:", self.sequenceEndItemIndexWidget) # # Transform direction # self.transformDirectionSelector = qt.QComboBox() self.transformDirectionSelector.setToolTip( "Moving to fixed: computes stabilizing transform. Fixed to moving: computes morphing transform, which deforms structures defined on the fixed frame to all moving frames." ) self.transformDirectionSelector.addItem("moving frames to fixed frame") self.transformDirectionSelector.addItem("fixed frame to moving frames") advancedFormLayout.addRow("Transform direction:", self.transformDirectionSelector) # # Option to show detailed log # self.showDetailedLogDuringExecutionCheckBox = qt.QCheckBox(" ") self.showDetailedLogDuringExecutionCheckBox.checked = False label = qt.QLabel("Show detailed log during registration:") label.setToolTip("Show detailed log during registration.") self.showDetailedLogDuringExecutionCheckBox.setToolTip( "Show detailed log during registration.") advancedFormLayout.addRow(label, self.showDetailedLogDuringExecutionCheckBox) # # Option to keep temporary files after registration # self.keepTemporaryFilesCheckBox = qt.QCheckBox(" ") self.keepTemporaryFilesCheckBox.checked = False label = qt.QLabel("Keep temporary files:") label.setToolTip( "Keep temporary files (inputs, computed outputs, logs) after the registration is completed." ) self.keepTemporaryFilesCheckBox.setToolTip( "Keep temporary files (inputs, computed outputs, logs) after the registration is completed." ) # # Button to open the folder in which temporary files are stored # self.showTemporaryFilesFolderButton = qt.QPushButton( "Show temp folder") self.showTemporaryFilesFolderButton.toolTip = "Open the folder where temporary files are stored." self.showTemporaryFilesFolderButton.setSizePolicy( qt.QSizePolicy.MinimumExpanding, qt.QSizePolicy.Preferred) hbox = qt.QHBoxLayout() hbox.addWidget(self.keepTemporaryFilesCheckBox) hbox.addWidget(self.showTemporaryFilesFolderButton) advancedFormLayout.addRow(label, hbox) self.showRegistrationParametersDatabaseFolderButton = qt.QPushButton( "Show database folder") self.showRegistrationParametersDatabaseFolderButton.toolTip = "Open the folder where temporary files are stored." self.showRegistrationParametersDatabaseFolderButton.setSizePolicy( qt.QSizePolicy.MinimumExpanding, qt.QSizePolicy.Preferred) advancedFormLayout.addRow( "Registration presets:", self.showRegistrationParametersDatabaseFolderButton) customElastixBinDir = self.logic.elastixLogic.getCustomElastixBinDir() self.customElastixBinDirSelector = ctk.ctkPathLineEdit() self.customElastixBinDirSelector.filters = ctk.ctkPathLineEdit.Dirs self.customElastixBinDirSelector.setCurrentPath(customElastixBinDir) self.customElastixBinDirSelector.setSizePolicy( qt.QSizePolicy.MinimumExpanding, qt.QSizePolicy.Preferred) self.customElastixBinDirSelector.setToolTip( "Set bin directory of an Elastix installation (where elastix executable is located). " "If value is empty then default elastix (bundled with SlicerElastix extension) will be used." ) advancedFormLayout.addRow("Custom Elastix toolbox location:", self.customElastixBinDirSelector) # # Apply Button # self.applyButton = qt.QPushButton("Register") self.applyButton.toolTip = "Start registration." self.applyButton.enabled = False self.layout.addWidget(self.applyButton) self.statusLabel = qt.QPlainTextEdit() self.statusLabel.setTextInteractionFlags(qt.Qt.TextSelectableByMouse) self.statusLabel.setCenterOnScroll(True) self.layout.addWidget(self.statusLabel) # connections self.applyButton.connect('clicked(bool)', self.onApplyButton) self.inputSelector.connect("currentNodeChanged(vtkMRMLNode*)", self.onInputSelect) self.outputVolumesSelector.connect("currentNodeChanged(vtkMRMLNode*)", self.onSelect) self.outputTransformSelector.connect( "currentNodeChanged(vtkMRMLNode*)", self.onSelect) self.sequenceFixedItemIndexWidget.connect('valueChanged(double)', self.setSequenceItemIndex) self.sequenceStartItemIndexWidget.connect('valueChanged(double)', self.setSequenceItemIndex) self.sequenceEndItemIndexWidget.connect('valueChanged(double)', self.setSequenceItemIndex) self.showTemporaryFilesFolderButton.connect( 'clicked(bool)', self.onShowTemporaryFilesFolder) self.showRegistrationParametersDatabaseFolderButton.connect( 'clicked(bool)', self.onShowRegistrationParametersDatabaseFolder) # Immediately update deleteTemporaryFiles and show detailed logs in the logic to make it possible to decide to # update these variables while the registration is running self.keepTemporaryFilesCheckBox.connect( "toggled(bool)", self.onKeepTemporaryFilesToggled) self.showDetailedLogDuringExecutionCheckBox.connect( "toggled(bool)", self.onShowLogToggled) # Check if user selects to create a new preset self.registrationPresetSelector.connect("activated(int)", self.onCreatePresetPressed) # Add vertical spacer self.layout.addStretch(1) # Variable initializations self.newParameterButtons = [] # Refresh Apply button state self.onInputSelect()
def setup(self): ScriptedLoadableModuleWidget.setup(self) self.logic = ScreenCaptureLogic() self.logic.logCallback = self.addLog # Instantiate and connect widgets ... # # Input area # inputCollapsibleButton = ctk.ctkCollapsibleButton() inputCollapsibleButton.text = "Input" self.layout.addWidget(inputCollapsibleButton) inputFormLayout = qt.QFormLayout(inputCollapsibleButton) # Input view selector self.viewNodeSelector = slicer.qMRMLNodeComboBox() self.viewNodeSelector.nodeTypes = [ "vtkMRMLSliceNode", "vtkMRMLViewNode" ] self.viewNodeSelector.addEnabled = False self.viewNodeSelector.removeEnabled = False self.viewNodeSelector.noneEnabled = False self.viewNodeSelector.showHidden = False self.viewNodeSelector.showChildNodeTypes = False self.viewNodeSelector.setMRMLScene(slicer.mrmlScene) self.viewNodeSelector.setToolTip( "Contents of this slice or 3D view will be captured.") inputFormLayout.addRow("View to capture: ", self.viewNodeSelector) # # Slice view options area # self.sliceViewOptionsCollapsibleButton = ctk.ctkCollapsibleButton() self.sliceViewOptionsCollapsibleButton.text = "Slice viewer sweep" self.layout.addWidget(self.sliceViewOptionsCollapsibleButton) sliceViewOptionsLayout = qt.QFormLayout( self.sliceViewOptionsCollapsibleButton) # Start slice offset position self.startSliceOffsetSliderWidget = ctk.ctkSliderWidget() self.startSliceOffsetSliderWidget.singleStep = 30 self.startSliceOffsetSliderWidget.minimum = -100 self.startSliceOffsetSliderWidget.maximum = 100 self.startSliceOffsetSliderWidget.value = 0 self.startSliceOffsetSliderWidget.setToolTip("Start slice offset.") sliceViewOptionsLayout.addRow("Start offset:", self.startSliceOffsetSliderWidget) # End slice offset position self.endSliceOffsetSliderWidget = ctk.ctkSliderWidget() self.endSliceOffsetSliderWidget.singleStep = 5 self.endSliceOffsetSliderWidget.minimum = -100 self.endSliceOffsetSliderWidget.maximum = 100 self.endSliceOffsetSliderWidget.value = 0 self.endSliceOffsetSliderWidget.setToolTip("End slice offset.") sliceViewOptionsLayout.addRow("End offset:", self.endSliceOffsetSliderWidget) # # 3D view options area # self.threeDViewOptionsCollapsibleButton = ctk.ctkCollapsibleButton() self.threeDViewOptionsCollapsibleButton.text = "3D view rotation" self.layout.addWidget(self.threeDViewOptionsCollapsibleButton) threeDViewOptionsLayout = qt.QFormLayout( self.threeDViewOptionsCollapsibleButton) # Start rotation self.startRotationSliderWidget = ctk.ctkSliderWidget() self.startRotationSliderWidget.singleStep = 5 self.startRotationSliderWidget.minimum = 0 self.startRotationSliderWidget.maximum = 180 self.startRotationSliderWidget.value = 180 self.startRotationSliderWidget.setToolTip( "Rotation angle for the first image, relative to current orientation." ) threeDViewOptionsLayout.addRow("Start rotation angle:", self.startRotationSliderWidget) # End rotation self.endRotationSliderWidget = ctk.ctkSliderWidget() self.endRotationSliderWidget.singleStep = 5 self.endRotationSliderWidget.minimum = 0 self.endRotationSliderWidget.maximum = 180 self.endRotationSliderWidget.value = 180 self.endRotationSliderWidget.setToolTip( "Rotation angle for the last image, relative to current orientation." ) threeDViewOptionsLayout.addRow("End rotation angle:", self.endRotationSliderWidget) # # Output area # outputCollapsibleButton = ctk.ctkCollapsibleButton() outputCollapsibleButton.text = "Output" self.layout.addWidget(outputCollapsibleButton) outputFormLayout = qt.QFormLayout(outputCollapsibleButton) # Number of steps value self.numberOfStepsSliderWidget = ctk.ctkSliderWidget() self.numberOfStepsSliderWidget.singleStep = 5 self.numberOfStepsSliderWidget.minimum = 2 self.numberOfStepsSliderWidget.maximum = 150 self.numberOfStepsSliderWidget.value = 30 self.numberOfStepsSliderWidget.decimals = 0 self.numberOfStepsSliderWidget.setToolTip( "Number of images extracted between start and stop positions.") outputFormLayout.addRow("Number of images:", self.numberOfStepsSliderWidget) # Output directory selector self.outputDirSelector = ctk.ctkPathLineEdit() self.outputDirSelector.filters = ctk.ctkPathLineEdit.Dirs self.outputDirSelector.settingKey = 'ScreenCaptureOutputDir' outputFormLayout.addRow("Output directory:", self.outputDirSelector) if not self.outputDirSelector.currentPath: defaultOutputPath = os.path.abspath( os.path.join(slicer.app.defaultScenePath, 'SlicerCapture')) self.outputDirSelector.setCurrentPath(defaultOutputPath) self.videoExportCheckBox = qt.QCheckBox() self.videoExportCheckBox.checked = False self.videoExportCheckBox.setToolTip( "If checked, exported images will be written as a video file.") outputFormLayout.addRow("Video export:", self.videoExportCheckBox) self.videoFileNameWidget = qt.QLineEdit() self.videoFileNameWidget.setToolTip( "String that defines file name, type, and numbering scheme. Default: capture.avi." ) self.videoFileNameWidget.text = "SlicerCapture.avi" self.videoFileNameWidget.setEnabled(False) outputFormLayout.addRow("Video file name:", self.videoFileNameWidget) self.videoQualitySliderWidget = ctk.ctkSliderWidget() self.videoQualitySliderWidget.singleStep = 0.1 self.videoQualitySliderWidget.minimum = 0 self.videoQualitySliderWidget.maximum = 20 self.videoQualitySliderWidget.value = 2 self.videoQualitySliderWidget.decimals = 1 self.videoQualitySliderWidget.setToolTip( "Bit-rate of video. Higher value means higher quality and larger file size." ) outputFormLayout.addRow("Video quality:", self.videoQualitySliderWidget) self.videoFrameRateSliderWidget = ctk.ctkSliderWidget() self.videoFrameRateSliderWidget.singleStep = 0.1 self.videoFrameRateSliderWidget.minimum = 0.1 self.videoFrameRateSliderWidget.maximum = 60 self.videoFrameRateSliderWidget.value = 25 self.videoFrameRateSliderWidget.decimals = 0 self.videoFrameRateSliderWidget.setToolTip( "Frames per second. Higher values mean faster, shorter videos.") outputFormLayout.addRow("Frame rate:", self.videoFrameRateSliderWidget) # Capture button self.captureButton = qt.QPushButton("Capture") self.captureButton.toolTip = "Capture slice sweep to image sequence." outputFormLayout.addRow(self.captureButton) self.statusLabel = qt.QPlainTextEdit() self.statusLabel.setTextInteractionFlags(qt.Qt.TextSelectableByMouse) self.statusLabel.setCenterOnScroll(True) outputFormLayout.addRow(self.statusLabel) # # Advanced area # self.advancedCollapsibleButton = ctk.ctkCollapsibleButton() self.advancedCollapsibleButton.text = "Advanced" self.advancedCollapsibleButton.collapsed = (self.logic.getFfmpegPath() is not None) self.layout.addWidget(self.advancedCollapsibleButton) advancedFormLayout = qt.QFormLayout(self.advancedCollapsibleButton) self.fileNamePatternWidget = qt.QLineEdit() self.fileNamePatternWidget.setToolTip( "String that defines file name, type, and numbering scheme. Default: image%05d.png." ) self.fileNamePatternWidget.text = "image_%05d.png" advancedFormLayout.addRow("Image file name pattern:", self.fileNamePatternWidget) ffmpegPath = self.logic.getFfmpegPath() self.ffmpegPathSelector = ctk.ctkPathLineEdit() self.ffmpegPathSelector.setCurrentPath(ffmpegPath) self.ffmpegPathSelector.nameFilters = ['ffmpeg.exe', 'ffmpeg'] self.ffmpegPathSelector.setMaximumWidth(300) self.ffmpegPathSelector.setToolTip( "Set the path to ffmpeg executable. Download from: https://www.ffmpeg.org/" ) self.ffmpegPathSelector.setEnabled(False) advancedFormLayout.addRow("ffmpeg executable:", self.ffmpegPathSelector) # Add vertical spacer self.layout.addStretch(1) # connections self.captureButton.connect('clicked(bool)', self.onCaptureButton) self.viewNodeSelector.connect("currentNodeChanged(vtkMRMLNode*)", self.onViewNodeSelected) self.startSliceOffsetSliderWidget.connect('valueChanged(double)', self.setSliceOffset) self.endSliceOffsetSliderWidget.connect('valueChanged(double)', self.setSliceOffset) self.videoExportCheckBox.connect('toggled(bool)', self.fileNamePatternWidget, 'setDisabled(bool)') self.videoExportCheckBox.connect('toggled(bool)', self.ffmpegPathSelector, 'setEnabled(bool)') self.videoExportCheckBox.connect('toggled(bool)', self.videoFileNameWidget, 'setEnabled(bool)') self.onViewNodeSelected()
def setup(self): ScriptedLoadableModuleWidget.setup(self) # Instantiate and connect widgets ... # # Parameters Area # parametersCollapsibleButton = ctk.ctkCollapsibleButton() parametersCollapsibleButton.text = "Parameters" self.layout.addWidget(parametersCollapsibleButton) # Layout within the dummy collapsible button parametersFormLayout = qt.QFormLayout(parametersCollapsibleButton) # # input volume selector # self.inputSelector = slicer.qMRMLNodeComboBox() self.inputSelector.nodeTypes = ["vtkMRMLScalarVolumeNode"] 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 Volume: ", self.inputSelector) # # iterations value # self.iterationsSliderWidget = ctk.ctkSliderWidget() self.iterationsSliderWidget.singleStep = 1 self.iterationsSliderWidget.minimum = 1 self.iterationsSliderWidget.maximum = 200 self.iterationsSliderWidget.value = 20 self.iterationsSliderWidget.setToolTip( """Number of iterations to run.""") parametersFormLayout.addRow("Iterations", self.iterationsSliderWidget) # # smoothing value # self.smoothingSliderWidget = ctk.ctkSliderWidget() self.smoothingSliderWidget.singleStep = 1 self.smoothingSliderWidget.minimum = 1 self.smoothingSliderWidget.maximum = 4 self.smoothingSliderWidget.value = 1 self.smoothingSliderWidget.setToolTip( """Number of times the smoothing operator is applied per iteration. Larger values lead to smoother segmentations.""") parametersFormLayout.addRow("Smoothing", self.smoothingSliderWidget) # # threshold value # self.thresholdSliderWidget = ctk.ctkSliderWidget() self.thresholdSliderWidget.singleStep = 0.01 self.thresholdSliderWidget.minimum = 0 self.thresholdSliderWidget.maximum = 1 self.thresholdSliderWidget.value = 0.5 self.thresholdSliderWidget.setToolTip( """Areas of the image with a value smaller than this threshold will be considered borders. The evolution of the contour will stop in this areas.""") parametersFormLayout.addRow("Threshold (GAC only)", self.thresholdSliderWidget) # # check box to trigger taking screen shots for later use in tutorials # self.enableBaloonFlagCheckBox = qt.QCheckBox() self.enableBaloonFlagCheckBox.checked = 1 self.enableBaloonFlagCheckBox.setToolTip( """Balloon force to guide the contour in non-informative areas of the image, i.e., areas where the gradient of the image is too small to push the contour towards a border. A negative value will shrink the contour, while a positive value will expand the contour in these areas.""" ) parametersFormLayout.addRow("Baloon (GAC only)", self.enableBaloonFlagCheckBox) self.markupsNode = slicer.mrmlScene.AddNewNodeByClass( "vtkMRMLMarkupsFiducialNode") self.placeWidget = slicer.qSlicerMarkupsPlaceWidget() self.placeWidget.setMRMLScene(slicer.mrmlScene) self.placeWidget.setCurrentNode(self.markupsNode) self.placeWidget.buttonsVisible = False self.placeWidget.placeButton().show() self.placeWidget.connect('activeMarkupsFiducialPlaceModeChanged(bool)', self.placementModeChanged) parametersFormLayout.addRow(self.placeWidget) # # name value # self.textWidget = qt.QPlainTextEdit("Tumor") parametersFormLayout.addRow("Segment name", self.textWidget) # # color value # self.color = [255, 255, 0] self.colorWidget = qt.QColorDialog() self.colorWidget.setOption(2) self.colorWidget.setCurrentColor( qt.QColor(self.color[0], self.color[1], self.color[2])) self.colorWidget.connect('currentColorChanged(QColor)', self.colorChanged) parametersFormLayout.addRow("Select color", self.colorWidget) # # 3D - MorphACWE Button # self.acwe3d = qt.QPushButton("3D - MorphACWE") self.acwe3d.toolTip = "Run the algorithm." self.acwe3d.enabled = True self.acwe3d.connect('clicked(bool)', self.onAcwe3d) parametersFormLayout.addRow(self.acwe3d) # # 2D - MorphACWE Button # self.acwe2d = qt.QPushButton("2D - MorphACWE") self.acwe2d.toolTip = "Run the algorithm." self.acwe2d.enabled = True self.acwe2d.connect('clicked(bool)', self.onAcwe2d) parametersFormLayout.addRow(self.acwe2d) # # 2D - MorphACWE Prev Button # self.acwe_prev2d = qt.QPushButton("2D - MorphACWE (prev)") self.acwe_prev2d.toolTip = "Run the algorithm." self.acwe_prev2d.enabled = True self.acwe_prev2d.connect('clicked(bool)', self.onAcwe2dPrev) parametersFormLayout.addRow(self.acwe_prev2d) # # 3D - MorphGAC Button # self.gac3d = qt.QPushButton("3D - MorphGAC") self.gac3d.toolTip = "Run the algorithm." self.gac3d.enabled = True self.gac3d.connect('clicked(bool)', self.onGac3d) parametersFormLayout.addRow(self.gac3d) # # 2D - MorphGAC Button # self.gac2d = qt.QPushButton("2D - MorphGAC") self.gac2d.toolTip = "Run the algorithm." self.gac2d.enabled = True self.gac2d.connect('clicked(bool)', self.onGac2d) parametersFormLayout.addRow(self.gac2d) # Add vertical spacer self.layout.addStretch(1) self.ras = [0, 0, 0]