def openProject(self, folderName=None): """ If no project name is supplied, it will open a file dialog so that the user can select a project file or project folder. :param folderName: Name of a folder with a project :type folderName: basestring """ fileName = "" if folderName: fileName = folderName else: fileName = QFileDialog.getExistingDirectory( self, "Open project", "", QFileDialog.ShowDirsOnly) if len(fileName) > 0: fullName = fileName + ProjectController.Instance().ProjectFile if os.path.isfile(fullName): self.multiDataWidget.transformations.clear() loaded = ProjectController.Instance().loadProject(fileName) if loaded: RegistrationShop.settings.setValue("project/lastProject", fileName) else: print "Couldn't load project:", folderName else: print "Warning: Project file does not exist" RegistrationShop.settings.remove("project/lastProject")
def setRenderWidgets(self, fixed=None, moving=None, multi=None): self.fixedWidget = fixed self.movingWidget = moving self.multiWidget = multi self.fixedPicker.setWidget(self.fixedWidget) self.movingPicker.setWidget(self.movingWidget) self.fixedPicker.pickedLocation.connect(self.pickedFixedLocation) self.movingPicker.pickedLocation.connect(self.pickedMovingLocation) # Save the original complete transform self.originalTransform = self.multiWidget.transformations.completeTransform( ) self.originalScalingTransform = self.multiWidget.transformations.scalingTransform( ) # Add a new transform on top of the others currentProject = ProjectController.Instance().currentProject transform = Transformation(vtkTransform(), Transformation.TypeLandmark, currentProject.movingData) self.multiWidget.transformations.append(transform) statusWidget = StatusWidget.Instance() statusWidget.setText( "Place landmarks in both volumes to create a landmark transform. " "Available methods for placing landmarks are the surface type and the two-step type." )
def testSavingAndLoadingProjectsToDisk(self): projectController = ProjectController.Instance() # Save the project in the current directory path = os.path.dirname(os.path.abspath(__file__)) projectPath = path + "/project" if not os.path.exists(projectPath): os.makedirs(projectPath) projectController.currentProject.title = "Unique title" projectController.currentProject.folder = unicode(projectPath) projectController.saveProject() # Reset the project controller projectController.newProject() self.assertIsNone(projectController.currentProject.title) self.assertIsNone(projectController.currentProject.folder) # Test for existance of a project file in the project folder self.assertTrue(os.path.exists(projectPath + "/project.yaml")) self.assertTrue(projectController.loadProject(projectPath)) # Load the project again from disk projectController.loadProject(projectPath) self.assertIsNotNone(projectController.currentProject.title) self.assertIn("Unique", projectController.currentProject.title) try: os.remove(projectPath + "/project.yaml") except Exception: self.assertTrue(False)
def exportDataAs(self): """ Opens a file dialog so that the user can provide a filename for saving the transformed dataset to. """ fileType = FileTypeDialog.getFileType(self, "Choose file type for export") if len(fileType) == 0: return extension = "(*." + fileType + ")" fileName, other = QFileDialog.getSaveFileName( self, "Save registration result to...", "", extension) if len(fileName) == 0: return self.showProgressBar("Exporting data...") transform = self.multiDataWidget.transformations.completeTransform() dataReader = DataReader() imageData = dataReader.GetImageData( ProjectController.Instance().currentProject.movingData) transformer = DataTransformer() outputData = transformer.TransformImageData(imageData, transform) writer = DataWriter() writer.WriteToFile(outputData, fileName, fileType) self.hideProgressBar()
def loadMovingDataSetFile(self): """ Open file dialog to search for data files. If valid data is given, it will pass the data file location on to the slicer and the project controller. """ dataReader = DataReader() extensions = dataReader.GetSupportedExtensionsAsString() fileName, other = QFileDialog.getOpenFileName( self, "Open moving data set", "", "Images (" + extensions + ")", options=QFileDialog.Directory) if len(fileName) > 0: # If there was another dataset first, ask if the user if the # visualizations should be reset projectController = ProjectController.Instance() if projectController.currentProject.movingData: dialog = ResetVisualizationDialog(self) dialog.setWindowModality(Qt.WindowModal) dialog.exec_() if dialog.result is not None: projectController.loadMovingDataSet(fileName) if dialog.result: self.movingRenderController.resetVisualizations() else: # Inserting an identity transform self.multiDataWidget.transformations.append( Transformation(vtkTransform(), "No transform", fileName)) projectController.loadMovingDataSet(fileName)
def newProject(self): """ Create new project by calling the project controller """ self.multiDataWidget.transformations.clear() ProjectController.Instance().newProject() # Reset the last loaded project in the settings RegistrationShop.settings.setValue("project/lastProject", "")
def setRenderWidgets(self, fixed=None, moving=None, multi=None): self.movingWidget = moving self.renderWidget = multi currentProject = ProjectController.Instance().currentProject self.transformBox.setWidget(self.renderWidget) self.transformBox.setImageData(self.renderWidget.movingImageData) self.renderWidget.transformations.append( Transformation(vtkTransform(), Transformation.TypeUser, currentProject.movingData)) statusWidget = StatusWidget.Instance() statusWidget.setText( "Use the box widget to transform the volume. " "For more specific control of the transformation, use the matrix values to specify the transform." )
def saveProjectAs(self): """ Opens a file dialog so that the user can select a folder in which to save the project. """ # Open file dialog fileName = QFileDialog.getExistingDirectory(self, "Select project folder", "", QFileDialog.ShowDirsOnly) if len(fileName) > 0: # TODO: check for existing project! # Set filename of project ProjectController.Instance().currentProject.folder = fileName # Call save project self.saveProject()
def __init__(self, args): """ Sets app specific properties. Initializes the UI. """ super(RegistrationShop, self).__init__(args) self.setApplicationPath() # Instantiate the project controller ProjectController.Instance() # Initialize the user interface self.initUI() lastProject = RegistrationShop.settings.value("project/lastProject", None) if lastProject: self.openProject(lastProject)
def startComparison(self): projectController = ProjectController.Instance() project = projectController.currentProject if not project or not project.fixedData or not project.movingData: statusWidget = StatusWidget.Instance() statusWidget.setText( "Could not start comparison. Please make a project first" " and make sure to load two datasets.") return if hasattr(self, "compareWidget"): del self.compareWidget transform = self.multiDataWidget.transformations.completeTransform() self.controller = ComparisonController() self.controller.setInputData(project.fixedData, project.movingData, transform) self.compareWidget = CompareWidget(self.controller.widgets) self.compareWidget.show() self.controller.initialize() self.controller.slicerChanged(self.controller.fixedImageWidget)
def saveProject(self): """ Save the project to the specified name in the current project. If no name is specified, then 'save project as' is called. """ projCont = ProjectController.Instance() if projCont.currentProject.folder is not None: # Save that project saved = projCont.saveProject() statusWidget = StatusWidget.Instance() if saved: # Save it in the settings that this was the last opened project RegistrationShop.settings.setValue( "project/lastProject", projCont.currentProject.folder) statusWidget.setText( "The project was succesfully saved to disk.") else: statusWidget.setText( "Something went wrong while saving the project to disk. " "Please try to save the project again.") else: self.saveProjectAs()
def connectElements(self): """ All the elements have to be connected because they are dependent on each other. There is the project controller, two render controllers and a multi render controller. Also there are two render widgets and a multi render widget. Together with some parameter widgets that show settings and with which the user can interact. """ projectController = ProjectController.Instance() projectController.fixedFileChanged.connect( self.fixedRenderController.setFile) projectController.fixedFileChanged.connect( self.multiRenderController.setFixedFile) projectController.movingFileChanged.connect( self.movingRenderController.setFile) projectController.movingFileChanged.connect( self.multiRenderController.setMovingFile) projectController.fixedSettingsChanged.connect( self.fixedRenderController.setRenderSettings) projectController.movingSettingsChanged.connect( self.movingRenderController.setRenderSettings) projectController.multiSettingsChanged.connect( self.multiRenderController.setRenderSettings) self.fixedRenderController.visualizationChanged.connect( self.multiRenderController.setFixedVisualization) self.fixedRenderController.visualizationUpdated.connect( self.multiRenderController.setFixedVisualization) self.movingRenderController.visualizationChanged.connect( self.multiRenderController.setMovingVisualization) self.movingRenderController.visualizationUpdated.connect( self.multiRenderController.setMovingVisualization) self.multiDataWidget.transformations.transformationChanged.connect( self.movingDataWidget.transformationsUpdated)
def applyTransform(self): """ * Show progress bar dialog * Define folder for output (projectFolder/data/result-<id>/.) * Write parameter file to output folder * Call elastix to process the data * Load the new data into the moving widget / project """ statusWidget = StatusWidget.Instance() statusWidget.setText( "Please grab a cup of coffee while Elastix " + "performs the registration: this might take a while...") self.startedElastix.emit("Transforming data...") projectController = ProjectController.Instance() currentProject = projectController.currentProject path = currentProject.folder if not path: statusWidget.setText( "Please create and save a project first so " "that the results of the registration can be saved to disk.") return # Determine filename + folder for new dataset (projectFolder/data/result-<id>/.) dataFolder = os.path.join(path, "data") filenames = os.listdir(dataFolder) if os.path.isdir(dataFolder) else [] resultId = 0 for filename in filenames: if os.path.isdir(os.path.join(dataFolder, filename)) and "result" in filename: resultId += 1 outputFolder = os.path.join(dataFolder, "result-" + str(resultId)) parameterFilePath = os.path.join(outputFolder, "Parameters.txt") initialTransformPath = os.path.join(outputFolder, "InitialTransformation.txt") # Iterate over the parameters to ensure that some parameters are adjusted # according to the data from the project for i in range(len(self.transformation)): param = self.transformation[i] if param.key() == "DefaultPixelValue": # Set the default pixel value to minimum scalar value scalarRange = self.movingWidget.imageData.GetScalarRange() param.setValue(scalarRange[0]) if param.key() == "ResultImagePixelType": # Set the resulting image pixel type to the type of the input data pixelType = self.movingWidget.imageData.GetScalarTypeAsString() param.setValue(pixelType) self.transformation.saveToFile(parameterFilePath) transform = self.multiWidget.transformations.completeTransform() dataset = ProjectController.Instance().currentProject.movingData initialTransform = TransformixTransformation( dataset, transform).transformation() if initialTransform: initialTransform.saveToFile(initialTransformPath) else: initialTransformPath = None command = ElastixCommand(fixedData=currentProject.fixedData, movingData=currentProject.movingData, outputFolder=outputFolder, transformation=parameterFilePath, initialTransformation=initialTransformPath) self.operator = Operator() self.operator.addCommand(command) self.operator.queue.join() self.endedElastix.emit() # Assume that there is only one resulting dataset: result.0.mhd outputData = os.path.join(outputFolder, "result.0.mhd") if os.path.exists(outputData): statusWidget.setText( "Thanks for your patience. The " + "transformed data will now be loaded. It can be found in the project folder." ) transformation = Transformation(vtkTransform(), Transformation.TypeDeformable, outputData) self.multiWidget.transformations.append(transformation) projectController.loadMovingDataSet(outputData) else: statusWidget.setText( "Something went wrong. Please see the project folder for the " + "elastix log to see what went wrong.") from subprocess import call call(["open", outputFolder])
def testProjectController(self): projectController = ProjectController.Instance() self.assertIsNotNone(projectController.currentProject) projectController.newProject() self.assertIsNone(projectController.currentProject.title)
def createElements(self): """ Creates the widgets and docks of which the main window is composed. """ self.mainWindow = QMainWindow() projectController = ProjectController.Instance() self.transformTool = None # Render widgets self.fixedDataWidget = RenderWidget() self.movingDataWidget = RenderWidget() self.multiDataWidget = MultiRenderWidget() self.fixedRenderController = RenderController(self.fixedDataWidget, "fixed") self.movingRenderController = RenderController(self.movingDataWidget, "moving") self.multiRenderController = MultiRenderController( self.multiDataWidget) # Give references of the render controllers to the project controller projectController.fixedRenderController = self.fixedRenderController projectController.movingRenderController = self.movingRenderController projectController.multiRenderController = self.multiRenderController # Render properties widgets sizePolicy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred) sizePolicy.setHorizontalStretch(1) self.fixedPropWidget = RenderPropWidget(self.fixedRenderController, parent=self) self.fixedPropWidget.setSizePolicy(sizePolicy) self.fixedPropWidget.setFileChangedSignal( projectController.fixedFileChanged) self.fixedPropWidget.setLoadDataSlot(self.loadFixedDataSetFile) self.movingPropWidget = RenderPropWidget(self.movingRenderController, parent=self) self.movingPropWidget.setSizePolicy(sizePolicy) self.movingPropWidget.setFileChangedSignal( projectController.movingFileChanged) self.movingPropWidget.setLoadDataSlot(self.loadMovingDataSetFile) self.multiPropWidget = MultiRenderPropWidget( self.multiRenderController, parent=self) self.multiPropWidget.setSizePolicy(sizePolicy) self.verticalSplitter = QSplitter() self.verticalSplitter.setOrientation(Qt.Vertical) # Create the layouts fixedDataTitleWidget = TitleWidget("Fixed volume") multiDataTitleWidget = TitleWidget("Fixed + Moving") movingDataTitleWidget = TitleWidget("Moving volume") fixedLayout = QGridLayout() fixedLayout.setSpacing(0) fixedLayout.setContentsMargins(0, 0, 0, 0) fixedLayout.addWidget(fixedDataTitleWidget) fixedLayout.addWidget(self.fixedDataWidget) fixedWidget = QWidget() fixedWidget.setLayout(fixedLayout) multiLayout = QGridLayout() multiLayout.setSpacing(0) multiLayout.setContentsMargins(0, 0, 0, 0) multiLayout.addWidget(multiDataTitleWidget) multiLayout.addWidget(self.multiDataWidget) multiWidget = QWidget() multiWidget.setLayout(multiLayout) movingLayout = QGridLayout() movingLayout.setSpacing(0) movingLayout.setContentsMargins(0, 0, 0, 0) movingLayout.addWidget(movingDataTitleWidget) movingLayout.addWidget(self.movingDataWidget) movingWidget = QWidget() movingWidget.setLayout(movingLayout) horizontalSplitter = QSplitter() horizontalSplitter.setOrientation(Qt.Horizontal) horizontalSplitter.addWidget(fixedWidget) horizontalSplitter.addWidget(multiWidget) horizontalSplitter.addWidget(movingWidget) propsLayout = QHBoxLayout() propsLayout.setSpacing(1) propsLayout.setContentsMargins(0, 0, 0, 0) propsLayout.addWidget(self.fixedPropWidget) propsLayout.addWidget(self.multiPropWidget) propsLayout.addWidget(self.movingPropWidget) propsWidget = QWidget() propsWidget.setMinimumHeight(245) propsWidget.setMaximumHeight(350) propsWidget.setLayout(propsLayout) self.verticalSplitter.addWidget(horizontalSplitter) self.verticalSplitter.addWidget(propsWidget) self.verticalSplitter.setStretchFactor(0, 2) self.verticalSplitter.setStretchFactor(1, 1) self.setCentralWidget(self.verticalSplitter)