def test_CompareVolumes2(self): """ Test modes with view watcher class. """ m = slicer.util.mainWindow() m.moduleSelector().selectModule('CompareVolumes') self.delayDisplay("Starting View Watcher test") watcher = ViewWatcher() # first with two volumes from SampleData import SampleDataLogic head = SampleDataLogic().downloadMRHead() brain = SampleDataLogic().downloadDTIBrain() logic = CompareVolumesLogic() logic.viewerPerVolume() self.delayDisplay('Should be one row with two columns') logic.viewerPerVolume(volumeNodes=(brain, head), viewNames=('brain', 'head')) self.delayDisplay('Should be two columns, with names') watcher.tearDown() self.delayDisplay('Test passed!')
def test_SubjectHierarchyReference(self): self.delayDisplay('Test that output node moved to referenced node location in subject hierarchy') self.delayDisplay('Load input volume') from SampleData import SampleDataLogic inputVolume = SampleDataLogic().downloadMRHead() self.delayDisplay('Create subject hierarchy of input volume') shNode = slicer.vtkMRMLSubjectHierarchyNode.GetSubjectHierarchyNode(slicer.mrmlScene) self.patientItemID = shNode.CreateSubjectItem(shNode.GetSceneItemID(), "John Doe") self.studyItemID = shNode.CreateStudyItem(self.patientItemID, "Some study") self.folderItemID = shNode.CreateFolderItem(self.studyItemID, "Some group") shNode.SetItemParent(shNode.GetItemByDataNode(inputVolume), self.folderItemID) outputVolume = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLScalarVolumeNode") # New node is expected to be created in the subject hierarchy root self.assertEqual(shNode.GetItemParent(shNode.GetItemByDataNode(outputVolume)), shNode.GetSceneItemID()) self.delayDisplay('Run CLI module') cliParams = {'InputVolume': inputVolume.GetID(), 'OutputVolume': outputVolume.GetID(), 'ThresholdValue' : 100, 'ThresholdType' : 'Above'} cliNode = slicer.cli.run(slicer.modules.thresholdscalarvolume, None, cliParams, wait_for_completion=True) # After CLI execution is completed, output volume must be in the same folder as the referenced node self.assertEqual(shNode.GetItemParent(shNode.GetItemByDataNode(outputVolume)), shNode.GetItemParent(shNode.GetItemByDataNode(inputVolume))) # After pending events are processed, the output volume must be in the same subject hierarchy folder slicer.app.processEvents() self.assertEqual(shNode.GetItemParent(shNode.GetItemByDataNode(outputVolume)), shNode.GetItemParent(shNode.GetItemByDataNode(inputVolume)))
def test_CompareVolumes1(self): """ Test modes with 3 volumes. """ m = slicer.util.mainWindow() m.moduleSelector().selectModule('CompareVolumes') self.delayDisplay("Starting the test") # first with two volumes from SampleData import SampleDataLogic head = SampleDataLogic().downloadMRHead() brain = SampleDataLogic().downloadDTIBrain() logic = CompareVolumesLogic() logic.viewerPerVolume() self.delayDisplay('Should be one row with two columns') logic.viewerPerVolume(volumeNodes=(brain, head), viewNames=('brain', 'head')) self.delayDisplay('Should be two columns, with names') # now with three volumes otherBrain = SampleDataLogic().downloadMRBrainTumor1() logic.viewerPerVolume() logic.viewerPerVolume(volumeNodes=(brain, head, otherBrain), viewNames=('brain', 'head', 'otherBrain')) self.delayDisplay('Should be one row with three columns') logic.viewerPerVolume(volumeNodes=(brain, head, otherBrain), viewNames=('brain', 'head', 'otherBrain'), orientation='Sagittal') self.delayDisplay('same thing in sagittal') logic.viewerPerVolume(volumeNodes=(brain, head, otherBrain), viewNames=('brain', 'head', 'otherBrain'), orientation='Coronal') self.delayDisplay('same thing in coronal') anotherHead = SampleDataLogic().downloadMRHead() logic.viewerPerVolume(volumeNodes=(brain, head, otherBrain, anotherHead), viewNames=('brain', 'head', 'otherBrain', 'anotherHead'), orientation='Coronal') self.delayDisplay('now four volumes, with three columns and two rows') logic.viewersPerVolume(volumeNodes=(brain, head)) self.delayDisplay('now axi/sag/cor for two volumes') logic.viewersPerVolume(volumeNodes=(brain, head, otherBrain)) self.delayDisplay('now axi/sag/cor for three volumes') self.delayDisplay('Test passed!')
def test_CompareVolumes3(self): """ Test LayerReveal From the python console: slicer.util.mainWindow().moduleSelector().selectModule("CompareVolumes"); slicer.modules.CompareVolumesWidget.onReloadAndTest(scenario="LayerReveal"); reveal = LayerReveal() """ self.delayDisplay("Starting LayerReveal test") # first with two volumes from SampleData import SampleDataLogic head = SampleDataLogic().downloadMRHead() dti = SampleDataLogic().downloadDTIBrain() tumor = SampleDataLogic().downloadMRBrainTumor1() logic = CompareVolumesLogic() logic.viewerPerVolume() self.delayDisplay('Should be one row with two columns') logic.viewerPerVolume(volumeNodes=(dti, tumor, head), background=dti, viewNames=('dti', 'tumor', 'head')) self.delayDisplay('Should be three columns, with dti in foreground') # the name of the view was givein the the call to viewerPerVolume above. # here we ask the layoutManager to give us the corresponding sliceWidget # from which we can get the interactorStyle so we can simulate events layoutManager = slicer.app.layoutManager() sliceWidget = layoutManager.sliceWidget('head') style = sliceWidget.sliceView().interactorStyle().GetInteractor() for scale in (False, True): for size in (100, 400): # create a reveal cursor to test reveal = LayerReveal(width=size, height=size, scale=scale) reveal.processEvent(style, "EnterEvent") steps = 300 for step in range(0, steps): t = step // float(steps) px = int(t * sliceWidget.width) py = int(t * sliceWidget.height) style.SetEventPosition(px, py) reveal.processEvent(style, "MouseMoveEvent") reveal.processEvent(style, "LeaveEvent") reveal.cleanup() self.delayDisplay(f'Scale {scale}, size {size}') self.delayDisplay( 'Should have just seen reveal cursor move through head view') self.delayDisplay('Test passed!')
def setUp(self): from SampleData import SampleDataLogic dtiSource = SampleDataLogic().sourceForSampleName('DTIBrain') self.file_name = SampleDataLogic().downloadSourceIntoCache(dtiSource)[0] self.ritk = vtkITK.vtkITKArchetypeDiffusionTensorImageReaderFile() self.ritk.SetUseOrientationFromFile(True) self.ritk.SetUseNativeOriginOn() self.ritk.SetOutputScalarTypeToNative() self.ritk.SetDesiredCoordinateOrientationToNative() self.ritk.SetArchetype(self.file_name) self.ritk.Update() self.rnrrd = vtkTeem.vtkTeemNRRDReader() self.rnrrd.SetFileName(self.file_name) self.rnrrd.Update()
def test_HelloSharpen1(self): """ Ideally you should have several levels of tests. At the lowest level tests should exercise the functionality of the logic with different inputs (both valid and invalid). At higher levels your tests should emulate the way the user would interact with your code and confirm that it still works the way you intended. One of the most important features of the tests is that it should alert other developers when their changes will have an impact on the behavior of your module. For example, if a developer removes a feature that you depend on, your test should break so they know that the feature is needed. """ self.delayDisplay("Starting the test") self.delayDisplay('Load input volume') from SampleData import SampleDataLogic inputVolume = SampleDataLogic().downloadMRHead() self.delayDisplay('Create output volume') outputVolume = slicer.mrmlScene.AddNewNodeByClass( "vtkMRMLScalarVolumeNode") self.delayDisplay('Compute results') logic = HelloSharpenLogic() success = logic.run(inputVolume, outputVolume) self.delayDisplay('Display output') slicer.util.setSliceViewerLayers(outputVolume) self.delayDisplay('Verify results') self.assertTrue(success) self.assertIsNotNone(outputVolume.GetImageData()) self.delayDisplay('Test passed!')
def test_BRAINSFitRigidRegistrationCrashIssue4139(self): """ Ideally you should have several levels of tests. At the lowest level tests should exercise the functionality of the logic with different inputs (both valid and invalid). At higher levels your tests should emulate the way the user would interact with your code and confirm that it still works the way you intended. One of the most important features of the tests is that it should alert other developers when their changes will have an impact on the behavior of your module. For example, if a developer removes a feature that you depend on, your test should break so they know that the feature is needed. """ self.delayDisplay("Starting the test") logic = BRAINSFitRigidRegistrationCrashIssue4139Logic() import SampleData from SampleData import SampleDataLogic sampleDatalogic = SampleDataLogic() fixed = sampleDatalogic.downloadMRBrainTumor1() self.assertIsNotNone(logic.hasImageData(fixed)) moving = sampleDatalogic.downloadMRBrainTumor2() self.assertIsNotNone(logic.hasImageData(moving)) self.delayDisplay('Finished with download and loading') outputTransform = slicer.vtkMRMLLinearTransformNode() slicer.mrmlScene.AddNode(outputTransform) outputVolume = slicer.vtkMRMLScalarVolumeNode() slicer.mrmlScene.AddNode(outputVolume) parameters = { 'fixedVolume' : fixed, 'movingVolume' : moving, 'linearTransform' : outputTransform, 'outputVolume' : outputVolume, 'useRigid' : True } cmdLineNode = slicer.cli.runSync(slicer.modules.brainsfit, parameters=parameters) self.assertIsNotNone(cmdLineNode) # If test reach this point without crashing it is a success self.delayDisplay('Test passed!')
def setUp(self): from SampleData import SampleDataLogic brainSource = SampleDataLogic().sourceForSampleName('MRHead') self.file_name = SampleDataLogic().downloadSourceIntoCache( brainSource)[0] self.ritk = vtkITK.vtkITKArchetypeImageSeriesScalarReader() self.ritk.SetUseOrientationFromFile(True) self.ritk.SetUseNativeOriginOn() self.ritk.SetOutputScalarTypeToNative() self.ritk.SetDesiredCoordinateOrientationToNative() self.ritk.SetArchetype(self.file_name) self.ritk.Update() self.rnrrd = teem.vtkTeemNRRDReader() self.rnrrd.SetFileName(self.file_name) self.rnrrd.Update() self.assertTrue( compare_vtk_matrix(self.ritk.GetRasToIjkMatrix(), self.rnrrd.GetRasToIjkMatrix()))
def setUpClass(cls): slicer.mrmlScene.Clear(0) cls.tempDir = slicer.app.temporaryPath cls.watchedDirectory = os.path.join(cls.tempDir, "SlicerProstateTesting", cls.__class__.__name__) cls.createDirectory(cls.watchedDirectory) cls.watcher = DirectoryWatcher(cls.watchedDirectory) cls.sampleDataLogic = SampleDataLogic() cls.startedEventEmitted = False cls.stoppedEventEmitted = False cls.fileCountChangedEmitted = False
def test_VolumeRenderThreeDOnlyLayout(self): """ Test that the following workflow does not segfault: - Set 3D-only layout, reinitialize slice widgets - Load volume - Enter the volume rendering module """ # Set 3D-only layout layoutManager = slicer.app.layoutManager() layoutManager.setLayout( slicer.vtkMRMLLayoutNode.SlicerLayoutOneUp3DView) # Reinitialize MRML scene to force re-creating slice widgets mrmlScene = layoutManager.mrmlScene() layoutManager.setMRMLScene(None) layoutManager.setMRMLScene(mrmlScene) # Load MRHead volume from SampleData import SampleDataLogic SampleDataLogic().downloadMRHead() # Enter the volume rendering module slicer.util.mainWindow().moduleSelector().selectModule( 'VolumeRendering')
def setup(self): ScriptedLoadableModuleWidget.setup(self) self.tutorials = { "ShapeAnalysisModule": "https://bit.ly/2Fyn97v", # SPHARM-PDM Generator "GroupWiseRegistrationModule": "https://bit.ly/2WsFiun", "RegressionComputation": "https://bit.ly/2uVYche", "ShapeVariationAnalyzer": "https://bit.ly/2HYbHVA", # Population Analysis "SRep": "https://bit.ly/3sTEG3H", "SRepCreator": "https://bit.ly/3sTEG3H", "SRepRefinement": "https://bit.ly/3sTEG3H", } # The anchor associated with each link corresponds to the name of the module to select. # For example, after the user click on the link associated with `href="#DataImporter"`, # the "DataImporter" module is selected. text = """ <br> <u>Workflow quick-reference:</u><br> <br> The drop-down Modules are ordered to follow the basic workflow for choosing and using data. As a quick reference, the basic steps involve:<br> <br> 1. Use the <a href="#DataImporter"><b>Data importer</b></a> module to load your segmentations from FreeSurf, FSL, Autoseg, or a bunch of vtp's<br><br> 2. Use <a href="#ShapePopulationViewer"><b>Shape Population Viewer</b></a> to do a quality check on the imported data<br><br> 3. Use <a href="#ShapeAnalysisModule"><b>SPHARM-PDM Generator</b></a> to do spherical harmonics based analysis<br><br> 4. Use the <a href="#GroupWiseRegistrationModule"><b>Study-specific Shape Analysis</b></a> module.<br><br> 5. Use the <a href="#SkeletalRepresentationVisualizer"><b>S-Rep Shape Analysis</b></a> module to do shape analysis via skeletal representations.<br><br> 6. Use the <a href="#ShapeVariationAnalyzer"><b>Shape Evaluator</b></a> module to compute a mean shape and see how the population varies.<br><br> 7. Use <a href="#RegressionComputation"><b>Shape Regressions</b></a> module to do regression based analysis.<br><br> 8. Use the <a href="#MFSDA"><b>Shape Statistics</b></a> module.<br><br> """ # TEXTEDIT self.HomeTextSection = qt.QTextBrowser() self.HomeTextSection.setHtml(text) self.HomeTextSection.setMinimumHeight(400) self.HomeTextSection.connect('anchorClicked(QUrl)', self.onAnchorClicked) self.layout.addWidget(self.HomeTextSection) # SPACER self.layout.addStretch() # SAMPLE DATA REGISTRATION for json_file in [ 'DataImporterInputData.json', 'MFSDAInputData.json', 'ShapeRegressionInputData.json', 'SPHARM-PDMTestData.json', 'SPHARM-PDMFiducials.json', 'SRepCreatorData.json', 'SVAInputData.json' ]: with open( self.resourcePath('SampleDataDescription/%s' % json_file), 'r') as json_data: source_data = json.load(json_data) if 'iconPath' in source_data: iconPath = self.resourcePath(source_data['iconPath']) else: iconPath = None SampleDataLogic.registerCustomSampleDataSource( category=source_data['category'], sampleName=source_data['sampleName'], uris=source_data['uris'], checksums=source_data.get('checksums', None), fileNames=source_data['fileNames'], nodeNames=None, thumbnailFileName=iconPath, loadFileType=None, customDownloader=self.downloadSampleDataInFolder, ) # HIDE SAMPLE DATA 'BUILTIN' CATEGORY slicer.modules.sampledata.widgetRepresentation().self( ).setCategoryVisible('BuiltIn', False) self.sampleDataModuleTab = None self.sampleDataTabTextEdit = None self.moduleNameToSampleDataCategory = { "DataImporter": "Data Importer", "MFSDA": "Covariate Significance Testing", "ShapeAnalysisModule": "SPHARM-PDM", "RegressionComputation": "Shape Regression", "ShapeVariationAnalyzer": "Population Analysis", "SRepCreator": "Skeletal Representation Creator" } self.sampleDataModuleTab = self.addSampleDataTab() self.updateSampleDataTab("Home") moduleMenu = slicer.util.mainWindow().moduleSelector().modulesMenu() moduleMenu.connect("currentModuleChanged(QString)", self.updateSampleDataTab)
def downloadSampleDataInFolder(source): if slicer.util.selectedModule() == "SampleData": sampleDataLogic = slicer.modules.sampledata.widgetRepresentation( ).self().logic else: sampleDataLogic = SampleDataLogic( logMessage=slicer.modules.HomeWidget.logSampleDataTabMessage) # Retrieve directory category = sampleDataLogic.categoryForSource(source) savedDirectory = slicer.app.userSettings().value( "SampleData/Last%sDownloadDirectory" % category, qt.QStandardPaths.writableLocation( qt.QStandardPaths.DocumentsLocation)) destFolderPath = str( qt.QFileDialog.getExistingDirectory(slicer.util.mainWindow(), 'Destination Folder', savedDirectory)) if not os.path.isdir(destFolderPath): return print('Selected data folder: %s' % destFolderPath) for uri, fileName, checksum in zip(source.uris, source.fileNames, source.checksums): sampleDataLogic.downloadFile(uri, destFolderPath, fileName, checksum=checksum) # Save directory slicer.app.userSettings().setValue( "SampleData/Last%sDownloadDirectory" % category, destFolderPath) filepath = destFolderPath + "/setup.py" if (os.path.exists(filepath)): spec = importlib.util.spec_from_file_location("setup", filepath) setup = importlib.util.module_from_spec(spec) spec.loader.exec_module(setup) setup.setup() # Pre-fill input/output fields in module currModule = slicer.util.selectedModule() outPath = os.path.join(destFolderPath, 'out') if not os.path.exists(outPath): os.mkdir(outPath) if currModule == slicer.moduleNames.DataImporter: slicer.modules.DataImporterWidget.FolderDirectoryButton.directory = destFolderPath slicer.modules.DataImporterWidget.inputShapeAnalysisPath = outPath elif currModule == slicer.moduleNames.ShapeAnalysisModule: slicer.modules.ShapeAnalysisModuleWidget.GroupProjectInputDirectory.directory = destFolderPath slicer.modules.ShapeAnalysisModuleWidget.RigidAlignmentFiducialsDirectory.directory = destFolderPath slicer.modules.ShapeAnalysisModuleWidget.GroupProjectOutputDirectory.directory = outPath if glob.glob(os.path.join(destFolderPath, '*_fid.fcsv')): slicer.modules.ShapeAnalysisModuleWidget.RigidAlignmentEnabled.checked = True slicer.modules.ShapeAnalysisModuleWidget.CollapsibleButton_RigidAlignment.checked = True elif currModule == slicer.moduleNames.ShapeVariationAnalyzer: slicer.modules.ShapeVariationAnalyzerWidget.collapsibleButton_PCA.collapsed = False slicer.modules.ShapeVariationAnalyzerWidget.pathLineEdit_CSVFilePCA.currentPath = os.path.join( destFolderPath, 'inputFiles.csv') slicer.modules.ShapeVariationAnalyzerWidget.DirectoryButton_PCASingleExport.directory = outPath elif currModule == slicer.moduleNames.RegressionComputation: slicer.modules.RegressionComputationWidget.shapeInputDirectory.directory = destFolderPath slicer.modules.RegressionComputationWidget.outputDirectory.directory = outPath elif currModule == slicer.moduleNames.MFSDA: slicer.modules.MFSDAWidget.lineEdit_csv.currentPath = os.path.join( destFolderPath, 'inputFiles.csv') slicer.modules.MFSDAWidget.lineEdit_pshape.currentPath = os.path.join( destFolderPath, 'g01', 'bump00.vtk') slicer.modules.MFSDAWidget.lineEdit_output.directory = os.path.join( destFolderPath, 'out')