def loadBinfo(self,filePath): filePrefix, fileExtension = os.path.splitext(filePath) if not fileExtension == ".binfo": print "Error, file not a binfo file: " + filePath self.voiComboBox.clear() self.motionStateComboBox.clear() binfo = LoadCTXLib.Binfo() binfo.readFile(filePath) self.binfoList.append(binfo) # #Create segmentation node for this binfo segmentationNode = slicer.vtkMRMLSegmentationNode() name = slicer.mrmlScene.GenerateUniqueName(os.path.basename(filePrefix)) segmentationNode.SetName(name) slicer.mrmlScene.AddNode(segmentationNode) binfo.segmentationNode = segmentationNode self.selectSegmentation.setCurrentNode(segmentationNode) self.setBinfoFile(segmentationNode) displayNode = slicer.vtkMRMLSegmentationDisplayNode() slicer.mrmlScene.AddNode(displayNode) segmentationNode.SetAndObserveDisplayNodeID(displayNode.GetID()) displayNode.SetAllSegmentsVisibility2DFill(False) displayNode.SetSliceIntersectionThickness(3) storageNode = slicer.vtkMRMLSegmentationStorageNode() slicer.mrmlScene.AddNode(storageNode) segmentationNode.SetAndObserveStorageNodeID(storageNode.GetID())
def TestSection_01_GenerateInputData(self): self.inputSegmentationNode = slicer.vtkMRMLSegmentationNode() slicer.mrmlScene.AddNode(self.inputSegmentationNode) # Create new segments import random for segmentName in ['first', 'second', 'third']: sphereSegment = vtkSegmentationCore.vtkSegment() sphereSegment.SetName(segmentName) sphereSegment.SetColor(random.uniform(0.0,1.0), random.uniform(0.0,1.0), random.uniform(0.0,1.0)) sphere = vtk.vtkSphereSource() sphere.SetCenter(random.uniform(0,100),random.uniform(0,100),random.uniform(0,100)) sphere.SetRadius(random.uniform(20,30)) sphere.Update() spherePolyData = sphere.GetOutput() sphereSegment.AddRepresentation( vtkSegmentationCore.vtkSegmentationConverter.GetSegmentationClosedSurfaceRepresentationName(), spherePolyData) self.inputSegmentationNode.GetSegmentation().AddSegment(sphereSegment) self.assertEqual(self.inputSegmentationNode.GetSegmentation().GetNumberOfSegments(), 3)
def onSegment(self): pluginHandlerSingleton = slicer.qSlicerSubjectHierarchyPluginHandler.instance() currentItemID = pluginHandlerSingleton.currentItem() if not currentItemID: logging.error("Invalid current item") shNode = pluginHandlerSingleton.subjectHierarchyNode() volumeNode = shNode.GetItemDataNode(currentItemID) # Switch to Segment Editor module pluginHandlerSingleton.pluginByName('Default').switchToModule('SegmentEditor') editorWidget = slicer.modules.segmenteditor.widgetRepresentation().self() # Create new segmentation only if there is no segmentation node, or the current segmentation is not empty # (switching to the module will create an empty segmentation if there is none in the scene, but not otherwise) segmentationNode = editorWidget.parameterSetNode.GetSegmentationNode() import vtkSegmentationCorePython as vtkSegmentationCore if segmentationNode is None or segmentationNode.GetSegmentation().GetNumberOfSegments() > 0: segmentationNode = slicer.vtkMRMLSegmentationNode() slicer.mrmlScene.AddNode(segmentationNode) editorWidget.parameterSetNode.SetAndObserveSegmentationNode(segmentationNode) # Name segmentation node based on the volume segmentationNode.SetName(volumeNode.GetName() + '_Segmentation') # Set master volume editorWidget.parameterSetNode.SetAndObserveMasterVolumeNode(volumeNode) # Place segmentation under the master volume in subject hierarchy segmentationShItemID = shNode.GetItemByDataNode(segmentationNode) shNode.SetItemParent(segmentationShItemID, shNode.GetItemParent(currentItemID))
def enter(self): """Runs whenever the module is reopened """ if self.editor.turnOffLightboxes(): slicer.util.warningDisplay( 'Segment Editor is not compatible with slice viewers in light box mode.' 'Views are being reset.', windowTitle='Segment Editor') # Allow switching between effects and selected segment using keyboard shortcuts self.editor.installKeyboardShortcuts() # Set parameter set node if absent self.selectParameterNode() self.editor.updateWidgetFromMRML() # If no segmentation node exists then create one so that the user does not have to create one manually if not self.editor.segmentationNodeID(): segmentationNode = slicer.mrmlScene.GetFirstNode( None, "vtkMRMLSegmentationNode") if not segmentationNode: segmentationNode = slicer.vtkMRMLSegmentationNode() slicer.mrmlScene.AddNode(segmentationNode) self.editor.setSegmentationNode(segmentationNode) if not self.editor.masterVolumeNodeID(): masterVolumeNodeID = self.getDefaultMasterVolumeNodeID() self.editor.setMasterVolumeNodeID(masterVolumeNodeID)
def UpdateSegmentationNode(self): SegLogic = slicer.modules.segmentations.logic() OldSegmentationNode = self.SegmentationNode NewSegmentationNode = slicer.vtkMRMLSegmentationNode() NewSegmentationNode.SetName(OldSegmentationNode.GetName()) # Import working labelmap from interface WorkingLabelMap = self.WorkingLabelMapStorage.currentNode() if WorkingLabelMap != None: LabelMapNodeName = WorkingLabelMap.GetName() OldNodeName = LabelMapNodeName[: -3] # Assuming all tag names are 3 chars long, the last one will be removed # Remove old label map - if present #if self.SegmentationNode.GetBinaryLabelmapRepresentation(OldNodeName) != None: self.SegmentationNode.RemoveSegment(OldNodeName) # Create new label map representation SegLogic.ImportLabelmapToSegmentationNode(WorkingLabelMap, self.SegmentationNode) self.SegmentationNode.CreateBinaryLabelmapRepresentation() # Update closed surface representation for visualization if self.SegmentationNode.GetClosedSurfaceRepresentation( LabelMapNodeName) == None: self.SegmentationNode.CreateClosedSurfaceRepresentation() self.SegmentationNode.SetDisplayVisibility(0) # Toggle visualization on, if specified if self.VisualizeLabelMapButton.isChecked(): self.SegmentationNode.SetDisplayVisibility(1)
def OnInputVolumeSelectorChanged(self): # First, (re)initialize segmentation node to contain input and working data # Check scene for previous segmentation node, remove if present SegNodeName = "Seg_" + self.InputVolumeSelector.currentNode().GetName() OldSegNode = slicer.util.getNode(SegNodeName) if OldSegNode != None: OldSegNode.SetSelected(0) slicer.mrmlScene.RemoveNode(OldSegNode) # Instantiate new segmentation node self.SegmentationNode = slicer.vtkMRMLSegmentationNode() self.SegmentationNode.SetScene(slicer.mrmlScene) slicer.mrmlScene.AddNode(self.SegmentationNode) self.SegmentationNode.SetSelected(1) self.SegmentationNode.SetName(SegNodeName) NewInputVolumeNode = self.InputVolumeSelector.currentNode() if NewInputVolumeNode == None: self.ThresholdVolumeButton.enabled = False return True if NewInputVolumeNode.GetClassName() != 'vtkMRMLScalarVolumeNode': print "ERROR - Invalid node type in Input Volume combo box" self.ThresholdVolumeButton.enabled = False return False else: #self.UpdateSegmentationNode() self.ThresholdVolumeButton.enabled = True
def onSegment(self): pluginHandlerSingleton = slicer.qSlicerSubjectHierarchyPluginHandler.instance( ) currentItemID = pluginHandlerSingleton.currentItem() if not currentItemID: logging.error("Invalid current item") shNode = pluginHandlerSingleton.subjectHierarchyNode() volumeNode = shNode.GetItemDataNode(currentItemID) # Switch to Segment Editor module pluginHandlerSingleton.pluginByName('Default').switchToModule( 'SegmentEditor') editorWidget = slicer.modules.segmenteditor.widgetRepresentation( ).self() # Create new segmentation only if there is no segmentation node, or the current segmentation is not empty # (switching to the module will create an empty segmentation if there is none in the scene, but not otherwise) segmentationNode = editorWidget.parameterSetNode.GetSegmentationNode() import vtkSegmentationCorePython as vtkSegmentationCore if segmentationNode is None or segmentationNode.GetSegmentation( ).GetNumberOfSegments() > 0: segmentationNode = slicer.vtkMRMLSegmentationNode() slicer.mrmlScene.AddNode(segmentationNode) editorWidget.parameterSetNode.SetAndObserveSegmentationNode( segmentationNode) # Name segmentation node based on the volume segmentationNode.SetName(volumeNode.GetName() + '_Segmentation') # Set master volume editorWidget.parameterSetNode.SetAndObserveMasterVolumeNode(volumeNode) # Place segmentation under the master volume in subject hierarchy segmentationShItemID = shNode.GetItemByDataNode(segmentationNode) shNode.SetItemParent(segmentationShItemID, currentItemID)
def TestSection_01_GenerateInputData(self): self.inputSegmentationNode = slicer.vtkMRMLSegmentationNode() slicer.mrmlScene.AddNode(self.inputSegmentationNode) # Create new segments import random for segmentName in ['first', 'second', 'third']: sphereSegment = vtkSegmentationCore.vtkSegment() sphereSegment.SetName(segmentName) sphereSegment.SetColor(random.uniform(0.0, 1.0), random.uniform(0.0, 1.0), random.uniform(0.0, 1.0)) sphere = vtk.vtkSphereSource() sphere.SetCenter(random.uniform(0, 100), random.uniform(0, 100), random.uniform(0, 100)) sphere.SetRadius(random.uniform(20, 30)) sphere.Update() spherePolyData = sphere.GetOutput() sphereSegment.AddRepresentation( vtkSegmentationCore.vtkSegmentationConverter. GetSegmentationClosedSurfaceRepresentationName(), spherePolyData) self.inputSegmentationNode.GetSegmentation().AddSegment( sphereSegment) self.assertEqual( self.inputSegmentationNode.GetSegmentation().GetNumberOfSegments(), 3)
def test_SegmentStatisticsBasic(self): """ This tests some aspects of the label statistics """ self.delayDisplay("Starting test_SegmentStatisticsBasic") import vtkSegmentationCorePython as vtkSegmentationCore import SampleData from SegmentStatistics import SegmentStatisticsLogic self.delayDisplay("Load master volume") sampleDataLogic = SampleData.SampleDataLogic() masterVolumeNode = sampleDataLogic.downloadMRBrainTumor1() self.delayDisplay("Create segmentation containing a few spheres") segmentationNode = slicer.vtkMRMLSegmentationNode() slicer.mrmlScene.AddNode(segmentationNode) segmentationNode.CreateDefaultDisplayNodes() segmentationNode.SetReferenceImageGeometryParameterFromVolumeNode(masterVolumeNode) # Geometry for each segment is defined by: radius, posX, posY, posZ segmentGeometries = [[10, -6,30,28], [20, 0,65,32], [15, 1, -14, 30], [12, 0, 28, -7], [5, 0,30,64], [12, 31, 33, 27], [17, -42, 30, 27]] for segmentGeometry in segmentGeometries: sphereSource = vtk.vtkSphereSource() sphereSource.SetRadius(segmentGeometry[0]) sphereSource.SetCenter(segmentGeometry[1], segmentGeometry[2], segmentGeometry[3]) sphereSource.Update() uniqueSegmentID = segmentationNode.GetSegmentation().GenerateUniqueSegmentID("Test") segmentationNode.AddSegmentFromClosedSurfaceRepresentation(sphereSource.GetOutput(), uniqueSegmentID) self.delayDisplay("Compute statistics") segStatLogic = SegmentStatisticsLogic() segStatLogic.getParameterNode().SetParameter("Segmentation", segmentationNode.GetID()) segStatLogic.getParameterNode().SetParameter("ScalarVolume", masterVolumeNode.GetID()) segStatLogic.computeStatistics() self.delayDisplay("Check a few numerical results") self.assertEqual( segStatLogic.getStatistics()["Test_2","LabelmapSegmentStatisticsPlugin.voxel_count"], 9807) self.assertEqual( segStatLogic.getStatistics()["Test_4","ScalarVolumeSegmentStatisticsPlugin.voxel_count"], 380) self.delayDisplay("Export results to table") resultsTableNode = slicer.vtkMRMLTableNode() slicer.mrmlScene.AddNode(resultsTableNode) segStatLogic.exportToTable(resultsTableNode) segStatLogic.showTable(resultsTableNode) self.delayDisplay("Export results to string") logging.info(segStatLogic.exportToString()) outputFilename = slicer.app.temporaryPath + '/SegmentStatisticsTestOutput.csv' self.delayDisplay("Export results to CSV file: "+outputFilename) segStatLogic.exportToCSVFile(outputFilename) self.delayDisplay('test_SegmentStatisticsBasic passed!')
def _loadMaskNode(self, root, fname, ref_im=None): ma_path = self._buildPath(root, fname) if ma_path is None: return None # Check if the file actually exists if not os.path.isfile(ma_path): self.logger.warning( 'Segmentation file %s does not exist, skipping...', fname) return None # Determine if file is segmentation based on extension isSegmentation = os.path.splitext(ma_path)[0].endswith('.seg') # Try to load the mask if isSegmentation: self.logger.debug('Loading segmentation') load_success, ma_node = slicer.util.loadSegmentation( ma_path, returnNode=True) else: self.logger.debug( 'Loading labelmap and converting to segmentation') # If not segmentation, then load as labelmap then convert to segmentation load_success, ma_node = slicer.util.loadLabelVolume( ma_path, returnNode=True) if load_success: # Only try to make a segmentation node if Slicer was able to load the label map seg_node = slicer.vtkMRMLSegmentationNode() slicer.mrmlScene.AddNode(seg_node) seg_node.SetReferenceImageGeometryParameterFromVolumeNode( ref_im) load_success = slicer.modules.segmentations.logic( ).ImportLabelmapToSegmentationNode(ma_node, seg_node) slicer.mrmlScene.RemoveNode(ma_node) ma_node = seg_node # Add a storage node for this segmentation node file_base, ext = os.path.splitext(ma_path) store_node = seg_node.CreateDefaultStorageNode() slicer.mrmlScene.AddNode(store_node) seg_node.SetAndObserveStorageNodeID(store_node.GetID()) store_node.SetFileName('%s.seg%s' % (file_base, ext)) # UnRegister the storage node to prevent a memory leak store_node.UnRegister(None) if not load_success: self.logger.warning('Failed to load ' + ma_path) return None # Use the file basename as the name for the newly loaded segmentation node file_base = os.path.splitext(os.path.basename(ma_path))[0] if isSegmentation: # split off .seg file_base = os.path.splitext(file_base)[0] ma_node.SetName(file_base) return ma_node
def test_Segmentation(self): """ Test the GetRASBounds & GetBounds method on a segmentation. """ #self.delayDisplay("Starting test_Segmentation") cubeSource = vtk.vtkCubeSource() cubeSource.SetXLength(500) cubeSource.SetYLength(200) cubeSource.SetZLength(300) cubeSource.SetCenter(10, -85, 0.7) rotation = vtk.vtkTransform() rotation.RotateX(15.0) rotation.RotateZ(78) applyTransform = vtk.vtkTransformPolyDataFilter() applyTransform.SetTransform(rotation) applyTransform.SetInputConnection(cubeSource.GetOutputPort()) applyTransform.Update() modelNode = slicer.mrmlScene.AddNode(slicer.vtkMRMLModelNode()) modelNode.SetPolyDataConnection(applyTransform.GetOutputPort()) segmentationNode = slicer.mrmlScene.AddNode( slicer.vtkMRMLSegmentationNode()) segmentationLogic = slicer.modules.segmentations.logic() segmentationLogic.ImportModelToSegmentationNode( modelNode, segmentationNode) # Testing bounds = range(6) segmentationNode.GetRASBounds(bounds) untransformedBounds = [ -65.4164152220677, 237.23434621664234, -305.4495706784099, 289.7072339384947, -217.46321203583187, 213.68731403607347 ] self.assertListAlmostEquals(bounds, untransformedBounds) segmentationNode.GetBounds(bounds) self.assertListAlmostEquals(bounds, untransformedBounds) transform = vtk.vtkTransform() transform.Translate([-5.0, +42.0, -0.1]) transform.RotateWXYZ(41, 0.7, 0.6, 75) transform.Scale(2, 3, 10) transformNode = slicer.mrmlScene.AddNode(slicer.vtkMRMLTransformNode()) transformNode.ApplyTransform(transform) segmentationNode.SetAndObserveTransformNodeID(transformNode.GetID()) transformedBounds = [ -690.2701685073098, 970.3186946284741, -744.3124542486084, 1018.260811721817, -2183.4639807718822, 2144.107746300856 ] segmentationNode.GetRASBounds(bounds) self.assertListAlmostEquals(bounds, transformedBounds) segmentationNode.GetBounds(bounds) self.assertListAlmostEquals(bounds, untransformedBounds)
def TestSection_2_MergeLabelmapWithDifferentGeometries(self): # Merge labelmap when segments containing labelmaps with different geometries (both same directions, different directions) logging.info('Test section 2: Merge labelmap with different geometries') self.assertIsNotNone(self.sphereSegment) self.sphereSegment.RemoveRepresentation(self.binaryLabelmapReprName) self.assertIsNone(self.sphereSegment.GetRepresentation(self.binaryLabelmapReprName)) # Create new segmentation with sphere segment self.secondSegmentationNode = slicer.vtkMRMLSegmentationNode() self.secondSegmentationNode.SetName('Second') self.secondSegmentationNode.GetSegmentation().SetMasterRepresentationName(self.binaryLabelmapReprName) slicer.mrmlScene.AddNode(self.secondSegmentationNode) self.secondSegmentationNode.GetSegmentation().AddSegment(self.sphereSegment) # Check automatically converted labelmap. It is supposed to have the default geometry # (which is different than the one in the input segmentation) sphereLabelmap = self.sphereSegment.GetRepresentation(self.binaryLabelmapReprName) self.assertIsNotNone(sphereLabelmap) sphereLabelmapSpacing = sphereLabelmap.GetSpacing() self.assertTrue(sphereLabelmapSpacing[0] == 1.0 and sphereLabelmapSpacing[1] == 1.0 and sphereLabelmapSpacing[2] == 1.0) # Create binary labelmap in segmentation that will create the merged labelmap from # different geometries so that labelmap is not removed from sphere segment when adding self.inputSegmentationNode.GetSegmentation().CreateRepresentation(self.binaryLabelmapReprName) # Copy segment to input segmentation self.inputSegmentationNode.GetSegmentation().CopySegmentFromSegmentation(self.secondSegmentationNode.GetSegmentation(), self.sphereSegmentName) self.assertEqual(self.inputSegmentationNode.GetSegmentation().GetNumberOfSegments(), 3) # Check merged labelmap # Reference geometry has the tiny patient spacing, and it is oversampled to have smimilar # voxel size as the sphere labelmap with the uniform 1mm spacing mergedLabelmap = vtkSegmentationCore.vtkOrientedImageData() self.inputSegmentationNode.GenerateMergedLabelmapForAllSegments(mergedLabelmap, 0) mergedLabelmapSpacing = mergedLabelmap.GetSpacing() self.assertAlmostEqual(mergedLabelmapSpacing[0], 1.2894736842, 8) self.assertAlmostEqual(mergedLabelmapSpacing[1], 1.2894736842, 8) self.assertAlmostEqual(mergedLabelmapSpacing[2], 0.6052631578, 8) imageStat = vtk.vtkImageAccumulate() imageStat.SetInputData(mergedLabelmap) imageStat.SetComponentExtent(0,5,0,0,0,0) imageStat.SetComponentOrigin(0,0,0) imageStat.SetComponentSpacing(1,1,1) imageStat.Update() self.assertEqual(imageStat.GetVoxelCount(), 54872000) imageStatResult = imageStat.GetOutput() for i in range(5): logging.info("Volume {0}: {1}".format(i, imageStatResult.GetScalarComponentAsDouble(i,0,0,0))) self.assertEqual(imageStatResult.GetScalarComponentAsDouble(0,0,0,0), 43573723) self.assertEqual(imageStatResult.GetScalarComponentAsDouble(1,0,0,0), 10601312) self.assertEqual(imageStatResult.GetScalarComponentAsDouble(2,0,0,0), 251476) self.assertEqual(imageStatResult.GetScalarComponentAsDouble(3,0,0,0), 445489) self.assertEqual(imageStatResult.GetScalarComponentAsDouble(4,0,0,0), 0) # Built from color table and color four is removed in previous test section
def setupNeedleAndSegModelNode(self): self.clearOldNodesByName(self.NEEDLE_NAME) self.setupFiducialWidgetAndTableWidget() self.setupSegmentationWidget() if self.needleModelNode is None: self.needleModelNode = ModuleLogicMixin.createModelNode( self.NEEDLE_NAME) if (self.needleModelNode.GetScene() is None) or ( not self.needleModelNode.GetScene() == slicer.mrmlScene): slicer.mrmlScene.AddNode(self.needleModelNode) if self.needleModelNode.GetDisplayNode() is None: ModuleLogicMixin.createAndObserveDisplayNode( self.needleModelNode, displayNodeClass=slicer.vtkMRMLModelDisplayNode) self.needleModelNode.GetDisplayNode().SetColor(1.0, 0.0, 0.0) if self.affectedAreaModelNode is None: self.affectedAreaModelNode = ModuleLogicMixin.createModelNode( self.AFFECTEDAREA_NAME) if (self.affectedAreaModelNode.GetScene() is None) or ( not self.affectedAreaModelNode.GetScene() == slicer.mrmlScene): slicer.mrmlScene.AddNode(self.affectedAreaModelNode) if self.affectedAreaModelNode.GetDisplayNode() is None: ModuleLogicMixin.createAndObserveDisplayNode( self.affectedAreaModelNode, displayNodeClass=slicer.vtkMRMLModelDisplayNode) self.affectedAreaModelNode.GetDisplayNode().SetOpacity(0.5) self.affectedAreaModelNode.GetDisplayNode().SetColor(0.0, 1.0, 0.0) if self.data.segmentModelNode is None: # Create segmentation self.data.segmentModelNode = slicer.vtkMRMLSegmentationNode() slicer.mrmlScene.AddNode(self.data.segmentModelNode) self.data.segmentModelNode.CreateDefaultDisplayNodes( ) # only needed for display self.data.segmentModelNode.CreateDefaultStorageNode() self.data.segmentModelNode.SetName("IntraOpSegmentation") if (self.data.segmentModelNode.GetScene() is None) or ( not self.data.segmentModelNode.GetScene() == slicer.mrmlScene): slicer.mrmlScene.AddNode(self.data.segmentModelNode) if self.data.segmentModelNode.GetDisplayNode() is None: ModuleLogicMixin.createAndObserveDisplayNode( self.data.segmentModelNode, displayNodeClass=slicer.vtkMRMLSegmentationDisplayNode) if self.segmentEditorNode is None: self.segmentEditorNode = slicer.vtkMRMLSegmentEditorNode() slicer.mrmlScene.AddNode(self.segmentEditorNode) if (self.segmentEditorNode.GetScene() is None) or ( not self.segmentEditorNode.GetScene() == slicer.mrmlScene): slicer.mrmlScene.AddNode(self.segmentEditorNode) self.segmentationEditor.setMRMLScene(slicer.mrmlScene) self.segmentationEditor.setMRMLSegmentEditorNode( self.segmentEditorNode) self.segmentationEditorMaskOverWriteCombox.setCurrentIndex( self.segmentationEditorMaskOverWriteCombox.findText('None'))
def buildSegment(self, inputVolme, masterSegment=None, segmentationNode=None, name='airway'): if (segmentationNode == None): segmentationNode = slicer.vtkMRMLSegmentationNode() slicer.mrmlScene.AddNode(segmentationNode) segmentationNode.CreateDefaultDisplayNodes() segmentationNode.SetReferenceImageGeometryParameterFromVolumeNode( inputVolme) segmentID = segmentationNode.GetSegmentation().AddEmptySegment(name) segmentationEditor = slicer.qMRMLSegmentEditorWidget() segmentationEditor.setMRMLScene(slicer.mrmlScene) segmentationEditor.setMRMLSegmentEditorNode( slicer.mrmlScene.AddNewNodeByClass('vtkMRMLSegmentEditorNode')) segmentationEditor.setSegmentationNode(segmentationNode) #//segmentationEditor.ad & test & # ? What was this line supposed to be? I can't remember but it doesn't seem to be causing problems for now segmentationEditor.setMasterVolumeNode(inputVolme) #import qSlicerSegmentationEditorEffectsPythonQt as effects segmentationEditor.setActiveEffectByName('Threshold') effect = segmentationEditor.activeEffect() effect.setParameter('MinimumThreshold', '-1024') effect.setParameter('MaximumThreshold', AIR_DENSITY_THRESHOLD) effect.self().onApply() # FIXME: part of the fix for handling out of bounds air - currently broken #if masterSegment is not None: #segmentationEditor.setActiveEffectByName('Logical operators') #effect = segmentationEditor.activeEffect() #effect.setParameter('ModifierSegmentID', masterSegment.GetName()) #effect.setParameter('Operation', 'INTERSECT') #effect.self().onApply() segmentationEditor.setActiveEffectByName('Islands') effect = segmentationEditor.activeEffect() effect.setParameter('KeepLargestIsland', True) effect.self().onApply() segmentationNode.CreateClosedSurfaceRepresentation() surfaceMesh = segmentationNode.GetClosedSurfaceRepresentation( segmentID) normals = vtk.vtkPolyDataNormals() normals.ConsistencyOn() normals.SetInputData(surfaceMesh) normals.Update() surfaceMesh = normals.GetOutput() return segmentationNode
def test_Autoscroll(self): """ Basic automated test of the segmentation method: - Create segmentation by placing sphere-shaped seeds - Run segmentation - Verify results using segment statistics The test can be executed from SelfTests module (test name: SegmentEditorAutoscroll) """ self.delayDisplay("Starting test_Autoscroll") import vtkSegmentationCorePython as vtkSegmentationCore import vtkSlicerSegmentationsModuleLogicPython as vtkSlicerSegmentationsModuleLogic import SampleData from SegmentStatistics import SegmentStatisticsLogic ################################## self.delayDisplay("Load master volume") import SampleData sampleDataLogic = SampleData.SampleDataLogic() masterVolumeNode = sampleDataLogic.downloadMRBrainTumor1() ################################## self.delayDisplay("Create segmentation with an empty segment") segmentationNode = slicer.vtkMRMLSegmentationNode() slicer.mrmlScene.AddNode(segmentationNode) segmentationNode.CreateDefaultDisplayNodes() segmentationNode.SetReferenceImageGeometryParameterFromVolumeNode(masterVolumeNode) segment = vtkSegmentationCore.vtkSegment() segmentationNode.GetSegmentation().AddSegment(segment) ################################## self.delayDisplay("Create segment editor") segmentEditorWidget = slicer.qMRMLSegmentEditorWidget() segmentEditorWidget.show() segmentEditorWidget.setMRMLScene(slicer.mrmlScene) segmentEditorNode = slicer.vtkMRMLSegmentEditorNode() slicer.mrmlScene.AddNode(segmentEditorNode) segmentEditorWidget.setMRMLSegmentEditorNode(segmentEditorNode) segmentEditorWidget.setSegmentationNode(segmentationNode) segmentEditorWidget.setMasterVolumeNode(masterVolumeNode) ################################## self.delayDisplay("Run autoscroll for 10 seconds") segmentEditorWidget.setActiveEffectByName("Autoscroll") effect = segmentEditorWidget.activeEffect() qt.QTimer.singleShot(10000, effect.self().onApply) effect.self().onApply() self.delayDisplay('test_Autoscroll passed')
def load_data_to_placeholders(self, subject_dir): self.image_root = subject_dir images = { 'pre_T1_pre': 0, 'pre_T1_EA': 1, 'pre_T1_EA_sub': 2, 'pre_T1_LA': 3, 'pre_T1_LA_sub': 4, 'pre_T1_PV': 5, 'pre_T1_PV_sub': 6, 'pre_ADC': 7, 'post_T1_pre': 8, 'post_T1_EA': 9, 'post_T1_EA_sub': 10, 'post_T1_LA': 11, 'post_T1_LA_sub': 12, 'post_T1_PV': 13, 'post_T1_PV_sub': 14, 'post_ADC': 15, 'post_ADC_Eq_1': 16, 'pre_ADC_Eq_1': 17 } raws = list() labels = list() for i in os.listdir(subject_dir): file_name = i.lower() for j, count in images.items(): if j.lower() + ".nii.gz" in file_name: #print (j+" is found! Corresponding to filepath:"+str(i)+"And is given a count of "+str(count)) img = slicer.util.loadVolume(os.path.join(subject_dir, i), returnNode=True)[1] raws.append([img, count]) if j.lower() + "_tumor_" + self.reader_name.lower( ) + ".nii.gz" in file_name: #print (j+" is found! Corresponding to filepath:"+str(i)+"And is given a count of "+str(count)) print("Reader Name: " + self.reader_name) load_success, ma_node = slicer.util.loadLabelVolume( os.path.join(subject_dir, i), returnNode=True) seg_node = slicer.vtkMRMLSegmentationNode() slicer.mrmlScene.AddNode(seg_node) load_success = slicer.modules.segmentations.logic( ).ImportLabelmapToSegmentationNode(ma_node, seg_node) & load_success slicer.mrmlScene.RemoveNode(ma_node) seg_node.SetName(j + "_segment") segmentationDisplayNode = seg_node.GetDisplayNode() segmentationDisplayNode.VisibilityOff() labels.append([seg_node, count]) #print (seg_node,count) return raws, labels
def OnSmoothLabelMapButtonClicked(self): # Get working polydata WorkingNodeName = self.WorkingLabelMapStorage.currentNode().GetName() if self.SegmentationNode.GetClosedSurfaceRepresentation( WorkingNodeName) == None: self.SegmentationNode.CreateClosedSurfaceRepresentation() WorkingPolyData = self.SegmentationNode.GetClosedSurfaceRepresentation( WorkingNodeName) # Smooth working polydata logic = UsSurfaceToLandmarksLogic() SmoothedPolyData = logic.SmoothPolyData( WorkingPolyData, self.SmoothingConvergenceSlider.value, self.SmoothingIterationsSlider.value) # Convert polydata to labelmap via segmentation and vtkmodel SmoothedModelNode = slicer.vtkMRMLModelNode() SmoothedModelNode.SetName(WorkingNodeName) SmoothedModelNode.SetAndObservePolyData(SmoothedPolyData) #SmoothedModelNode ConvSeg = slicer.vtkMRMLSegmentationNode() ConvSeg.SetScene(slicer.mrmlScene) SegLogic = slicer.modules.segmentations.logic() SegLogic.ImportModelToSegmentationNode(SmoothedModelNode, ConvSeg) ConvSeg.CreateBinaryLabelmapRepresentation() ConvSeg.SetMasterRepresentationToBinaryLabelmap() # Clear mrmlScene of old labelmap node before exporting the new one #OldLabelMapNode = self.WorkingLabelMapStorage.currentNode() #OldLabelMapNode = slicer.util.getNode(WorkingNodeName) #if OldLabelMapNode != None: # slicer.mrmlScene.RemoveNode(OldLabelMapNode) # Export segmentation label map representation to mrml node for storage in interface SmoothedLabelMapNode = slicer.vtkMRMLLabelMapVolumeNode() SmoothedLabelMapNode.SetName(WorkingNodeName + self.SmoothTag) LabelMapName = vtk.vtkStringArray() LabelMapName.InsertNextValue(WorkingNodeName) slicer.mrmlScene.AddNode(SmoothedLabelMapNode) SegLogic.ExportSegmentsToLabelmapNode(ConvSeg, LabelMapName, SmoothedLabelMapNode) #SmoothedLabelMapNode.SetOrigin(self.InputVolumeSelector.currentNode().GetOrigin()) # Update working polydata in UI # Add new smoothed label map node to mrmlScene self.WorkingLabelMapStorage.setCurrentNode(SmoothedLabelMapNode) self.UpdateSegmentationNode() return True
def test_Segmentation(self): """ Test the GetRASBounds & GetBounds method on a segmentation. """ #self.delayDisplay("Starting test_Segmentation") cubeSource = vtk.vtkCubeSource() cubeSource.SetXLength(500) cubeSource.SetYLength(200) cubeSource.SetZLength(300) cubeSource.SetCenter(10, -85, 0.7) rotation = vtk.vtkTransform() rotation.RotateX(15.0) rotation.RotateZ(78) applyTransform = vtk.vtkTransformPolyDataFilter() applyTransform.SetTransform(rotation) applyTransform.SetInputConnection(cubeSource.GetOutputPort()) applyTransform.Update() modelNode = slicer.mrmlScene.AddNode(slicer.vtkMRMLModelNode()) modelNode.SetPolyDataConnection(applyTransform.GetOutputPort()) segmentationNode = slicer.mrmlScene.AddNode(slicer.vtkMRMLSegmentationNode()) segmentationLogic = slicer.modules.segmentations.logic() segmentationLogic.ImportModelToSegmentationNode(modelNode, segmentationNode) # Testing bounds = range(6) segmentationNode.GetRASBounds(bounds) untransformedBounds = [-65.0710220336914, 235.9289779663086, -304.413391113281, 288.586608886719, -216.427032470703, 213.572967529297] self.assertListAlmostEquals(bounds, untransformedBounds) segmentationNode.GetBounds(bounds) self.assertListAlmostEquals(bounds, untransformedBounds) transform = vtk.vtkTransform() transform.Translate([-5.0, +42.0, -0.1]) transform.RotateWXYZ(41, 0.7, 0.6, 75) transform.Scale(2, 3, 10) transformNode = slicer.mrmlScene.AddNode(slicer.vtkMRMLTransformNode()) transformNode.ApplyTransform(transform) segmentationNode.SetAndObserveTransformNodeID(transformNode.GetID()) transformedBounds = [-200.70776329131795, 479.54290966330126, -723.6172978253361, 996.0765602877555, -2171.2883672792996, 2141.1537548033725] segmentationNode.GetRASBounds(bounds) self.assertListAlmostEquals(bounds, transformedBounds) segmentationNode.GetBounds(bounds) self.assertListAlmostEquals(bounds, untransformedBounds)
def test_Segmentation(self): """ Test the GetRASBounds & GetBounds method on a segmentation. """ #self.delayDisplay("Starting test_Segmentation") cubeSource = vtk.vtkCubeSource() cubeSource.SetXLength(500) cubeSource.SetYLength(200) cubeSource.SetZLength(300) cubeSource.SetCenter(10, -85, 0.7) rotation = vtk.vtkTransform() rotation.RotateX(15.0) rotation.RotateZ(78) applyTransform = vtk.vtkTransformPolyDataFilter() applyTransform.SetTransform(rotation) applyTransform.SetInputConnection(cubeSource.GetOutputPort()) applyTransform.Update() modelNode = slicer.mrmlScene.AddNode(slicer.vtkMRMLModelNode()) modelNode.SetPolyDataConnection(applyTransform.GetOutputPort()) segmentationNode = slicer.mrmlScene.AddNode(slicer.vtkMRMLSegmentationNode()) segmentationLogic = slicer.modules.segmentations.logic() segmentationLogic.ImportModelToSegmentationNode(modelNode, segmentationNode) # Testing bounds = range(6) segmentationNode.GetRASBounds(bounds) untransformedBounds = [-65.4164152220677, 237.23434621664234, -305.4495706784099, 289.7072339384947, -217.46321203583187, 213.68731403607347] self.assertListAlmostEquals(bounds, untransformedBounds) segmentationNode.GetBounds(bounds) self.assertListAlmostEquals(bounds, untransformedBounds) transform = vtk.vtkTransform() transform.Translate([-5.0, +42.0, -0.1]) transform.RotateWXYZ(41, 0.7, 0.6, 75) transform.Scale(2, 3, 10) transformNode = slicer.mrmlScene.AddNode(slicer.vtkMRMLTransformNode()) transformNode.ApplyTransform(transform) segmentationNode.SetAndObserveTransformNodeID(transformNode.GetID()) transformedBounds = [-690.2701685073098, 970.3186946284741, -744.3124542486084, 1018.260811721817, -2183.4639807718822, 2144.107746300856] segmentationNode.GetRASBounds(bounds) self.assertListAlmostEquals(bounds, transformedBounds) segmentationNode.GetBounds(bounds) self.assertListAlmostEquals(bounds, untransformedBounds)
def test_Segmentation(self): """ Test the GetRASBounds & GetBounds method on a segmentation. """ #self.delayDisplay("Starting test_Segmentation") cubeSource = vtk.vtkCubeSource() cubeSource.SetXLength(500) cubeSource.SetYLength(200) cubeSource.SetZLength(300) cubeSource.SetCenter(10, -85, 0.7) rotation = vtk.vtkTransform() rotation.RotateX(15.0) rotation.RotateZ(78) applyTransform = vtk.vtkTransformPolyDataFilter() applyTransform.SetTransform(rotation) applyTransform.SetInputConnection(cubeSource.GetOutputPort()) applyTransform.Update() modelNode = slicer.mrmlScene.AddNode(slicer.vtkMRMLModelNode()) modelNode.SetPolyDataConnection(applyTransform.GetOutputPort()) segmentationNode = slicer.mrmlScene.AddNode(slicer.vtkMRMLSegmentationNode()) segmentationLogic = slicer.modules.segmentations.logic() segmentationLogic.ImportModelToSegmentationNode(modelNode, segmentationNode) # Testing bounds = range(6) segmentationNode.GetRASBounds(bounds) untransformedBounds = [-65.0710220336914, 235.9289779663086, -304.413391113281, 288.586608886719, -216.427032470703, 213.572967529297] self.assertListAlmostEquals(bounds, untransformedBounds) segmentationNode.GetBounds(bounds) self.assertListAlmostEquals(bounds, untransformedBounds) transform = vtk.vtkTransform() transform.Translate([-5.0, +42.0, -0.1]) transform.RotateWXYZ(41, 0.7, 0.6, 75) transform.Scale(2, 3, 10) transformNode = slicer.mrmlScene.AddNode(slicer.vtkMRMLTransformNode()) transformNode.ApplyTransform(transform) segmentationNode.SetAndObserveTransformNodeID(transformNode.GetID()) transformedBounds = [-687.4653523284665, 966.3004987004498, -741.50842882335, 1013.9676912857693, -2173.06971199151, 2142.935099515583] segmentationNode.GetRASBounds(bounds) self.assertListAlmostEquals(bounds, transformedBounds) segmentationNode.GetBounds(bounds) self.assertListAlmostEquals(bounds, untransformedBounds)
def AddSegmentNode(self, modelNode, volumeLabel): #This function creates a segmentation from the output model (ie cropped breast models) # and computed the volume of the segmentation, this is done to ensure the volume is computed correctly segmentationNode = slicer.vtkMRMLSegmentationNode() slicer.mrmlScene.AddNode(segmentationNode) displayNode = slicer.mrmlScene.GetNthNodeByClass(1, 'vtkMRMLScalarVolumeDisplayNode') if displayNode == None: displayNode = slicer.vtkMRMLScalarVolumeDisplayNode() segmentationNode.SetAndObserveDisplayNodeID(displayNode.GetID()) segmentationNode.SetName("Model Segmentation Node") slicer.modules.segmentations.logic().ImportModelToSegmentationNode(modelNode, segmentationNode) segment = segmentationNode.GetSegmentation().GetNthSegment(0) segBinaryLabelName = vtkSegmentationCore.vtkSegmentationConverter.GetSegmentationBinaryLabelmapRepresentationName() segmentLabelmap = segment.GetRepresentation(segBinaryLabelName) # We need to know exactly the value of the segment voxels, apply threshold to make force the selected label value labelValue = 1 backgroundValue = 0 thresh = vtk.vtkImageThreshold() thresh.SetInputData(segmentLabelmap) thresh.ThresholdByLower(0) thresh.SetInValue(backgroundValue) thresh.SetOutValue(labelValue) thresh.SetOutputScalarType(vtk.VTK_UNSIGNED_CHAR) thresh.Update() # Use binary labelmap as a stencil stencil = vtk.vtkImageToImageStencil() stencil.SetInputData(thresh.GetOutput()) stencil.ThresholdByUpper(labelValue) stencil.Update() stat = vtk.vtkImageAccumulate() stat.SetInputData(thresh.GetOutput()) stat.SetStencilData(stencil.GetOutput()) stat.Update() # Add data to statistics list cubicMMPerVoxel = reduce(lambda x, y: x * y, segmentLabelmap.GetSpacing()) ccPerCubicMM = 0.001 stats = {} volume = round(stat.GetVoxelCount() * cubicMMPerVoxel * ccPerCubicMM, 0) volumeLabel.setText(volume) slicer.mrmlScene.RemoveNode(segmentationNode) return volume
def enter(self): """Runs whenever the module is reopened """ self.turnOffLightboxes() self.installShortcutKeys() # Set parameter set node if absent self.selectParameterNode() self.editor.updateWidgetFromMRML() # If no segmentation node exists then create one so that the user does not have to create one manually if not self.editor.segmentationNodeID(): newSegmentationNode = slicer.vtkMRMLSegmentationNode() slicer.mrmlScene.AddNode(newSegmentationNode) self.editor.setSegmentationNode(newSegmentationNode) masterVolumeNodeID = self.getDefaultMasterVolumeNodeID() self.editor.setMasterVolumeNodeID(masterVolumeNodeID)
def importFiles(self, filePaths): for path in filePaths: # load each file pathPair = os.path.split(path) directory = pathPair[0] fileName = pathPair[1] self.testCaseDict[fileName] = MRMLUtility.loadMRMLNode( fileName, directory, fileName, 'LabelMap') if self.testCaseDict[fileName] is None: print 'ERROR: Failed to load ' + fileName + 'as a labelmap' # make sure each one is a labelmap continue # Create segmentation representations. self.segmentationDict[fileName] = MRMLUtility.createNewMRMLNode( fileName + '_allSegments', slicer.vtkMRMLSegmentationNode()) slicer.modules.segmentations.logic( ).ImportLabelmapToSegmentationNode(self.testCaseDict[fileName], self.segmentationDict[fileName]) t = self.segmentationDict[ fileName].CreateClosedSurfaceRepresentation() if t == False: print 'ERROR: Failed to create closed surface representation' continue self.segmentationDict[fileName].SetDisplayVisibility(False) # find how many labels each file has.. labelRange = self.testCaseDict[fileName].GetImageData( ).GetScalarRange() if self.labelRangeInCohort != ( -1, -1) and labelRange != self.labelRangeInCohort: print 'ERROR: Number of labels do not match in the cohort' return False self.labelRangeInCohort = labelRange print 'Cohort label range is: ' + str(self.labelRangeInCohort) # given labels, and current mode populate the structures slider self.labelRangeInCohort = (int(self.labelRangeInCohort[0]), int(self.labelRangeInCohort[1])) return True
def duplicateProbeNode(fidPairs, probeNode): #print("Copying: ", probeNode) numDuplicates = int(fidPairs) nodeIds = [] #nodeIds.append(probeNode.GetID()) if (numDuplicates > 0): for i in range(0, numDuplicates): mergedImage = vtk.vtkPolyData() probeNode.GetClosedSurfaceRepresentation( probeNode.GetSegmentation().GetNthSegmentID(0), mergedImage) segmentationNode = slicer.vtkMRMLSegmentationNode() slicer.mrmlScene.AddNode(segmentationNode) slicer.app.processEvents( ) #force update as occasionally the follow steps cause slicer to crash time.sleep(0.1) segmentationNode.CreateDefaultDisplayNodes( ) # only needed for display segmentationNode.AddSegmentFromClosedSurfaceRepresentation( mergedImage, "duplicate_node", [0, 1, 0]) segmentationNode.GetSegmentation().CreateRepresentation( "Closed surface") segmentationNode.GetSegmentation().SetMasterRepresentationName( "Binary labelmap") segDisplayNode = probeNode.GetDisplayNode() segDisplayNode.SetOpacity(0.3) segDisplayNode = segmentationNode.GetDisplayNode() segDisplayNode.SetOpacity(0.3) slicer.app.processEvents() time.sleep(0.1) nodeIds.append(segmentationNode.GetID()) #CHANGED THIS seg_name = probeNode.GetName() new_seg_name = seg_name + "_" + str(i) segmentationNode.SetName(new_seg_name) #probeNode.GetSegmentation().CreateRepresentation("Binary labelmap") #probeNode.GetSegmentation().SetMasterRepresentationName("Binary labelmap") return nodeIds
def OnDecimateLabelMapButtonClicked(self): # Get working polydata WorkingNodeName = self.WorkingLabelMapStorage.currentNode().GetName() if self.SegmentationNode.GetClosedSurfaceRepresentation( WorkingNodeName) == None: self.SegmentationNode.CreateClosedSurfaceRepresentation() WorkingPolyData = self.SegmentationNode.GetClosedSurfaceRepresentation( WorkingNodeName) # Decimate working polydata logic = UsSurfaceToLandmarksLogic() DecimatedPolyData = logic.DecimatePolyData(WorkingPolyData) # Convert polydata to labelmap via segmentation and vtkmodel DecimatedModelNode = slicer.vtkMRMLModelNode() DecimatedModelNode.SetName(WorkingNodeName) DecimatedModelNode.SetAndObservePolyData(DecimatedPolyData) ConvSeg = slicer.vtkMRMLSegmentationNode() ConvSeg.SetScene(slicer.mrmlScene) SegLogic = slicer.modules.segmentations.logic() SegLogic.ImportModelToSegmentationNode(DecimatedModelNode, ConvSeg) ConvSeg.CreateBinaryLabelmapRepresentation() ConvSeg.SetMasterRepresentationToBinaryLabelmap() LabelMapName = vtk.vtkStringArray() LabelMapName.InsertNextValue(WorkingNodeName) DecimatedLabelMapNode = slicer.vtkMRMLLabelMapVolumeNode() DecimatedLabelMapNode.SetName(WorkingNodeName) slicer.mrmlScene.AddNode(DecimatedLabelMapNode) SegLogic.ExportSegmentsToLabelmapNode(ConvSeg, LabelMapName, DecimatedLabelMapNode) #SmoothedOrientedImageData = ConvSeg.GetBinaryLabelmapRepresentation(WorkingNodeName) #DecimatedLabelMapNode.SetAndObserveImageData(SmoothedOrientedImageData) # Update working polydata in UI self.WorkingLabelMapStorage.setCurrentNode(DecimatedLabelMapNode) self.UpdateSegmentationNode() return True
def OnRemoveIslandsButtonClicked(self): logic = UsSurfaceToLandmarksLogic() WorkingLabelMap = self.WorkingLabelMapStorage.currentNode() WorkingImageData = WorkingLabelMap.GetImageData() # Clear mrmlScene of old labelmap node before exporting the new one OldLabelMapNode = self.WorkingLabelMapStorage.currentNode() if OldLabelMapNode != None: slicer.mrmlScene.RemoveNode(OldLabelMapNode) print "DEBUG - About to remove islands" LabelMapIslandsRemoved = logic.RemoveCoronalIslands( WorkingImageData, self.IslandSizeThresholdSlider.value) LabelMapIslandsRemoved.SetName(WorkingLabelMap.GetName()) print "DEBUG - Islands removed" ConvSeg = slicer.vtkMRMLSegmentationNode() ConvSeg.SetScene(slicer.mrmlScene) SegLogic = slicer.modules.segmentations.logic() SegLogic.ImportLabelmapToSegmentationNode(LabelMapIslandsRemoved, ConvSeg) ConvSeg.CreateBinaryLabelmapRepresentation() ConvSeg.SetMasterRepresentationToBinaryLabelmap() LabelMapName = vtk.vtkStringArray() LabelMapName.InsertNextValue(WorkingLabelMap.GetName()) DeislandedLabelMapNode = slicer.vtkMRMLLabelMapVolumeNode() DeislandedLabelMapNode.SetName(WorkingLabelMap.GetName()) slicer.mrmlScene.AddNode(DeislandedLabelMapNode) SegLogic.ExportSegmentsToLabelmapNode(ConvSeg, LabelMapName, DeislandedLabelMapNode) # Update mrmlScene and UI #slicer.mrmlScene.AddNode(LabelMapIslandsRemoved) self.WorkingLabelMapStorage.setCurrentNode(DeislandedLabelMapNode) self.UpdateSegmentationNode() return True
def enter(self): """Runs whenever the module is reopened """ if self.editor.turnOffLightboxes(): slicer.util.warningDisplay('Segment Editor is not compatible with slice viewers in light box mode.' 'Views are being reset.', windowTitle='Segment Editor') # Allow switching between effects and selected segment using keyboard shortcuts self.editor.installKeyboardShortcuts() # Set parameter set node if absent self.selectParameterNode() self.editor.updateWidgetFromMRML() # If no segmentation node exists then create one so that the user does not have to create one manually if not self.editor.segmentationNodeID(): segmentationNode = slicer.mrmlScene.GetFirstNode(None, "vtkMRMLSegmentationNode") if not segmentationNode: segmentationNode = slicer.vtkMRMLSegmentationNode() slicer.mrmlScene.AddNode(segmentationNode) self.editor.setSegmentationNode(segmentationNode) if not self.editor.masterVolumeNodeID(): masterVolumeNodeID = self.getDefaultMasterVolumeNodeID() self.editor.setMasterVolumeNodeID(masterVolumeNodeID)
def generateMask(self): #masterVolumeNode = slicer.util.getNode('1*') try: slicer.mrmlScene.RemoveNode(slicer.util.getNode("*masked")) except slicer.util.MRMLNodeNotFoundException: pass try: slicer.mrmlScene.RemoveNode(slicer.util.getNode("*masked*")) except slicer.util.MRMLNodeNotFoundException: pass # Create segmentation if mesh objects are present/selected if not self.selectedModelsList == []: for model in self.selectedModelsList: if model.currentNode() is not None: try: masterVolumeNode = slicer.util.getNode("*masked") except slicer.util.MRMLNodeNotFoundException: masterVolumeNode = slicer.util.getNode('1*') try: masterVolumeNode = slicer.util.getNode("*masked*") except slicer.util.MRMLNodeNotFoundException: masterVolumeNode = slicer.util.getNode('1*') segmentationNode = slicer.vtkMRMLSegmentationNode() slicer.mrmlScene.AddNode(segmentationNode) #segmentationNode.CreateDefaultDisplayNodes() # only needed for display slicer.vtkSlicerSegmentationsModuleLogic.ImportModelToSegmentationNode( model.currentNode(), segmentationNode) segmentationNode.CreateBinaryLabelmapRepresentation() # Create segment editor to get access to effects segmentEditorWidget = slicer.qMRMLSegmentEditorWidget() # To show segment editor widget (useful for debugging): segmentEditorWidget.show() segmentEditorWidget.setMRMLScene(slicer.mrmlScene) segmentEditorNode = slicer.vtkMRMLSegmentEditorNode() slicer.mrmlScene.AddNode(segmentEditorNode) segmentEditorWidget.setMRMLSegmentEditorNode( segmentEditorNode) segmentEditorWidget.setSegmentationNode(segmentationNode) segmentEditorWidget.setMasterVolumeNode(masterVolumeNode) # Set up masking parameters segmentEditorWidget.setActiveEffectByName("Mask volume") effect = segmentEditorWidget.activeEffect() # set fill value to be outside the valid intensity range effect.setParameter("FillValue", str(20000)) # Blank out voxels that are outside the segment effect.setParameter("Operation", "FILL_INSIDE") for segmentIndex in range(segmentationNode.GetSegmentation( ).GetNumberOfSegments()): # Set active segment segmentID = segmentationNode.GetSegmentation( ).GetNthSegmentID(segmentIndex) segmentEditorWidget.setCurrentSegmentID(segmentID) # Apply mask effect.self().onApply() if "masked" in masterVolumeNode.GetName(): slicer.mrmlScene.RemoveNode(masterVolumeNode)
def test_Engrave1(self): """ Basic automated test of the segmentation method: - Create segmentation by placing fiducials around tumor - Apply - Verify results using segment statistics The test can be executed from SelfTests module (test name: SegmentEditorEngrave) """ self.delayDisplay("Starting test_Engrave1") ################################## self.delayDisplay("Load master volume") import SampleData sampleDataLogic = SampleData.SampleDataLogic() masterVolumeNode = sampleDataLogic.downloadMRBrainTumor1() ################################## self.delayDisplay("Create tumor segmentation") segmentationNode = slicer.vtkMRMLSegmentationNode() slicer.mrmlScene.AddNode(segmentationNode) segmentationNode.CreateDefaultDisplayNodes() segmentationNode.SetReferenceImageGeometryParameterFromVolumeNode( masterVolumeNode) segmentName = "Tumor" import vtkSegmentationCorePython as vtkSegmentationCore segment = vtkSegmentationCore.vtkSegment() segment.SetName( segmentationNode.GetSegmentation().GenerateUniqueSegmentID( segmentName)) segmentationNode.GetSegmentation().AddSegment(segment) ################################## self.delayDisplay("Create segment editor") segmentEditorWidget = slicer.qMRMLSegmentEditorWidget() segmentEditorWidget.show() segmentEditorWidget.setMRMLScene(slicer.mrmlScene) segmentEditorNode = slicer.vtkMRMLSegmentEditorNode() slicer.mrmlScene.AddNode(segmentEditorNode) segmentEditorWidget.setMRMLSegmentEditorNode(segmentEditorNode) segmentEditorWidget.setSegmentationNode(segmentationNode) segmentEditorWidget.setMasterVolumeNode(masterVolumeNode) ################################## self.delayDisplay("Run segmentation") segmentEditorWidget.setActiveEffectByName("ENgrave") effect = segmentEditorWidget.activeEffect() # effect.self().fiducialPlacementToggle.placeButton().click() # points =[[2.589283578714074, 44.60536690073953, 27.299999999999997], [8.515228351086698, 35.22262101114956, 27.299999999999997], # [13.700430026912741, 25.099132025013006, 27.299999999999997], [5.799170330415919, 19.17318725264039, 27.299999999999997], # [2.589283578714074, 9.296612632019361, 27.299999999999997], [-10.250263428093263, 12.25958501820567, 27.299999999999997], # [-16.17620820046588, 18.185529790578286, 27.299999999999997], [-20.373752414229813, 27.568275680168263, 27.299999999999997], # [-15.929293834950343, 38.679422128366916, 27.299999999999997], [-11.484835255670887, 44.11153816970849, 27.299999999999997], # [6.539913426962492, 33.49422045254088, 31.499999999999993], [1.354711751136449, 42.383137611099805, 31.499999999999993], # [-8.768777235000101, 44.35845253522401, 31.499999999999993], [-14.200893276341674, 36.70410720424271, 31.499999999999993], # [-18.398437490105607, 27.07444694913721, 31.499999999999993], [-12.719407083248512, 16.704043597485132, 31.499999999999993], # [-7.534205407422476, 11.765756287174618, 31.499999999999993], [0.12013992355882408, 12.25958501820567, 31.499999999999993], # [5.799170330415919, 16.21021486645408, 31.499999999999993], [8.268313985571176, 21.642330907795646, 31.499999999999993], # [13.947344392428263, 26.827532583621682, 31.499999999999993], [-3.0897468281430065, 32.50656299047878, 45.49999999999998], # [2.589283578714074, 27.32136131465274, 45.49999999999998], [-5.3119761177827485, 21.642330907795646, 45.49999999999998], # [-8.02803413845352, 27.32136131465274, 45.49999999999998], [-14.694722007372718, 30.778162431870093, 38.499999999999986], # [-8.02803413845352, 12.01267065269014, 38.499999999999986], [-3.583575559174065, 39.66707959042902, 11.900000000000007], # [3.576941040776184, 31.765819893932196, 11.900000000000007], [0.12013992355882408, 20.901587811249065, 11.900000000000007], # [-9.26260596603116, 28.555933142230366, 11.900000000000007], [6.046084695931441, 38.432507762851394, 17.500000000000007], # [-17.163865662527982, 33.7411348180564, 17.500000000000007], [-14.200893276341674, 21.889245273311168, 17.500000000000007]] # for p in points: # effect.self().segmentMarkupNode.AddControlPoint(p) # effect.self().onApply() # ################################## # self.delayDisplay("Make segmentation results nicely visible in 3D") # segmentationDisplayNode = segmentationNode.GetDisplayNode() # segmentationDisplayNode.SetSegmentVisibility(segmentName, True) # slicer.util.findChild(segmentEditorWidget, "Show3DButton").checked = True # segmentationDisplayNode.SetSegmentOpacity3D("Background",0.5) # ################################## # self.delayDisplay("Compute statistics") # from SegmentStatistics import SegmentStatisticsLogic # segStatLogic = SegmentStatisticsLogic() # segStatLogic.getParameterNode().SetParameter("Segmentation", segmentationNode.GetID()) # segStatLogic.getParameterNode().SetParameter("ScalarVolume", masterVolumeNode.GetID()) # segStatLogic.getParameterNode().SetParameter("visibleSegmentsOnly", "False") # segStatLogic.computeStatistics() # # Export results to table (just to see all results) # resultsTableNode = slicer.vtkMRMLTableNode() # slicer.mrmlScene.AddNode(resultsTableNode) # segStatLogic.exportToTable(resultsTableNode) # segStatLogic.showTable(resultsTableNode) # self.delayDisplay("Check a few numerical results") # stats = segStatLogic.getStatistics() # self.assertEqual( round(stats['Tumor', 'LabelmapSegmentStatisticsPlugin.volume_mm3']), 19498.0) self.delayDisplay('test_Engrave1 passed')
def test_SegmentEditorFloodFilling1(self): """ Basic automated test of the segmentation method: - Create segmentation by placing sphere-shaped seeds - Run segmentation - Verify results using segment statistics The test can be executed from SelfTests module (test name: SegmentEditorFloodFilling) """ self.delayDisplay("Starting test_SegmentEditorFloodFilling1") import vtkSegmentationCorePython as vtkSegmentationCore import vtkSlicerSegmentationsModuleLogicPython as vtkSlicerSegmentationsModuleLogic import SampleData from SegmentStatistics import SegmentStatisticsLogic ################################## self.delayDisplay("Load master volume") import SampleData sampleDataLogic = SampleData.SampleDataLogic() masterVolumeNode = sampleDataLogic.downloadMRBrainTumor1() ################################## self.delayDisplay("Create segmentation containing a few spheres") segmentationNode = slicer.vtkMRMLSegmentationNode() slicer.mrmlScene.AddNode(segmentationNode) segmentationNode.CreateDefaultDisplayNodes() segmentationNode.SetReferenceImageGeometryParameterFromVolumeNode( masterVolumeNode) # Segments are defined by a list of: name and a list of sphere [radius, posX, posY, posZ] segmentGeometries = [['Tumor', [[10, -6, 30, 28]]], [ 'Background', [[10, 0, 65, 22], [15, 1, -14, 30], [12, 0, 28, -7], [5, 0, 30, 54], [12, 31, 33, 27], [17, -42, 30, 27], [6, -2, -17, 71]] ], ['Air', [[10, 76, 73, 0], [15, -70, 74, 0]]]] for segmentGeometry in segmentGeometries: segmentName = segmentGeometry[0] appender = vtk.vtkAppendPolyData() for sphere in segmentGeometry[1]: sphereSource = vtk.vtkSphereSource() sphereSource.SetRadius(sphere[0]) sphereSource.SetCenter(sphere[1], sphere[2], sphere[3]) appender.AddInputConnection(sphereSource.GetOutputPort()) segment = vtkSegmentationCore.vtkSegment() segment.SetName( segmentationNode.GetSegmentation().GenerateUniqueSegmentID( segmentName)) appender.Update() segment.AddRepresentation( vtkSegmentationCore.vtkSegmentationConverter. GetSegmentationClosedSurfaceRepresentationName(), appender.GetOutput()) segmentationNode.GetSegmentation().AddSegment(segment) ################################## self.delayDisplay("Create segment editor") segmentEditorWidget = slicer.qMRMLSegmentEditorWidget() segmentEditorWidget.show() segmentEditorWidget.setMRMLScene(slicer.mrmlScene) segmentEditorNode = slicer.vtkMRMLSegmentEditorNode() slicer.mrmlScene.AddNode(segmentEditorNode) segmentEditorWidget.setMRMLSegmentEditorNode(segmentEditorNode) segmentEditorWidget.setSegmentationNode(segmentationNode) segmentEditorWidget.setMasterVolumeNode(masterVolumeNode) ################################## self.delayDisplay("Run segmentation") segmentEditorWidget.setActiveEffectByName("SegmentEditorFloodFilling") effect = segmentEditorWidget.activeEffect() effect.setParameter("ObjectScaleMm", 3.0) effect.self().onApply() ################################## self.delayDisplay("Make segmentation results nicely visible in 3D") segmentationDisplayNode = segmentationNode.GetDisplayNode() segmentationDisplayNode.SetSegmentVisibility("Air", False) segmentationDisplayNode.SetSegmentOpacity3D("Background", 0.5) ################################## self.delayDisplay("Compute statistics") segStatLogic = SegmentStatisticsLogic() segStatLogic.computeStatistics(segmentationNode, masterVolumeNode) # Export results to table (just to see all results) resultsTableNode = slicer.vtkMRMLTableNode() slicer.mrmlScene.AddNode(resultsTableNode) segStatLogic.exportToTable(resultsTableNode) segStatLogic.showTable(resultsTableNode) self.delayDisplay("Check a few numerical results") self.assertEqual( round(segStatLogic.statistics["Tumor", "LM volume cc"]), 16) self.assertEqual( round(segStatLogic.statistics["Background", "LM volume cc"]), 3010) self.delayDisplay('test_SegmentEditorFloodFilling1 passed')
def run(self, inputVolume, Index): logging.info('Processing started') DosiFilmImage = inputVolume logging.info(DosiFilmImage) date = datetime.datetime.now() savepath = u"//s-grp/grp/RADIOPHY/Personnel/Aurélien Corroyer-Dulmont/3dSlicer/Field_Center_vs_Jaw_setting_TOMOTHERAPY_QC_Results/Results_" + str( date.day) + str(date.month) + str(date.year) + ".txt" logging.info(savepath) logging.info(Index) #### To get background intensity for the thershold value of the bloc # Create segmentation segmentationNode = slicer.vtkMRMLSegmentationNode() slicer.mrmlScene.AddNode(segmentationNode) segmentationNode.CreateDefaultDisplayNodes() # only needed for display segmentationNode.SetReferenceImageGeometryParameterFromVolumeNode( DosiFilmImage) # Create segment backgroundSeed = vtk.vtkSphereSource() backgroundSeed.SetCenter(-40, -30, 0) backgroundSeed.SetRadius(5) backgroundSeed.Update() segmentationNode.AddSegmentFromClosedSurfaceRepresentation( backgroundSeed.GetOutput(), "Segment A", [1.0, 0.0, 0.0]) mergedLabelmapNode = slicer.vtkMRMLLabelMapVolumeNode() slicer.mrmlScene.AddNode(mergedLabelmapNode) sa = vtk.vtkStringArray() sa.InsertNextValue("Segment A") slicer.vtkSlicerSegmentationsModuleLogic.ExportSegmentsToLabelmapNode( segmentationNode, sa, mergedLabelmapNode, DosiFilmImage) label = su.PullVolumeFromSlicer("LabelMapVolume") image = su.PullVolumeFromSlicer(DosiFilmImage) stat_filter_backgroundSeed = sitk.LabelIntensityStatisticsImageFilter() stat_filter_backgroundSeed.Execute(label, image) #attention à l'ordre meanBackground = stat_filter_backgroundSeed.GetMean(1) print(meanBackground) # Stockage du nom de la machine en utilisant le choix de l'utilisateur dans la class Widget if Index == 0: machineName = 'Tomotherapy 1' else: machineName = 'Tomotherapy 2' # Création de la segmentation segmentationNode = slicer.mrmlScene.AddNewNodeByClass( "vtkMRMLSegmentationNode") segmentationNode.CreateDefaultDisplayNodes() segmentationNode.SetReferenceImageGeometryParameterFromVolumeNode( DosiFilmImage) logging.info(segmentationNode) # Création des segments editors temporaires segmentEditorWidget = slicer.qMRMLSegmentEditorWidget() segmentEditorWidget.setMRMLScene(slicer.mrmlScene) segmentEditorNode = slicer.mrmlScene.AddNewNodeByClass( "vtkMRMLSegmentEditorNode") segmentEditorWidget.setMRMLSegmentEditorNode(segmentEditorNode) segmentEditorWidget.setSegmentationNode(segmentationNode) segmentEditorWidget.setMasterVolumeNode(DosiFilmImage) # Création d'un segment après seuillage addedSegmentID = segmentationNode.GetSegmentation().AddEmptySegment( "IrradiatedBlocks") segmentEditorNode.SetSelectedSegmentID(addedSegmentID) segmentEditorWidget.setActiveEffectByName("Threshold") effect = segmentEditorWidget.activeEffect() #effect.setParameter("MinimumThreshold",str(22000)) #effect.setParameter("MaximumThreshold",str(55000)) effect.setParameter("MinimumThreshold", str(meanBackground / 5)) effect.setParameter("MaximumThreshold", str(meanBackground / 1.2)) effect.self().onApply() # Passage en mode closed surface pour calcul des centres n = slicer.util.getNode('Segmentation_1') s = n.GetSegmentation() ss = s.GetSegment('IrradiatedBlocks') ss.AddRepresentation('Closed surface', vtk.vtkPolyData()) # Division du segment en plusieurs segments (un par bloc d'irradiation) segmentEditorWidget.setActiveEffectByName("Islands") effect = segmentEditorWidget.activeEffect() effect.setParameter("Operation", str("SPLIT_ISLANDS_TO_SEGMENTS")) effect.setParameter("MinimumSize", 1000) effect.self().onApply() ######### Initialisation des variables fixes d'intérêt########### Segmentation_Name = 'Segmentation_1' Segment_Name = [ "IrradiatedBlocks", "IrradiatedBlocks -_1", "IrradiatedBlocks -_2", "IrradiatedBlocks -_3", "IrradiatedBlocks -_4", "IrradiatedBlocks -_5", "IrradiatedBlocks -_6" ] ListYaxisCenterOfBlock = [ 0, 0, 0, 0, 0, 0, 0 ] # initialisation de la liste contenant les valeurs Y centrales des blocs # Boucle de calcul des centres pour les 7 blocs (segment) i = 0 while i < len(Segment_Name): n = slicer.util.getNode(Segmentation_Name) s = n.GetSegmentation() ss = s.GetSegment(Segment_Name[i]) pd = ss.GetRepresentation('Closed surface') com = vtk.vtkCenterOfMass() com.SetInputData(pd) com.Update() com.GetCenter() # A voir mais je pense que cette ligne est inutile CenterOfBlock = com.GetCenter( ) # CenterOfBlock est alors un tuple avec plusieurs variables (coordonées x,y,z) YaxisCenterOfBlock = ( CenterOfBlock[1] ) # Sélection de la 2ème valeur du tuple (indice 1) qui est la valeur dans l'axe Y qui est l'unique valeure d'intérêt YaxisCenterOfBlock = abs( YaxisCenterOfBlock) # On passe en valeur absolue ListYaxisCenterOfBlock[i] = YaxisCenterOfBlock i += 1 logging.info(ListYaxisCenterOfBlock) ######### Calcul de la différence en Y entre les centres des différents blocs########### MaxYaxisCenter = max(ListYaxisCenterOfBlock) MinYaxisCenter = min(ListYaxisCenterOfBlock) DifferenceMaxInPixelYCenters = MaxYaxisCenter - MinYaxisCenter DifferenceMaxInMmYCenters = float(DifferenceMaxInPixelYCenters) DifferenceMaxInMmYCenters = DifferenceMaxInMmYCenters * 0.3528 # Pas élégant mais si je ne fais pas ça, il initialise DifferenceMaxInMmYCenters en tuple et pas en variable... ### Enonciation des résultats ### logging.info("Coordonnee Max en Y : " + str(MaxYaxisCenter)) logging.info("Coordonnee Min en Y : " + str(MinYaxisCenter)) logging.info("Difference maximale entre les blocs (en pixel) : " + str(DifferenceMaxInPixelYCenters)) logging.info("Difference maximale entre les blocs (en mm) : " + str(DifferenceMaxInMmYCenters)) ######### Création et remplissage fichier text pour stocker les résultats########### file = open(savepath, 'w') ### encodage du fichier pour écriture incluant les "é" ### file = codecs.open(savepath, encoding='utf-8') txt = file.read() file = codecs.open(savepath, "w", encoding='mbcs') date = datetime.datetime.now() file.write(u"Résultats test -Field Center vs Jaw setting-") file.write("\n\n") file.write("Machine : " + str(machineName)) file.write("\n\n") file.write("Date : " + str(date.day) + "/" + str(date.month) + "/" + str(date.year)) file.write("\n\n") file.write("\n\n") i = 0 for i in range( len(ListYaxisCenterOfBlock) ): # Boucle pour obtenir les coordonées Y des centres des 7 blocs file.write(u"Coordonnée Y du centre du bloc n°" + str(i + 1) + ": ") file.write(str(ListYaxisCenterOfBlock[i])) file.write("\n\n") file.write("\n\n") file.write(u"Coordonnée Max en Y : " + str(MaxYaxisCenter)) file.write("\n\n") file.write(u"Coordonnée Min en Y : " + str(MinYaxisCenter)) file.write("\n\n") file.write(u"Différence maximale entre les blocs (en pixel) : " + str(DifferenceMaxInPixelYCenters)) file.write("\n\n") file.write(u"Différence maximale entre les blocs (en mm) : " + str(DifferenceMaxInMmYCenters)) ######### Calcul de la conformité et mention dans le fichier résultats########### if 0 <= DifferenceMaxInMmYCenters < 0.5: Result = "Conforme" elif DifferenceMaxInMmYCenters > 0.5: Result = "Hors tolerance" else: Result = "Limite" #car si pas < ou > à 0.5 alors = à 0.5 if DifferenceMaxInMmYCenters < 0: logging.info( u"Valeur de la différence négative, problème dans l'image ou dans le programme, contactez Aurélien Corroyer-Dulmont tel : 5768" ) logging.info(Result) file.write("\n\n") file.write("\n\n") file.write(u"Résultat : " + str(Result)) file.close() logging.info('Processing completed') logging.info('\n\nResults are in the following file : ' + savepath) return True
def TestSection_2_qMRMLSegmentationGeometryWidget(self): logging.info('Test section 2: qMRMLSegmentationGeometryWidget') import vtkSegmentationCore binaryLabelmapReprName = vtkSegmentationCore.vtkSegmentationConverter.GetBinaryLabelmapRepresentationName() closedSurfaceReprName = vtkSegmentationCore.vtkSegmentationConverter.GetClosedSurfaceRepresentationName() # Use MRHead and Tinypatient for testing import SampleData sampleDataLogic = SampleData.SampleDataLogic() mrVolumeNode = sampleDataLogic.downloadMRHead() [tinyVolumeNode, tinySegmentationNode] = sampleDataLogic.downloadSample('TinyPatient') # Convert MRHead to oriented image data import vtkSlicerSegmentationsModuleLogicPython as vtkSlicerSegmentationsModuleLogic mrOrientedImageData = vtkSlicerSegmentationsModuleLogic.vtkSlicerSegmentationsModuleLogic.CreateOrientedImageDataFromVolumeNode(mrVolumeNode) mrOrientedImageData.UnRegister(None) # Create segmentation node with binary labelmap master and one segment with MRHead geometry segmentationNode = slicer.vtkMRMLSegmentationNode() segmentationNode.GetSegmentation().SetMasterRepresentationName(binaryLabelmapReprName) geometryStr = vtkSegmentationCore.vtkSegmentationConverter.SerializeImageGeometry(mrOrientedImageData) segmentationNode.GetSegmentation().SetConversionParameter( vtkSegmentationCore.vtkSegmentationConverter.GetReferenceImageGeometryParameterName(), geometryStr) slicer.mrmlScene.AddNode(segmentationNode) threshold = vtk.vtkImageThreshold() threshold.SetInputData(mrOrientedImageData) threshold.ThresholdByUpper(16.0) threshold.SetInValue(1) threshold.SetOutValue(0) threshold.SetOutputScalarType(vtk.VTK_UNSIGNED_CHAR) threshold.Update() segmentOrientedImageData = vtkSegmentationCore.vtkOrientedImageData() segmentOrientedImageData.DeepCopy(threshold.GetOutput()) mrImageToWorldMatrix = vtk.vtkMatrix4x4() mrOrientedImageData.GetImageToWorldMatrix(mrImageToWorldMatrix) segmentOrientedImageData.SetImageToWorldMatrix(mrImageToWorldMatrix) segment = vtkSegmentationCore.vtkSegment() segment.SetName('Brain') segment.SetColor(0.0,0.0,1.0) segment.AddRepresentation(binaryLabelmapReprName, segmentOrientedImageData) segmentationNode.GetSegmentation().AddSegment(segment) # Create geometry widget geometryWidget = slicer.qMRMLSegmentationGeometryWidget() geometryWidget.setSegmentationNode(segmentationNode) geometryWidget.editEnabled = True geometryImageData = vtkSegmentationCore.vtkOrientedImageData() # To contain the output later # Volume source with no transforms geometryWidget.setSourceNode(tinyVolumeNode) geometryWidget.geometryImageData(geometryImageData) self.assertTrue(self.compareOutputGeometry(geometryImageData, (49,49,23), (248.8439, 248.2890, -123.75), [[-1.0, 0.0, 0.0], [0.0, -1.0, 0.0], [0.0, 0.0, 1.0]])) vtkSegmentationCore.vtkOrientedImageDataResample.ResampleOrientedImageToReferenceOrientedImage( segmentOrientedImageData, geometryImageData, geometryImageData, False, True) self.assertEqual(self.getForegroundVoxelCount(geometryImageData), 92) # Transformed volume source translationTransformMatrix = vtk.vtkMatrix4x4() translationTransformMatrix.SetElement(0,3,24.5) translationTransformMatrix.SetElement(1,3,24.5) translationTransformMatrix.SetElement(2,3,11.5) translationTransformNode = slicer.vtkMRMLLinearTransformNode() translationTransformNode.SetName('TestTranslation') slicer.mrmlScene.AddNode(translationTransformNode) translationTransformNode.SetMatrixTransformToParent(translationTransformMatrix) tinyVolumeNode.SetAndObserveTransformNodeID(translationTransformNode.GetID()) geometryWidget.geometryImageData(geometryImageData) self.assertTrue(self.compareOutputGeometry(geometryImageData, (49,49,23), (224.3439, 223.7890, -135.25), [[-1.0, 0.0, 0.0], [0.0, -1.0, 0.0], [0.0, 0.0, 1.0]])) vtkSegmentationCore.vtkOrientedImageDataResample.ResampleOrientedImageToReferenceOrientedImage( segmentOrientedImageData, geometryImageData, geometryImageData, False, True) self.assertEqual(self.getForegroundVoxelCount(geometryImageData), 94) # Volume source with isotropic spacing tinyVolumeNode.SetAndObserveTransformNodeID(None) geometryWidget.setIsotropicSpacing(True) geometryWidget.geometryImageData(geometryImageData) self.assertTrue(self.compareOutputGeometry(geometryImageData, (23,23,23), (248.8439, 248.2890, -123.75), [[-1.0, 0.0, 0.0], [0.0, -1.0, 0.0], [0.0, 0.0, 1.0]])) vtkSegmentationCore.vtkOrientedImageDataResample.ResampleOrientedImageToReferenceOrientedImage( segmentOrientedImageData, geometryImageData, geometryImageData, False, True) self.assertEqual(self.getForegroundVoxelCount(geometryImageData), 414) # Volume source with oversampling geometryWidget.setIsotropicSpacing(False) geometryWidget.setOversamplingFactor(2.0) geometryWidget.geometryImageData(geometryImageData) self.assertTrue(self.compareOutputGeometry(geometryImageData, (24.5, 24.5, 11.5), (261.0939, 260.5390, -129.5), [[-1.0, 0.0, 0.0], [0.0, -1.0, 0.0], [0.0, 0.0, 1.0]])) vtkSegmentationCore.vtkOrientedImageDataResample.ResampleOrientedImageToReferenceOrientedImage( segmentOrientedImageData, geometryImageData, geometryImageData, False, True) self.assertEqual(self.getForegroundVoxelCount(geometryImageData), 751) slicer.util.delayDisplay('Volume source cases - OK') # Segmentation source with binary labelmap master geometryWidget.setOversamplingFactor(1.0) geometryWidget.setSourceNode(tinySegmentationNode) geometryWidget.geometryImageData(geometryImageData) self.assertTrue(self.compareOutputGeometry(geometryImageData, (49,49,23), (248.8439, 248.2890, -123.75), [[-1.0, 0.0, 0.0], [0.0, -1.0, 0.0], [0.0, 0.0, 1.0]])) vtkSegmentationCore.vtkOrientedImageDataResample.ResampleOrientedImageToReferenceOrientedImage( segmentOrientedImageData, geometryImageData, geometryImageData, False, True) self.assertEqual(self.getForegroundVoxelCount(geometryImageData), 92) # Segmentation source with closed surface master tinySegmentationNode.GetSegmentation().SetConversionParameter('Smoothing factor', '0.0') self.assertTrue(tinySegmentationNode.GetSegmentation().CreateRepresentation(closedSurfaceReprName)) tinySegmentationNode.GetSegmentation().SetMasterRepresentationName(closedSurfaceReprName) tinySegmentationNode.Modified() # Trigger re-calculation of geometry (only generic Modified event is observed) geometryWidget.geometryImageData(geometryImageData) self.assertTrue(self.compareOutputGeometry(geometryImageData, (1,1,1), (-167.156, -217.711, -135.75), [[0.0, 0.0, 1.0], [-1.0, 0.0, 0.0], [0.0, -1.0, 0.0]])) vtkSegmentationCore.vtkOrientedImageDataResample.ResampleOrientedImageToReferenceOrientedImage( segmentOrientedImageData, geometryImageData, geometryImageData, False, True) self.assertEqual(self.getForegroundVoxelCount(geometryImageData), 5223846) slicer.util.delayDisplay('Segmentation source cases - OK') # Model source with no transform outputModelHierarchy = slicer.vtkMRMLModelHierarchyNode() slicer.mrmlScene.AddNode(outputModelHierarchy) success = vtkSlicerSegmentationsModuleLogic.vtkSlicerSegmentationsModuleLogic.ExportVisibleSegmentsToModelHierarchy( tinySegmentationNode, outputModelHierarchy ) self.assertTrue(success) modelNode = slicer.util.getNode('Body_Contour') geometryWidget.setSourceNode(modelNode) geometryWidget.geometryImageData(geometryImageData) self.assertTrue(self.compareOutputGeometry(geometryImageData, (1,1,1), (-167.156, -217.711, -135.75), [[0.0, 0.0, 1.0], [-1.0, 0.0, 0.0], [0.0, -1.0, 0.0]])) vtkSegmentationCore.vtkOrientedImageDataResample.ResampleOrientedImageToReferenceOrientedImage( segmentOrientedImageData, geometryImageData, geometryImageData, False, True) self.assertEqual(self.getForegroundVoxelCount(geometryImageData), 5223846) # Transformed model source rotationTransform = vtk.vtkTransform() rotationTransform.RotateX(45) rotationTransformMatrix = vtk.vtkMatrix4x4() rotationTransform.GetMatrix(rotationTransformMatrix) rotationTransformNode = slicer.vtkMRMLLinearTransformNode() rotationTransformNode.SetName('TestRotation') slicer.mrmlScene.AddNode(rotationTransformNode) rotationTransformNode.SetMatrixTransformToParent(rotationTransformMatrix) modelNode.SetAndObserveTransformNodeID(rotationTransformNode.GetID()) modelNode.Modified() geometryWidget.geometryImageData(geometryImageData) self.assertTrue(self.compareOutputGeometry(geometryImageData, (1,1,1), (-167.156, -58.6623, -249.228), [[0.0, 0.0, 1.0], [-0.7071, -0.7071, 0.0], [0.7071, -0.7071, 0.0]])) vtkSegmentationCore.vtkOrientedImageDataResample.ResampleOrientedImageToReferenceOrientedImage( segmentOrientedImageData, geometryImageData, geometryImageData, False, True) self.assertEqual(self.getForegroundVoxelCount(geometryImageData), 5221241) # ROI source roiNode = slicer.vtkMRMLAnnotationROINode() roiNode.SetName('SourceROI') slicer.mrmlScene.AddNode(roiNode) roiNode.UnRegister(None) xyz = [0]*3 center = [0]*3 slicer.vtkMRMLSliceLogic.GetVolumeRASBox(tinyVolumeNode, xyz, center) radius = map(lambda x: x/2.0, xyz) roiNode.SetXYZ(center) roiNode.SetRadiusXYZ(radius) geometryWidget.setSourceNode(roiNode) geometryWidget.geometryImageData(geometryImageData) self.assertTrue(self.compareOutputGeometry(geometryImageData, (1,1,1), (-216.156, -217.711, -135.75), [[0.0, 0.0, 1.0], [-1.0, 0.0, 0.0], [0.0, -1.0, 0.0]])) vtkSegmentationCore.vtkOrientedImageDataResample.ResampleOrientedImageToReferenceOrientedImage( segmentOrientedImageData, geometryImageData, geometryImageData, False, True) self.assertEqual(self.getForegroundVoxelCount(geometryImageData), 5223846) slicer.util.delayDisplay('Model and ROI source cases - OK') slicer.util.delayDisplay('Segmentation geometry widget test passed')
def TestSection_3_ImportExportSegment(self): # Import/export, both one label and all labels logging.info('Test section 3: Import/export segment') # Export single segment to model node bodyModelNode = slicer.vtkMRMLModelNode() bodyModelNode.SetName('BodyModel') slicer.mrmlScene.AddNode(bodyModelNode) bodySegment = self.inputSegmentationNode.GetSegmentation().GetSegment( 'Body_Contour') result = slicer.vtkSlicerSegmentationsModuleLogic.ExportSegmentToRepresentationNode( bodySegment, bodyModelNode) self.assertTrue(result) self.assertIsNotNone(bodyModelNode.GetPolyData()) #TODO: Number of points increased to 1677 due to end-capping, need to investigate! #self.assertEqual(bodyModelNode.GetPolyData().GetNumberOfPoints(), 302) #TODO: On Linux and Windows it is 588, on Mac it is 580. Need to investigate # self.assertEqual(bodyModelNode.GetPolyData().GetNumberOfCells(), 588) #self.assertTrue(bodyModelNode.GetPolyData().GetNumberOfCells() == 588 or bodyModelNode.GetPolyData().GetNumberOfCells() == 580) # Export single segment to volume node bodyLabelmapNode = slicer.vtkMRMLLabelMapVolumeNode() bodyLabelmapNode.SetName('BodyLabelmap') slicer.mrmlScene.AddNode(bodyLabelmapNode) result = slicer.vtkSlicerSegmentationsModuleLogic.ExportSegmentToRepresentationNode( bodySegment, bodyLabelmapNode) self.assertTrue(result) bodyImageData = bodyLabelmapNode.GetImageData() self.assertIsNotNone(bodyImageData) imageStat = vtk.vtkImageAccumulate() imageStat.SetInputData(bodyImageData) imageStat.Update() self.assertEqual(imageStat.GetVoxelCount(), 792) self.assertEqual(imageStat.GetMin()[0], 0) self.assertEqual(imageStat.GetMax()[0], 1) # Export multiple segments to volume node allSegmentsLabelmapNode = slicer.vtkMRMLLabelMapVolumeNode() allSegmentsLabelmapNode.SetName('AllSegmentsLabelmap') slicer.mrmlScene.AddNode(allSegmentsLabelmapNode) result = slicer.vtkSlicerSegmentationsModuleLogic.ExportAllSegmentsToLabelmapNode( self.inputSegmentationNode, allSegmentsLabelmapNode) self.assertTrue(result) allSegmentsImageData = allSegmentsLabelmapNode.GetImageData() self.assertIsNotNone(allSegmentsImageData) imageStat = vtk.vtkImageAccumulate() imageStat.SetInputData(allSegmentsImageData) imageStat.SetComponentExtent(0, 5, 0, 0, 0, 0) imageStat.SetComponentOrigin(0, 0, 0) imageStat.SetComponentSpacing(1, 1, 1) imageStat.Update() self.assertEqual(imageStat.GetVoxelCount(), 24198552) imageStatResult = imageStat.GetOutput() self.assertEqual( imageStatResult.GetScalarComponentAsDouble(0, 0, 0, 0), 12900275) self.assertEqual( imageStatResult.GetScalarComponentAsDouble(1, 0, 0, 0), 10601312) self.assertEqual( imageStatResult.GetScalarComponentAsDouble(2, 0, 0, 0), 251476) self.assertEqual( imageStatResult.GetScalarComponentAsDouble(3, 0, 0, 0), 445489) # Import model to segment modelImportSegmentationNode = slicer.vtkMRMLSegmentationNode() modelImportSegmentationNode.SetName('ModelImport') modelImportSegmentationNode.GetSegmentation( ).SetMasterRepresentationName(self.closedSurfaceReprName) slicer.mrmlScene.AddNode(modelImportSegmentationNode) modelSegment = slicer.vtkSlicerSegmentationsModuleLogic.CreateSegmentFromModelNode( bodyModelNode) modelSegment.UnRegister(None) # Need to release ownership self.assertIsNotNone(modelSegment) self.assertIsNotNone( modelSegment.GetRepresentation(self.closedSurfaceReprName)) # Import multi-label labelmap to segmentation multiLabelImportSegmentationNode = slicer.vtkMRMLSegmentationNode() multiLabelImportSegmentationNode.SetName('MultiLabelImport') multiLabelImportSegmentationNode.GetSegmentation( ).SetMasterRepresentationName(self.binaryLabelmapReprName) slicer.mrmlScene.AddNode(multiLabelImportSegmentationNode) result = slicer.vtkSlicerSegmentationsModuleLogic.ImportLabelmapToSegmentationNode( allSegmentsLabelmapNode, multiLabelImportSegmentationNode) self.assertTrue(result) self.assertEqual( multiLabelImportSegmentationNode.GetSegmentation(). GetNumberOfSegments(), 3) # Import labelmap into single segment singleLabelImportSegmentationNode = slicer.vtkMRMLSegmentationNode() singleLabelImportSegmentationNode.SetName('SingleLabelImport') singleLabelImportSegmentationNode.GetSegmentation( ).SetMasterRepresentationName(self.binaryLabelmapReprName) slicer.mrmlScene.AddNode(singleLabelImportSegmentationNode) # Should not import multi-label labelmap to segment nullSegment = slicer.vtkSlicerSegmentationsModuleLogic.CreateSegmentFromLabelmapVolumeNode( allSegmentsLabelmapNode) self.assertIsNone(nullSegment) logging.info( '(This error message tests an impossible scenario, it is supposed to appear)' ) # Make labelmap single-label and import again threshold = vtk.vtkImageThreshold() threshold.SetInValue(0) threshold.SetOutValue(1) threshold.ReplaceInOn() threshold.ThresholdByLower(0) threshold.SetOutputScalarType(vtk.VTK_UNSIGNED_CHAR) if vtk.VTK_MAJOR_VERSION <= 5: threshold.SetInput(allSegmentsLabelmapNode.GetImageData()) else: threshold.SetInputData(allSegmentsLabelmapNode.GetImageData()) threshold.Update() allSegmentsLabelmapNode.GetImageData().ShallowCopy( threshold.GetOutput()) labelSegment = slicer.vtkSlicerSegmentationsModuleLogic.CreateSegmentFromLabelmapVolumeNode( allSegmentsLabelmapNode) labelSegment.UnRegister(None) # Need to release ownership self.assertIsNotNone(labelSegment) self.assertIsNotNone( labelSegment.GetRepresentation(self.binaryLabelmapReprName)) # Import/export with transforms logging.info('Test section 4/2: Import/export with transforms') # Create transform node that will be used to transform the tested nodes bodyModelTransformNode = slicer.vtkMRMLLinearTransformNode() slicer.mrmlScene.AddNode(bodyModelTransformNode) bodyModelTransform = vtk.vtkTransform() bodyModelTransform.Translate(1000.0, 0.0, 0.0) bodyModelTransformNode.ApplyTransformMatrix( bodyModelTransform.GetMatrix()) # Set transform as parent to input segmentation node self.inputSegmentationNode.SetAndObserveTransformNodeID( bodyModelTransformNode.GetID()) # Export single segment to model node from transformed segmentation bodyModelNodeTransformed = slicer.vtkMRMLModelNode() bodyModelNodeTransformed.SetName('BodyModelTransformed') slicer.mrmlScene.AddNode(bodyModelNodeTransformed) bodySegment = self.inputSegmentationNode.GetSegmentation().GetSegment( 'Body_Contour') result = slicer.vtkSlicerSegmentationsModuleLogic.ExportSegmentToRepresentationNode( bodySegment, bodyModelNodeTransformed) self.assertTrue(result) self.assertIsNotNone(bodyModelNodeTransformed.GetParentTransformNode()) # Export single segment to volume node from transformed segmentation bodyLabelmapNodeTransformed = slicer.vtkMRMLLabelMapVolumeNode() bodyLabelmapNodeTransformed.SetName('BodyLabelmapTransformed') slicer.mrmlScene.AddNode(bodyLabelmapNodeTransformed) result = slicer.vtkSlicerSegmentationsModuleLogic.ExportSegmentToRepresentationNode( bodySegment, bodyLabelmapNodeTransformed) self.assertTrue(result) self.assertIsNotNone( bodyLabelmapNodeTransformed.GetParentTransformNode()) # Create transform node that will be used to transform the tested nodes modelTransformedImportSegmentationTransformNode = slicer.vtkMRMLLinearTransformNode( ) slicer.mrmlScene.AddNode( modelTransformedImportSegmentationTransformNode) modelTransformedImportSegmentationTransform = vtk.vtkTransform() modelTransformedImportSegmentationTransform.Translate(-500.0, 0.0, 0.0) modelTransformedImportSegmentationTransformNode.ApplyTransformMatrix( modelTransformedImportSegmentationTransform.GetMatrix()) # Import transformed model to segment in transformed segmentation modelTransformedImportSegmentationNode = slicer.vtkMRMLSegmentationNode( ) modelTransformedImportSegmentationNode.SetName( 'ModelImportTransformed') modelTransformedImportSegmentationNode.GetSegmentation( ).SetMasterRepresentationName(self.closedSurfaceReprName) slicer.mrmlScene.AddNode(modelTransformedImportSegmentationNode) modelTransformedImportSegmentationNode.SetAndObserveTransformNodeID( modelTransformedImportSegmentationTransformNode.GetID()) modelSegmentTranformed = slicer.vtkSlicerSegmentationsModuleLogic.CreateSegmentFromModelNode( bodyModelNodeTransformed, modelTransformedImportSegmentationNode) modelSegmentTranformed.UnRegister(None) # Need to release ownership self.assertIsNotNone(modelSegmentTranformed) modelSegmentTransformedPolyData = modelSegmentTranformed.GetRepresentation( self.closedSurfaceReprName) self.assertIsNotNone(modelSegmentTransformedPolyData) self.assertEqual(int(modelSegmentTransformedPolyData.GetBounds()[0]), 1332) self.assertEqual(int(modelSegmentTransformedPolyData.GetBounds()[1]), 1675) # Clean up temporary nodes slicer.mrmlScene.RemoveNode(bodyModelNode) slicer.mrmlScene.RemoveNode(bodyLabelmapNode) slicer.mrmlScene.RemoveNode(allSegmentsLabelmapNode) slicer.mrmlScene.RemoveNode(modelImportSegmentationNode) slicer.mrmlScene.RemoveNode(multiLabelImportSegmentationNode) slicer.mrmlScene.RemoveNode(singleLabelImportSegmentationNode) slicer.mrmlScene.RemoveNode(bodyModelTransformNode) slicer.mrmlScene.RemoveNode(bodyModelNodeTransformed) slicer.mrmlScene.RemoveNode(bodyLabelmapNodeTransformed) slicer.mrmlScene.RemoveNode(modelTransformedImportSegmentationNode)
def test_TemplateKey1(self): """ Basic automated test of the segmentation method: - Create segmentation by placing sphere-shaped seeds - Run segmentation - Verify results using segment statistics The test can be executed from SelfTests module (test name: SegmentEditorTemplateKey) """ self.delayDisplay("Starting test_TemplateKey1") import vtkSegmentationCorePython as vtkSegmentationCore import vtkSlicerSegmentationsModuleLogicPython as vtkSlicerSegmentationsModuleLogic import SampleData from SegmentStatistics import SegmentStatisticsLogic ################################## self.delayDisplay("Load master volume") import SampleData sampleDataLogic = SampleData.SampleDataLogic() masterVolumeNode = sampleDataLogic.downloadMRBrainTumor1() ################################## self.delayDisplay("Create segmentation containing a few spheres") segmentationNode = slicer.vtkMRMLSegmentationNode() slicer.mrmlScene.AddNode(segmentationNode) segmentationNode.CreateDefaultDisplayNodes() segmentationNode.SetReferenceImageGeometryParameterFromVolumeNode(masterVolumeNode) # Segments are defined by a list of: name and a list of sphere [radius, posX, posY, posZ] segmentGeometries = [ ['Tumor', [[10, -6,30,28]]], ['Background', [[10, 0,65,22], [15, 1, -14, 30], [12, 0, 28, -7], [5, 0,30,54], [12, 31, 33, 27], [17, -42, 30, 27], [6, -2,-17,71]]], ['Air', [[10, 76,73,0], [15, -70,74,0]]] ] for segmentGeometry in segmentGeometries: segmentName = segmentGeometry[0] appender = vtk.vtkAppendPolyData() for sphere in segmentGeometry[1]: sphereSource = vtk.vtkSphereSource() sphereSource.SetRadius(sphere[0]) sphereSource.SetCenter(sphere[1], sphere[2], sphere[3]) appender.AddInputConnection(sphereSource.GetOutputPort()) segment = vtkSegmentationCore.vtkSegment() segment.SetName(segmentationNode.GetSegmentation().GenerateUniqueSegmentID(segmentName)) appender.Update() segment.AddRepresentation(vtkSegmentationCore.vtkSegmentationConverter.GetSegmentationClosedSurfaceRepresentationName(), appender.GetOutput()) segmentationNode.GetSegmentation().AddSegment(segment) ################################## self.delayDisplay("Create segment editor") segmentEditorWidget = slicer.qMRMLSegmentEditorWidget() segmentEditorWidget.show() segmentEditorWidget.setMRMLScene(slicer.mrmlScene) segmentEditorNode = slicer.vtkMRMLSegmentEditorNode() slicer.mrmlScene.AddNode(segmentEditorNode) segmentEditorWidget.setMRMLSegmentEditorNode(segmentEditorNode) segmentEditorWidget.setSegmentationNode(segmentationNode) segmentEditorWidget.setMasterVolumeNode(masterVolumeNode) ################################## self.delayDisplay("Run segmentation") segmentEditorWidget.setActiveEffectByName("TemplateKey") effect = segmentEditorWidget.activeEffect() effect.setParameter("ObjectScaleMm", 3.0) effect.self().onApply() ################################## self.delayDisplay("Make segmentation results nicely visible in 3D") segmentationDisplayNode = segmentationNode.GetDisplayNode() segmentationDisplayNode.SetSegmentVisibility("Air", False) segmentationDisplayNode.SetSegmentOpacity3D("Background",0.5) ################################## self.delayDisplay("Compute statistics") segStatLogic = SegmentStatisticsLogic() segStatLogic.computeStatistics(segmentationNode, masterVolumeNode) # Export results to table (just to see all results) resultsTableNode = slicer.vtkMRMLTableNode() slicer.mrmlScene.AddNode(resultsTableNode) segStatLogic.exportToTable(resultsTableNode) segStatLogic.showTable(resultsTableNode) self.delayDisplay("Check a few numerical results") self.assertEqual( round(segStatLogic.statistics["Tumor","LM volume cc"]), 16) self.assertEqual( round(segStatLogic.statistics["Background","LM volume cc"]), 3010) self.delayDisplay('test_TemplateKey1 passed')
def TestSection_2_MergeLabelmapWithDifferentGeometries(self): # Merge labelmap when segments containing labelmaps with different geometries (both same directions, different directions) logging.info( 'Test section 2: Merge labelmap with different geometries') self.assertIsNotNone(self.sphereSegment) self.sphereSegment.RemoveRepresentation(self.binaryLabelmapReprName) self.assertIsNone( self.sphereSegment.GetRepresentation(self.binaryLabelmapReprName)) # Create new segmentation with sphere segment self.secondSegmentationNode = slicer.vtkMRMLSegmentationNode() self.secondSegmentationNode.SetName('Second') self.secondSegmentationNode.GetSegmentation( ).SetMasterRepresentationName(self.binaryLabelmapReprName) slicer.mrmlScene.AddNode(self.secondSegmentationNode) self.secondSegmentationNode.GetSegmentation().AddSegment( self.sphereSegment) # Check automatically converted labelmap. It is supposed to have the default geometry # (which is different than the one in the input segmentation) sphereLabelmap = self.sphereSegment.GetRepresentation( self.binaryLabelmapReprName) self.assertIsNotNone(sphereLabelmap) sphereLabelmapSpacing = sphereLabelmap.GetSpacing() self.assertTrue(sphereLabelmapSpacing[0] == 1.0 and sphereLabelmapSpacing[1] == 1.0 and sphereLabelmapSpacing[2] == 1.0) # Create binary labelmap in segmentation that will create the merged labelmap from # different geometries so that labelmap is not removed from sphere segment when adding self.inputSegmentationNode.GetSegmentation().CreateRepresentation( self.binaryLabelmapReprName) # Copy segment to input segmentation self.inputSegmentationNode.GetSegmentation( ).CopySegmentFromSegmentation( self.secondSegmentationNode.GetSegmentation(), self.sphereSegmentName) self.assertEqual( self.inputSegmentationNode.GetSegmentation().GetNumberOfSegments(), 3) # Check merged labelmap # Reference geometry has the tiny patient spacing, and it is oversampled to have smimilar # voxel size as the sphere labelmap with the uniform 1mm spacing mergedLabelmap = vtkSegmentationCore.vtkOrientedImageData() self.inputSegmentationNode.GenerateMergedLabelmapForAllSegments( mergedLabelmap, 0) mergedLabelmapSpacing = mergedLabelmap.GetSpacing() self.assertAlmostEqual(mergedLabelmapSpacing[0], 1.2894736842, 8) self.assertAlmostEqual(mergedLabelmapSpacing[1], 1.2894736842, 8) self.assertAlmostEqual(mergedLabelmapSpacing[2], 0.6052631578, 8) imageStat = vtk.vtkImageAccumulate() imageStat.SetInputData(mergedLabelmap) imageStat.SetComponentExtent(0, 5, 0, 0, 0, 0) imageStat.SetComponentOrigin(0, 0, 0) imageStat.SetComponentSpacing(1, 1, 1) imageStat.Update() self.assertEqual(imageStat.GetVoxelCount(), 54872000) imageStatResult = imageStat.GetOutput() for i in range(5): logging.info("Volume {0}: {1}".format( i, imageStatResult.GetScalarComponentAsDouble(i, 0, 0, 0))) self.assertEqual( imageStatResult.GetScalarComponentAsDouble(0, 0, 0, 0), 43573723) self.assertEqual( imageStatResult.GetScalarComponentAsDouble(1, 0, 0, 0), 10601312) self.assertEqual( imageStatResult.GetScalarComponentAsDouble(2, 0, 0, 0), 251476) self.assertEqual( imageStatResult.GetScalarComponentAsDouble(3, 0, 0, 0), 445489) self.assertEqual( imageStatResult.GetScalarComponentAsDouble(4, 0, 0, 0), 0 ) # Built from color table and color four is removed in previous test section
def TestSection_3_ImportExportSegment(self): # Import/export, both one label and all labels logging.info('Test section 3: Import/export segment') # Export single segment to model node bodyModelNode = slicer.vtkMRMLModelNode() bodyModelNode.SetName('BodyModel') slicer.mrmlScene.AddNode(bodyModelNode) bodySegment = self.inputSegmentationNode.GetSegmentation().GetSegment('Body_Contour') result = slicer.vtkSlicerSegmentationsModuleLogic.ExportSegmentToRepresentationNode(bodySegment, bodyModelNode) self.assertTrue(result) self.assertIsNotNone(bodyModelNode.GetPolyData()) #TODO: Number of points increased to 1677 due to end-capping, need to investigate! #self.assertEqual(bodyModelNode.GetPolyData().GetNumberOfPoints(), 302) #TODO: On Linux and Windows it is 588, on Mac it is 580. Need to investigate # self.assertEqual(bodyModelNode.GetPolyData().GetNumberOfCells(), 588) #self.assertTrue(bodyModelNode.GetPolyData().GetNumberOfCells() == 588 or bodyModelNode.GetPolyData().GetNumberOfCells() == 580) # Export single segment to volume node bodyLabelmapNode = slicer.vtkMRMLLabelMapVolumeNode() bodyLabelmapNode.SetName('BodyLabelmap') slicer.mrmlScene.AddNode(bodyLabelmapNode) result = slicer.vtkSlicerSegmentationsModuleLogic.ExportSegmentToRepresentationNode(bodySegment, bodyLabelmapNode) self.assertTrue(result) bodyImageData = bodyLabelmapNode.GetImageData() self.assertIsNotNone(bodyImageData) imageStat = vtk.vtkImageAccumulate() imageStat.SetInputData(bodyImageData) imageStat.Update() self.assertEqual(imageStat.GetVoxelCount(), 792) self.assertEqual(imageStat.GetMin()[0], 0) self.assertEqual(imageStat.GetMax()[0], 1) # Export multiple segments to volume node allSegmentsLabelmapNode = slicer.vtkMRMLLabelMapVolumeNode() allSegmentsLabelmapNode.SetName('AllSegmentsLabelmap') slicer.mrmlScene.AddNode(allSegmentsLabelmapNode) result = slicer.vtkSlicerSegmentationsModuleLogic.ExportAllSegmentsToLabelmapNode(self.inputSegmentationNode, allSegmentsLabelmapNode) self.assertTrue(result) allSegmentsImageData = allSegmentsLabelmapNode.GetImageData() self.assertIsNotNone(allSegmentsImageData) imageStat = vtk.vtkImageAccumulate() imageStat.SetInputData(allSegmentsImageData) imageStat.SetComponentExtent(0,5,0,0,0,0) imageStat.SetComponentOrigin(0,0,0) imageStat.SetComponentSpacing(1,1,1) imageStat.Update() self.assertEqual(imageStat.GetVoxelCount(), 24198552) imageStatResult = imageStat.GetOutput() self.assertEqual(imageStatResult.GetScalarComponentAsDouble(0,0,0,0), 12900275) self.assertEqual(imageStatResult.GetScalarComponentAsDouble(1,0,0,0), 10601312) self.assertEqual(imageStatResult.GetScalarComponentAsDouble(2,0,0,0), 251476) self.assertEqual(imageStatResult.GetScalarComponentAsDouble(3,0,0,0), 445489) # Import model to segment modelImportSegmentationNode = slicer.vtkMRMLSegmentationNode() modelImportSegmentationNode.SetName('ModelImport') modelImportSegmentationNode.GetSegmentation().SetMasterRepresentationName(self.closedSurfaceReprName) slicer.mrmlScene.AddNode(modelImportSegmentationNode) modelSegment = slicer.vtkSlicerSegmentationsModuleLogic.CreateSegmentFromModelNode(bodyModelNode) modelSegment.UnRegister(None) # Need to release ownership self.assertIsNotNone(modelSegment) self.assertIsNotNone(modelSegment.GetRepresentation(self.closedSurfaceReprName)) # Import multi-label labelmap to segmentation multiLabelImportSegmentationNode = slicer.vtkMRMLSegmentationNode() multiLabelImportSegmentationNode.SetName('MultiLabelImport') multiLabelImportSegmentationNode.GetSegmentation().SetMasterRepresentationName(self.binaryLabelmapReprName) slicer.mrmlScene.AddNode(multiLabelImportSegmentationNode) result = slicer.vtkSlicerSegmentationsModuleLogic.ImportLabelmapToSegmentationNode(allSegmentsLabelmapNode, multiLabelImportSegmentationNode) self.assertTrue(result) self.assertEqual(multiLabelImportSegmentationNode.GetSegmentation().GetNumberOfSegments(), 3) # Import labelmap into single segment singleLabelImportSegmentationNode = slicer.vtkMRMLSegmentationNode() singleLabelImportSegmentationNode.SetName('SingleLabelImport') singleLabelImportSegmentationNode.GetSegmentation().SetMasterRepresentationName(self.binaryLabelmapReprName) slicer.mrmlScene.AddNode(singleLabelImportSegmentationNode) # Should not import multi-label labelmap to segment nullSegment = slicer.vtkSlicerSegmentationsModuleLogic.CreateSegmentFromLabelmapVolumeNode(allSegmentsLabelmapNode) self.assertIsNone(nullSegment) logging.info('(This error message tests an impossible scenario, it is supposed to appear)') # Make labelmap single-label and import again threshold = vtk.vtkImageThreshold() threshold.SetInValue(0) threshold.SetOutValue(1) threshold.ReplaceInOn() threshold.ThresholdByLower(0) threshold.SetOutputScalarType(vtk.VTK_UNSIGNED_CHAR) if vtk.VTK_MAJOR_VERSION <= 5: threshold.SetInput(allSegmentsLabelmapNode.GetImageData()) else: threshold.SetInputData(allSegmentsLabelmapNode.GetImageData()) threshold.Update() allSegmentsLabelmapNode.GetImageData().ShallowCopy(threshold.GetOutput()) labelSegment = slicer.vtkSlicerSegmentationsModuleLogic.CreateSegmentFromLabelmapVolumeNode(allSegmentsLabelmapNode) labelSegment.UnRegister(None) # Need to release ownership self.assertIsNotNone(labelSegment) self.assertIsNotNone(labelSegment.GetRepresentation(self.binaryLabelmapReprName)) # Import/export with transforms logging.info('Test section 4/2: Import/export with transforms') # Create transform node that will be used to transform the tested nodes bodyModelTransformNode = slicer.vtkMRMLLinearTransformNode() slicer.mrmlScene.AddNode(bodyModelTransformNode) bodyModelTransform = vtk.vtkTransform() bodyModelTransform.Translate(1000.0, 0.0, 0.0) bodyModelTransformNode.ApplyTransformMatrix(bodyModelTransform.GetMatrix()) # Set transform as parent to input segmentation node self.inputSegmentationNode.SetAndObserveTransformNodeID(bodyModelTransformNode.GetID()) # Export single segment to model node from transformed segmentation bodyModelNodeTransformed = slicer.vtkMRMLModelNode() bodyModelNodeTransformed.SetName('BodyModelTransformed') slicer.mrmlScene.AddNode(bodyModelNodeTransformed) bodySegment = self.inputSegmentationNode.GetSegmentation().GetSegment('Body_Contour') result = slicer.vtkSlicerSegmentationsModuleLogic.ExportSegmentToRepresentationNode(bodySegment, bodyModelNodeTransformed) self.assertTrue(result) self.assertIsNotNone(bodyModelNodeTransformed.GetParentTransformNode()) # Export single segment to volume node from transformed segmentation bodyLabelmapNodeTransformed = slicer.vtkMRMLLabelMapVolumeNode() bodyLabelmapNodeTransformed.SetName('BodyLabelmapTransformed') slicer.mrmlScene.AddNode(bodyLabelmapNodeTransformed) result = slicer.vtkSlicerSegmentationsModuleLogic.ExportSegmentToRepresentationNode(bodySegment, bodyLabelmapNodeTransformed) self.assertTrue(result) self.assertIsNotNone(bodyLabelmapNodeTransformed.GetParentTransformNode()) # Create transform node that will be used to transform the tested nodes modelTransformedImportSegmentationTransformNode = slicer.vtkMRMLLinearTransformNode() slicer.mrmlScene.AddNode(modelTransformedImportSegmentationTransformNode) modelTransformedImportSegmentationTransform = vtk.vtkTransform() modelTransformedImportSegmentationTransform.Translate(-500.0, 0.0, 0.0) modelTransformedImportSegmentationTransformNode.ApplyTransformMatrix(modelTransformedImportSegmentationTransform.GetMatrix()) # Import transformed model to segment in transformed segmentation modelTransformedImportSegmentationNode = slicer.vtkMRMLSegmentationNode() modelTransformedImportSegmentationNode.SetName('ModelImportTransformed') modelTransformedImportSegmentationNode.GetSegmentation().SetMasterRepresentationName(self.closedSurfaceReprName) slicer.mrmlScene.AddNode(modelTransformedImportSegmentationNode) modelTransformedImportSegmentationNode.SetAndObserveTransformNodeID(modelTransformedImportSegmentationTransformNode.GetID()) modelSegmentTranformed = slicer.vtkSlicerSegmentationsModuleLogic.CreateSegmentFromModelNode(bodyModelNodeTransformed, modelTransformedImportSegmentationNode) modelSegmentTranformed.UnRegister(None) # Need to release ownership self.assertIsNotNone(modelSegmentTranformed) modelSegmentTransformedPolyData = modelSegmentTranformed.GetRepresentation(self.closedSurfaceReprName) self.assertIsNotNone(modelSegmentTransformedPolyData) self.assertEqual(int(modelSegmentTransformedPolyData.GetBounds()[0]), 1332) self.assertEqual(int(modelSegmentTransformedPolyData.GetBounds()[1]), 1675) # Clean up temporary nodes slicer.mrmlScene.RemoveNode(bodyModelNode) slicer.mrmlScene.RemoveNode(bodyLabelmapNode) slicer.mrmlScene.RemoveNode(allSegmentsLabelmapNode) slicer.mrmlScene.RemoveNode(modelImportSegmentationNode) slicer.mrmlScene.RemoveNode(multiLabelImportSegmentationNode) slicer.mrmlScene.RemoveNode(singleLabelImportSegmentationNode) slicer.mrmlScene.RemoveNode(bodyModelTransformNode) slicer.mrmlScene.RemoveNode(bodyModelNodeTransformed) slicer.mrmlScene.RemoveNode(bodyLabelmapNodeTransformed) slicer.mrmlScene.RemoveNode(modelTransformedImportSegmentationNode)
def test_SegmentStatisticsPlugins(self): """ This tests some aspects of the segment statistics plugins """ self.delayDisplay("Starting test_SegmentStatisticsPlugins") import vtkSegmentationCorePython as vtkSegmentationCore import SampleData from SegmentStatistics import SegmentStatisticsLogic self.delayDisplay("Load master volume") sampleDataLogic = SampleData.SampleDataLogic() masterVolumeNode = sampleDataLogic.downloadMRBrainTumor1() self.delayDisplay("Create segmentation containing a few spheres") segmentationNode = slicer.vtkMRMLSegmentationNode() slicer.mrmlScene.AddNode(segmentationNode) segmentationNode.CreateDefaultDisplayNodes() segmentationNode.SetReferenceImageGeometryParameterFromVolumeNode( masterVolumeNode) # Geometry for each segment is defined by: radius, posX, posY, posZ segmentGeometries = [[10, -6, 30, 28], [20, 0, 65, 32], [15, 1, -14, 30], [12, 0, 28, -7], [5, 0, 30, 64], [12, 31, 33, 27], [17, -42, 30, 27]] for segmentGeometry in segmentGeometries: sphereSource = vtk.vtkSphereSource() sphereSource.SetRadius(segmentGeometry[0]) sphereSource.SetCenter(segmentGeometry[1], segmentGeometry[2], segmentGeometry[3]) sphereSource.Update() segment = vtkSegmentationCore.vtkSegment() uniqueSegmentID = segmentationNode.GetSegmentation( ).GenerateUniqueSegmentID("Test") segmentationNode.AddSegmentFromClosedSurfaceRepresentation( sphereSource.GetOutput(), uniqueSegmentID) # test calculating only measurements for selected segments self.delayDisplay( "Test calculating only measurements for individual segments") segStatLogic = SegmentStatisticsLogic() segStatLogic.getParameterNode().SetParameter("Segmentation", segmentationNode.GetID()) segStatLogic.getParameterNode().SetParameter("ScalarVolume", masterVolumeNode.GetID()) segStatLogic.updateStatisticsForSegment('Test_2') resultsTableNode = slicer.vtkMRMLTableNode() slicer.mrmlScene.AddNode(resultsTableNode) segStatLogic.exportToTable(resultsTableNode) segStatLogic.showTable(resultsTableNode) self.assertEqual( segStatLogic.getStatistics()[ "Test_2", "LabelmapSegmentStatisticsPlugin.voxel_count"], 9807) with self.assertRaises(KeyError): segStatLogic.getStatistics()[ "Test_4", "ScalarVolumeSegmentStatisticsPlugin.voxel count"] # assert there are no result for this segment segStatLogic.updateStatisticsForSegment('Test_4') segStatLogic.exportToTable(resultsTableNode) segStatLogic.showTable(resultsTableNode) self.assertEqual( segStatLogic.getStatistics()[ "Test_2", "LabelmapSegmentStatisticsPlugin.voxel_count"], 9807) self.assertEqual( segStatLogic.getStatistics()[ "Test_4", "LabelmapSegmentStatisticsPlugin.voxel_count"], 380) with self.assertRaises(KeyError): segStatLogic.getStatistics()[ "Test_5", "ScalarVolumeSegmentStatisticsPlugin.voxel count"] # assert there are no result for this segment # calculate measurements for all segments segStatLogic.computeStatistics() self.assertEqual( segStatLogic.getStatistics()[ "Test", "LabelmapSegmentStatisticsPlugin.voxel_count"], 2948) self.assertEqual( segStatLogic.getStatistics() ["Test_1", "LabelmapSegmentStatisticsPlugin.voxel_count"], 23281) # test updating measurements for segments one by one self.delayDisplay("Update some segments in the segmentation") segmentGeometriesNew = [[5, -6, 30, 28], [21, 0, 65, 32]] for i in range(len(segmentGeometriesNew)): segmentGeometry = segmentGeometriesNew[i] sphereSource = vtk.vtkSphereSource() sphereSource.SetRadius(segmentGeometry[0]) sphereSource.SetCenter(segmentGeometry[1], segmentGeometry[2], segmentGeometry[3]) sphereSource.Update() segment = segmentationNode.GetSegmentation().GetNthSegment(i) segment.RemoveAllRepresentations() closedSurfaceName = vtkSegmentationCore.vtkSegmentationConverter.GetSegmentationClosedSurfaceRepresentationName( ) segment.AddRepresentation(closedSurfaceName, sphereSource.GetOutput()) self.assertEqual( segStatLogic.getStatistics()[ "Test", "LabelmapSegmentStatisticsPlugin.voxel_count"], 2948) self.assertEqual( segStatLogic.getStatistics() ["Test_1", "LabelmapSegmentStatisticsPlugin.voxel_count"], 23281) segStatLogic.updateStatisticsForSegment('Test_1') self.assertEqual( segStatLogic.getStatistics()[ "Test", "LabelmapSegmentStatisticsPlugin.voxel_count"], 2948) self.assertTrue(segStatLogic.getStatistics()[ "Test_1", "LabelmapSegmentStatisticsPlugin.voxel_count"] != 23281) segStatLogic.updateStatisticsForSegment('Test') self.assertTrue(segStatLogic.getStatistics()[ "Test", "LabelmapSegmentStatisticsPlugin.voxel_count"] != 2948) self.assertTrue(segStatLogic.getStatistics()[ "Test_1", "LabelmapSegmentStatisticsPlugin.voxel_count"] != 23281) # test enabling/disabling of individual measurements self.delayDisplay("Test disabling of individual measurements") segStatLogic = SegmentStatisticsLogic() segStatLogic.getParameterNode().SetParameter("Segmentation", segmentationNode.GetID()) segStatLogic.getParameterNode().SetParameter("ScalarVolume", masterVolumeNode.GetID()) segStatLogic.getParameterNode().SetParameter( "LabelmapSegmentStatisticsPlugin.voxel_count.enabled", str(False)) segStatLogic.getParameterNode().SetParameter( "LabelmapSegmentStatisticsPlugin.volume_cm3.enabled", str(False)) segStatLogic.computeStatistics() segStatLogic.exportToTable(resultsTableNode) segStatLogic.showTable(resultsTableNode) columnHeaders = [ resultsTableNode.GetColumnName(i) for i in range(resultsTableNode.GetNumberOfColumns()) ] self.assertFalse('Number of voxels [voxels] (1)' in columnHeaders) self.assertTrue('Volume [mm3] (1)' in columnHeaders) self.assertFalse('Volume [cm3] (3)' in columnHeaders) self.delayDisplay("Test re-enabling of individual measurements") segStatLogic.getParameterNode().SetParameter( "LabelmapSegmentStatisticsPlugin.voxel_count.enabled", str(True)) segStatLogic.getParameterNode().SetParameter( "LabelmapSegmentStatisticsPlugin.volume_cm3.enabled", str(True)) segStatLogic.computeStatistics() segStatLogic.exportToTable(resultsTableNode) segStatLogic.showTable(resultsTableNode) columnHeaders = [ resultsTableNode.GetColumnName(i) for i in range(resultsTableNode.GetNumberOfColumns()) ] self.assertTrue('Number of voxels [voxels] (1)' in columnHeaders) self.assertTrue('Volume [mm3] (1)' in columnHeaders) self.assertTrue('Volume [cm3] (1)' in columnHeaders) # test enabling/disabling of individual plugins self.delayDisplay("Test disabling of plugin") segStatLogic.getParameterNode().SetParameter( "LabelmapSegmentStatisticsPlugin.enabled", str(False)) segStatLogic.computeStatistics() segStatLogic.exportToTable(resultsTableNode) segStatLogic.showTable(resultsTableNode) columnHeaders = [ resultsTableNode.GetColumnName(i) for i in range(resultsTableNode.GetNumberOfColumns()) ] self.assertFalse('Number of voxels [voxels] (3)' in columnHeaders) self.assertFalse('Volume [mm3] (3)' in columnHeaders) self.assertTrue('Volume [mm3] (2)' in columnHeaders) self.delayDisplay("Test re-enabling of plugin") segStatLogic.getParameterNode().SetParameter( "LabelmapSegmentStatisticsPlugin.enabled", str(True)) segStatLogic.computeStatistics() segStatLogic.exportToTable(resultsTableNode) segStatLogic.showTable(resultsTableNode) columnHeaders = [ resultsTableNode.GetColumnName(i) for i in range(resultsTableNode.GetNumberOfColumns()) ] self.assertTrue('Number of voxels [voxels] (2)' in columnHeaders) self.assertTrue('Volume [mm3] (3)' in columnHeaders) # test unregistering/registering of plugins self.delayDisplay("Test of removing all registered plugins") SegmentStatisticsLogic.registeredPlugins = [ ] # remove all registered plugins segStatLogic = SegmentStatisticsLogic() segStatLogic.getParameterNode().SetParameter("Segmentation", segmentationNode.GetID()) segStatLogic.getParameterNode().SetParameter("ScalarVolume", masterVolumeNode.GetID()) segStatLogic.computeStatistics() segStatLogic.exportToTable(resultsTableNode) segStatLogic.showTable(resultsTableNode) columnHeaders = [ resultsTableNode.GetColumnName(i) for i in range(resultsTableNode.GetNumberOfColumns()) ] self.assertEqual(len(columnHeaders), 1) # only header element should be "Segment" self.assertEqual(columnHeaders[0], "Segment") # only header element should be "Segment" self.delayDisplay("Test registering plugins") SegmentStatisticsLogic.registerPlugin( LabelmapSegmentStatisticsPlugin()) SegmentStatisticsLogic.registerPlugin( ScalarVolumeSegmentStatisticsPlugin()) SegmentStatisticsLogic.registerPlugin( ClosedSurfaceSegmentStatisticsPlugin()) segStatLogic = SegmentStatisticsLogic() segStatLogic.getParameterNode().SetParameter("Segmentation", segmentationNode.GetID()) segStatLogic.getParameterNode().SetParameter("ScalarVolume", masterVolumeNode.GetID()) segStatLogic.computeStatistics() segStatLogic.exportToTable(resultsTableNode) segStatLogic.showTable(resultsTableNode) columnHeaders = [ resultsTableNode.GetColumnName(i) for i in range(resultsTableNode.GetNumberOfColumns()) ] self.assertTrue('Number of voxels [voxels] (1)' in columnHeaders) self.assertTrue('Number of voxels [voxels] (2)' in columnHeaders) self.assertTrue('Surface area [mm2]' in columnHeaders) self.delayDisplay('test_SegmentStatisticsPlugins passed!')
class VertebraSegmentation() # Load master volume sampleDataLogic = SampleData.SampleDataLogic() masterVolumeNode = sampleDataLogic.downloadCTACardio() ##gets the node coordinates to run the grow cut from later hierarchy = slicer.vtkMMRLSubjectHierarchyNode(slicer.mmrlScene) sceneItemID = hierarchy.GetSceneItemID() subjectItemID = hierarchy.GetItemChildWithName(sceneItemID,'Fiducial Nodes') fidList = slicer.util.getNode('FiducialNodes') # Create segmentation segmentationNode = slicer.vtkMRMLSegmentationNode() slicer.mrmlScene.AddNode(segmentationNode) segmentationNode.CreateDefaultDisplayNodes() # only needed for display segmentationNode.name = 'Lumbar' segmentationNode.SetReferenceImageGeometryParameterFromVolumeNode(masterVolumeNode) # Create seed segment inside lumbar and name lumbarSeed = fidList[0] lumbarSeed.SetRadius(3) lumbarSeed.Update() segmentationNode.AddSegmentFromClosedSurfaceRepresentation(lumbarSeed.GetOutput(), "Lumbar Vertebra", [1.0,0.0,0.0]) def __init__(self, scriptedEffect): SegmentEditorThresholdEffect.__init__(self, scriptedEffect) scriptedEffect.name = 'Local Threshold' self.previewSteps = 4 def updateMRMLFromGUI(self): ## sets the parameters for local threshold - grow cut at 6mm for feature size and 265.00 to 1009.00 for threshold range SegmentEditorThresholdEffect.updateMRMLFromGUI(self) featureSizeMm = 6.000 ##self.minimumMinimumFeatureSize.value self.scriptedEffect.setParameter(MINIMUM_FEATURE_MM_PARAMETER_NAME, featureSizeMm) segmentationAlgorithm = "GrowCut" ##self.segmentationAlgorithmSelector.currentText self.scriptedEffect.setParameter(SEGMENTATION_ALGORITHM_PARAMETER_NAME, segmentationAlgorithm) def runGrowCut(self, masterImageData, seedLabelmap, outputLabelmap): ## runs the grow cut - local threshold on the segment self.clippedMaskImageData = slicer.vtkOrientedImageData() intensityBasedMasking = self.scriptedEffect.parameterSetNode().GetMasterVolumeIntensityMask() segmentationNode = self.scriptedEffect.parameterSetNode().GetSegmentationNode() success = segmentationNode.GenerateEditMask(self.clippedMaskImageData, self.scriptedEffect.parameterSetNode().GetMaskMode(), masterImageData, # reference geometry "", # edited segment ID self.scriptedEffect.parameterSetNode().GetMaskSegmentID() if self.scriptedEffect.parameterSetNode().GetMaskSegmentID() else "", masterImageData if intensityBasedMasking else None, self.scriptedEffect.parameterSetNode().GetMasterVolumeIntensityMaskRange() if intensityBasedMasking else None) import vtkSlicerSegmentationsModuleLogicPython as vtkSlicerSegmentationsModuleLogic self.growCutFilter = vtkSlicerSegmentationsModuleLogic.vtkImageGrowCutSegment() self.growCutFilter.SetIntensityVolume(masterImageData) self.growCutFilter.SetSeedLabelVolume(seedLabelmap) self.growCutFilter.SetMaskVolume(self.clippedMaskImageData) self.growCutFilter.Update() outputLabelmap.ShallowCopy(self.growCutFilter.GetOutput()) def apply(self, ijkPoints): kernelSizePixel = self.getKernelSizePixel() if kernelSizePixel[0]<=0 and kernelSizePixel[1]<=0 and kernelSizePixel[2]<=0: return qt.QApplication.setOverrideCursor(qt.Qt.WaitCursor) # Get parameter set node parameterSetNode = self.scriptedEffect.parameterSetNode() # Get parameters minimumThreshold = self.scriptedEffect.doubleParameter("MinimumThreshold") maximumThreshold = self.scriptedEffect.doubleParameter("MaximumThreshold") # Get modifier labelmap modifierLabelmap = self.scriptedEffect.defaultModifierLabelmap() # Get master volume image data masterImageData = self.scriptedEffect.masterVolumeImageData() # Set intensity range oldMasterVolumeIntensityMask = parameterSetNode.GetMasterVolumeIntensityMask() parameterSetNode.MasterVolumeIntensityMaskOn() oldIntensityMaskRange = parameterSetNode.GetMasterVolumeIntensityMaskRange() intensityRange = [265.00, 1009.00] if oldMasterVolumeIntensityMask: intensityRange = [max(oldIntensityMaskRange[0], minimumThreshold), min(oldIntensityMaskRange[1], maximumThreshold)] parameterSetNode.SetMasterVolumeIntensityMaskRange(intensityRange) roiNode = lumbarSeed ##self.roiSelector.currentNode() clippedMasterImageData = masterImageData if roiNode is not None: worldToImageMatrix = vtk.vtkMatrix4x4() masterImageData.GetWorldToImageMatrix(worldToImageMatrix) bounds = [0,0,0,0,0,0] roiNode.GetRASBounds(bounds) corner1RAS = [bounds[0], bounds[2], bounds[4], 1] corner1IJK = [0, 0, 0, 0] worldToImageMatrix.MultiplyPoint(corner1RAS, corner1IJK) corner2RAS = [bounds[1], bounds[3], bounds[5], 1] corner2IJK = [0, 0, 0, 0] worldToImageMatrix.MultiplyPoint(corner2RAS, corner2IJK) extent = [0, -1, 0, -1, 0, -1] for i in range(3): lowerPoint = min(corner1IJK[i], corner2IJK[i]) upperPoint = max(corner1IJK[i], corner2IJK[i]) extent[2*i] = int(math.floor(lowerPoint)) extent[2*i+1] = int(math.ceil(upperPoint)) imageToWorldMatrix = vtk.vtkMatrix4x4() masterImageData.GetImageToWorldMatrix(imageToWorldMatrix) clippedMasterImageData = slicer.vtkOrientedImageData() self.padder = vtk.vtkImageConstantPad() self.padder.SetInputData(masterImageData) self.padder.SetOutputWholeExtent(extent) self.padder.Update() clippedMasterImageData.ShallowCopy(self.padder.GetOutput()) clippedMasterImageData.SetImageToWorldMatrix(imageToWorldMatrix) # Pipeline self.thresh = vtk.vtkImageThreshold() self.thresh.SetInValue(LABEL_VALUE) self.thresh.SetOutValue(BACKGROUND_VALUE) self.thresh.SetInputData(clippedMasterImageData) self.thresh.ThresholdBetween(minimumThreshold, maximumThreshold) self.thresh.SetOutputScalarTypeToUnsignedChar() self.thresh.Update() self.erode = vtk.vtkImageDilateErode3D() self.erode.SetInputConnection(self.thresh.GetOutputPort()) self.erode.SetDilateValue(BACKGROUND_VALUE) self.erode.SetErodeValue(LABEL_VALUE) self.erode.SetKernelSize( kernelSizePixel[0], kernelSizePixel[1], kernelSizePixel[2]) self.erodeCast = vtk.vtkImageCast() self.erodeCast.SetInputConnection(self.erode.GetOutputPort()) self.erodeCast.SetOutputScalarTypeToUnsignedInt() self.erodeCast.Update() # Remove small islands self.islandMath = vtkITK.vtkITKIslandMath() self.islandMath.SetInputConnection(self.erodeCast.GetOutputPort()) self.islandMath.SetFullyConnected(False) self.islandMath.SetMinimumSize(125) # remove regions smaller than 5x5x5 voxels self.islandThreshold = vtk.vtkImageThreshold() self.islandThreshold.SetInputConnection(self.islandMath.GetOutputPort()) self.islandThreshold.ThresholdByLower(BACKGROUND_VALUE) self.islandThreshold.SetInValue(BACKGROUND_VALUE) self.islandThreshold.SetOutValue(LABEL_VALUE) self.islandThreshold.SetOutputScalarTypeToUnsignedChar() self.islandThreshold.Update() # Points may be outside the region after it is eroded. # Snap the points to LABEL_VALUE voxels, snappedIJKPoints = self.snapIJKPointsToLabel(ijkPoints, self.islandThreshold.GetOutput()) if snappedIJKPoints.GetNumberOfPoints() == 0: qt.QApplication.restoreOverrideCursor() return # Convert points to real data coordinates. Required for vtkImageThresholdConnectivity. seedPoints = vtk.vtkPoints() origin = masterImageData.GetOrigin() spacing = masterImageData.GetSpacing() for i in range(snappedIJKPoints.GetNumberOfPoints()): ijkPoint = snappedIJKPoints.GetPoint(i) seedPoints.InsertNextPoint( origin[0]+ijkPoint[0]*spacing[0], origin[1]+ijkPoint[1]*spacing[1], origin[2]+ijkPoint[2]*spacing[2]) segmentationAlgorithm = self.scriptedEffect.parameter(SEGMENTATION_ALGORITHM_PARAMETER_NAME) if segmentationAlgorithm == SEGMENTATION_ALGORITHM_MASKING: self.runMasking(seedPoints, self.islandThreshold.GetOutput(), modifierLabelmap) else: self.floodFillingFilterIsland = vtk.vtkImageThresholdConnectivity() self.floodFillingFilterIsland.SetInputConnection(self.islandThreshold.GetOutputPort()) self.floodFillingFilterIsland.SetInValue(SELECTED_ISLAND_VALUE) self.floodFillingFilterIsland.ReplaceInOn() self.floodFillingFilterIsland.ReplaceOutOff() self.floodFillingFilterIsland.ThresholdBetween(265.00, 1009.00) self.floodFillingFilterIsland.SetSeedPoints(seedPoints) self.floodFillingFilterIsland.Update() self.maskCast = vtk.vtkImageCast() self.maskCast.SetInputData(self.thresh.GetOutput()) self.maskCast.SetOutputScalarTypeToUnsignedChar() self.maskCast.Update() self.imageMask = vtk.vtkImageMask() self.imageMask.SetInputConnection(self.floodFillingFilterIsland.GetOutputPort()) self.imageMask.SetMaskedOutputValue(OUTSIDE_THRESHOLD_VALUE) self.imageMask.SetMaskInputData(self.maskCast.GetOutput()) self.imageMask.Update() imageMaskOutput = slicer.vtkOrientedImageData() imageMaskOutput.ShallowCopy(self.imageMask.GetOutput()) imageMaskOutput.CopyDirections(clippedMasterImageData) imageToWorldMatrix = vtk.vtkMatrix4x4() imageMaskOutput.GetImageToWorldMatrix(imageToWorldMatrix) segmentOutputLabelmap = slicer.vtkOrientedImageData() if segmentationAlgorithm == SEGMENTATION_ALGORITHM_GROWCUT: self.runGrowCut(clippedMasterImageData, imageMaskOutput, segmentOutputLabelmap) elif segmentationAlgorithm == SEGMENTATION_ALGORITHM_WATERSHED: self.runWatershed(clippedMasterImageData, imageMaskOutput, segmentOutputLabelmap) else: logging.error("Unknown segmentation algorithm: \"" + segmentationAlgorithm + "\"") segmentOutputLabelmap.SetImageToWorldMatrix(imageToWorldMatrix) self.selectedSegmentThreshold = vtk.vtkImageThreshold() self.selectedSegmentThreshold.SetInputData(segmentOutputLabelmap) self.selectedSegmentThreshold.ThresholdBetween(SELECTED_ISLAND_VALUE, SELECTED_ISLAND_VALUE) self.selectedSegmentThreshold.SetInValue(LABEL_VALUE) self.selectedSegmentThreshold.SetOutValue(BACKGROUND_VALUE) self.selectedSegmentThreshold.SetOutputScalarType(modifierLabelmap.GetScalarType()) self.selectedSegmentThreshold.Update() modifierLabelmap.ShallowCopy(self.selectedSegmentThreshold.GetOutput()) self.scriptedEffect.saveStateForUndo() self.scriptedEffect.modifySelectedSegmentByLabelmap(modifierLabelmap, slicer.qSlicerSegmentEditorAbstractEffect.ModificationModeAdd) parameterSetNode.SetMasterVolumeIntensityMask(oldMasterVolumeIntensityMask) parameterSetNode.SetMasterVolumeIntensityMaskRange(oldIntensityMaskRange) qt.QApplication.restoreOverrideCursor()
def test_SegmentStatisticsPlugins(self): """ This tests some aspects of the segment statistics plugins """ self.delayDisplay("Starting test_SegmentStatisticsPlugins") import vtkSegmentationCorePython as vtkSegmentationCore import SampleData from SegmentStatistics import SegmentStatisticsLogic self.delayDisplay("Load master volume") sampleDataLogic = SampleData.SampleDataLogic() masterVolumeNode = sampleDataLogic.downloadMRBrainTumor1() self.delayDisplay("Create segmentation containing a few spheres") segmentationNode = slicer.vtkMRMLSegmentationNode() slicer.mrmlScene.AddNode(segmentationNode) segmentationNode.CreateDefaultDisplayNodes() segmentationNode.SetReferenceImageGeometryParameterFromVolumeNode(masterVolumeNode) # Geometry for each segment is defined by: radius, posX, posY, posZ segmentGeometries = [[10, -6,30,28], [20, 0,65,32], [15, 1, -14, 30], [12, 0, 28, -7], [5, 0,30,64], [12, 31, 33, 27], [17, -42, 30, 27]] for segmentGeometry in segmentGeometries: sphereSource = vtk.vtkSphereSource() sphereSource.SetRadius(segmentGeometry[0]) sphereSource.SetCenter(segmentGeometry[1], segmentGeometry[2], segmentGeometry[3]) sphereSource.Update() segment = vtkSegmentationCore.vtkSegment() uniqueSegmentID = segmentationNode.GetSegmentation().GenerateUniqueSegmentID("Test") segmentationNode.AddSegmentFromClosedSurfaceRepresentation(sphereSource.GetOutput(), uniqueSegmentID) # test calculating only measurements for selected segments self.delayDisplay("Test calculating only measurements for individual segments") segStatLogic = SegmentStatisticsLogic() segStatLogic.getParameterNode().SetParameter("Segmentation", segmentationNode.GetID()) segStatLogic.getParameterNode().SetParameter("ScalarVolume", masterVolumeNode.GetID()) segStatLogic.updateStatisticsForSegment('Test_2') resultsTableNode = slicer.vtkMRMLTableNode() slicer.mrmlScene.AddNode(resultsTableNode) segStatLogic.exportToTable(resultsTableNode) segStatLogic.showTable(resultsTableNode) self.assertEqual( segStatLogic.getStatistics()["Test_2","LabelmapSegmentStatisticsPlugin.voxel_count"], 9807) with self.assertRaises(KeyError): segStatLogic.getStatistics()["Test_4","ScalarVolumeSegmentStatisticsPlugin.voxel count"] # assert there are no result for this segment segStatLogic.updateStatisticsForSegment('Test_4') segStatLogic.exportToTable(resultsTableNode) segStatLogic.showTable(resultsTableNode) self.assertEqual( segStatLogic.getStatistics()["Test_2","LabelmapSegmentStatisticsPlugin.voxel_count"], 9807) self.assertEqual( segStatLogic.getStatistics()["Test_4","LabelmapSegmentStatisticsPlugin.voxel_count"], 380) with self.assertRaises(KeyError): segStatLogic.getStatistics()["Test_5","ScalarVolumeSegmentStatisticsPlugin.voxel count"] # assert there are no result for this segment # calculate measurements for all segments segStatLogic.computeStatistics() self.assertEqual( segStatLogic.getStatistics()["Test","LabelmapSegmentStatisticsPlugin.voxel_count"], 2948) self.assertEqual( segStatLogic.getStatistics()["Test_1","LabelmapSegmentStatisticsPlugin.voxel_count"], 23281) # test updating measurements for segments one by one self.delayDisplay("Update some segments in the segmentation") segmentGeometriesNew = [[5, -6,30,28], [21, 0,65,32]] for i in range(len(segmentGeometriesNew)): segmentGeometry = segmentGeometriesNew[i] sphereSource = vtk.vtkSphereSource() sphereSource.SetRadius(segmentGeometry[0]) sphereSource.SetCenter(segmentGeometry[1], segmentGeometry[2], segmentGeometry[3]) sphereSource.Update() segment = segmentationNode.GetSegmentation().GetNthSegment(i) segment.RemoveAllRepresentations() closedSurfaceName = vtkSegmentationCore.vtkSegmentationConverter.GetSegmentationClosedSurfaceRepresentationName() segment.AddRepresentation(closedSurfaceName, sphereSource.GetOutput()) self.assertEqual( segStatLogic.getStatistics()["Test","LabelmapSegmentStatisticsPlugin.voxel_count"], 2948) self.assertEqual( segStatLogic.getStatistics()["Test_1","LabelmapSegmentStatisticsPlugin.voxel_count"], 23281) segStatLogic.updateStatisticsForSegment('Test_1') self.assertEqual( segStatLogic.getStatistics()["Test","LabelmapSegmentStatisticsPlugin.voxel_count"], 2948) self.assertTrue( segStatLogic.getStatistics()["Test_1","LabelmapSegmentStatisticsPlugin.voxel_count"]!=23281) segStatLogic.updateStatisticsForSegment('Test') self.assertTrue( segStatLogic.getStatistics()["Test","LabelmapSegmentStatisticsPlugin.voxel_count"]!=2948) self.assertTrue( segStatLogic.getStatistics()["Test_1","LabelmapSegmentStatisticsPlugin.voxel_count"]!=23281) # test enabling/disabling of individual measurements self.delayDisplay("Test disabling of individual measurements") segStatLogic = SegmentStatisticsLogic() segStatLogic.getParameterNode().SetParameter("Segmentation", segmentationNode.GetID()) segStatLogic.getParameterNode().SetParameter("ScalarVolume", masterVolumeNode.GetID()) segStatLogic.getParameterNode().SetParameter("LabelmapSegmentStatisticsPlugin.voxel_count.enabled",str(False)) segStatLogic.getParameterNode().SetParameter("LabelmapSegmentStatisticsPlugin.volume_cm3.enabled",str(False)) segStatLogic.computeStatistics() segStatLogic.exportToTable(resultsTableNode) segStatLogic.showTable(resultsTableNode) columnHeaders = [resultsTableNode.GetColumnName(i) for i in range(resultsTableNode.GetNumberOfColumns())] self.assertFalse('Number of voxels [voxels] (1)' in columnHeaders) self.assertTrue('Volume [mm3] (1)' in columnHeaders) self.assertFalse('Volume [cm3] (3)' in columnHeaders) self.delayDisplay("Test re-enabling of individual measurements") segStatLogic.getParameterNode().SetParameter("LabelmapSegmentStatisticsPlugin.voxel_count.enabled",str(True)) segStatLogic.getParameterNode().SetParameter("LabelmapSegmentStatisticsPlugin.volume_cm3.enabled",str(True)) segStatLogic.computeStatistics() segStatLogic.exportToTable(resultsTableNode) segStatLogic.showTable(resultsTableNode) columnHeaders = [resultsTableNode.GetColumnName(i) for i in range(resultsTableNode.GetNumberOfColumns())] self.assertTrue('Number of voxels [voxels] (1)' in columnHeaders) self.assertTrue('Volume [mm3] (1)' in columnHeaders) self.assertTrue('Volume [cm3] (1)' in columnHeaders) # test enabling/disabling of individual plugins self.delayDisplay("Test disabling of plugin") segStatLogic.getParameterNode().SetParameter("LabelmapSegmentStatisticsPlugin.enabled",str(False)) segStatLogic.computeStatistics() segStatLogic.exportToTable(resultsTableNode) segStatLogic.showTable(resultsTableNode) columnHeaders = [resultsTableNode.GetColumnName(i) for i in range(resultsTableNode.GetNumberOfColumns())] self.assertFalse('Number of voxels [voxels] (3)' in columnHeaders) self.assertFalse('Volume [mm3] (3)' in columnHeaders) self.assertTrue('Volume [mm3] (2)' in columnHeaders) self.delayDisplay("Test re-enabling of plugin") segStatLogic.getParameterNode().SetParameter("LabelmapSegmentStatisticsPlugin.enabled",str(True)) segStatLogic.computeStatistics() segStatLogic.exportToTable(resultsTableNode) segStatLogic.showTable(resultsTableNode) columnHeaders = [resultsTableNode.GetColumnName(i) for i in range(resultsTableNode.GetNumberOfColumns())] self.assertTrue('Number of voxels [voxels] (2)' in columnHeaders) self.assertTrue('Volume [mm3] (3)' in columnHeaders) # test unregistering/registering of plugins self.delayDisplay("Test of removing all registered plugins") SegmentStatisticsLogic.registeredPlugins = [] # remove all registered plugins segStatLogic = SegmentStatisticsLogic() segStatLogic.getParameterNode().SetParameter("Segmentation", segmentationNode.GetID()) segStatLogic.getParameterNode().SetParameter("ScalarVolume", masterVolumeNode.GetID()) segStatLogic.computeStatistics() segStatLogic.exportToTable(resultsTableNode) segStatLogic.showTable(resultsTableNode) columnHeaders = [resultsTableNode.GetColumnName(i) for i in range(resultsTableNode.GetNumberOfColumns())] self.assertEqual(len(columnHeaders),1) # only header element should be "Segment" self.assertEqual(columnHeaders[0],"Segment") # only header element should be "Segment" self.delayDisplay("Test registering plugins") SegmentStatisticsLogic.registerPlugin(LabelmapSegmentStatisticsPlugin()) SegmentStatisticsLogic.registerPlugin(ScalarVolumeSegmentStatisticsPlugin()) SegmentStatisticsLogic.registerPlugin(ClosedSurfaceSegmentStatisticsPlugin()) segStatLogic = SegmentStatisticsLogic() segStatLogic.getParameterNode().SetParameter("Segmentation", segmentationNode.GetID()) segStatLogic.getParameterNode().SetParameter("ScalarVolume", masterVolumeNode.GetID()) segStatLogic.computeStatistics() segStatLogic.exportToTable(resultsTableNode) segStatLogic.showTable(resultsTableNode) columnHeaders = [resultsTableNode.GetColumnName(i) for i in range(resultsTableNode.GetNumberOfColumns())] self.assertTrue('Number of voxels [voxels] (1)' in columnHeaders) self.assertTrue('Number of voxels [voxels] (2)' in columnHeaders) self.assertTrue('Surface area [mm2]' in columnHeaders) self.delayDisplay('test_SegmentStatisticsPlugins passed!')
def test_sceneImport24281(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") # # first, get some data # self.delayDisplay("Getting Data") import SampleData head = SampleData.downloadSample("MRHead") # Create segmentation segmentationNode = slicer.vtkMRMLSegmentationNode() slicer.mrmlScene.AddNode(segmentationNode) segmentationNode.CreateDefaultDisplayNodes() # only needed for display segmentationNode.SetReferenceImageGeometryParameterFromVolumeNode(head) # Add a few segments segments = [["Segment A", [0, 65, 32], 25, [1.0, 0.0, 0.0]], ["Segment B", [1, -14, 30], 30, [1.0, 1.0, 0.0]], ["Segment C", [0, 28, -7], 15, [0.0, 1.0, 1.0]], ["Segment D", [31, 33, 27], 25, [0.0, 0.0, 1.0]]] for [name, position, radius, color] in segments: seed = vtk.vtkSphereSource() seed.SetCenter(position) seed.SetRadius(radius) seed.Update() segmentationNode.AddSegmentFromClosedSurfaceRepresentation( seed.GetOutput(), name, color) # Export to labelmap volume headLabel = slicer.mrmlScene.AddNewNodeByClass( 'vtkMRMLLabelMapVolumeNode') slicer.modules.segmentations.logic( ).ExportVisibleSegmentsToLabelmapNode(segmentationNode, headLabel, head) selectionNode = slicer.app.applicationLogic().GetSelectionNode() selectionNode.SetActiveVolumeID(head.GetID()) selectionNode.SetActiveLabelVolumeID(headLabel.GetID()) slicer.app.applicationLogic().PropagateVolumeSelection(0) # # now build: # create a model using the command line module # based on the current editor parameters # - make a new hierarchy node # self.delayDisplay("Building...") parameters = {} parameters["InputVolume"] = headLabel.GetID() # create models for all labels parameters["JointSmoothing"] = True parameters["StartLabel"] = -1 parameters["EndLabel"] = -1 outHierarchy = slicer.vtkMRMLModelHierarchyNode() outHierarchy.SetScene(slicer.mrmlScene) outHierarchy.SetName("sceneImport2428Hierachy") slicer.mrmlScene.AddNode(outHierarchy) parameters["ModelSceneFile"] = outHierarchy modelMaker = slicer.modules.modelmaker self.CLINode = None self.CLINode = slicer.cli.runSync(modelMaker, self.CLINode, parameters, delete_temporary_files=False) self.delayDisplay("Models built") success = self.verifyModels() success = success and ( slicer.mrmlScene.GetNumberOfNodesByClass("vtkMRMLModelNode") > 3) self.delayDisplay("Test finished") if success: self.delayDisplay("Ahh... test passed.") else: self.delayDisplay("!$!$!#!@#!@!@$%! Test Failed!!") self.assertTrue(success)