def resetIslandSegments(self, islandSizes): self.segmentation.RemoveAllSegments() totalSize = 0 voxelSizeSum = 0 for size in islandSizes: totalSize += size + 1 voxelSizeSum += size mergedLabelmap = vtkSegmentationCore.vtkOrientedImageData() mergedLabelmapExtent = [0, totalSize-1, 0, 0, 0, 0] self.setupIslandLabelmap(mergedLabelmap, mergedLabelmapExtent, 0) emptySegment = slicer.vtkSegment() emptySegment.SetName("Segment_1") emptySegment.AddRepresentation(self.binaryLabelmapReprName, mergedLabelmap) self.segmentation.AddSegment(emptySegment) self.segmentEditorNode.SetSelectedSegmentID("Segment_1") startExtent = 0 for size in islandSizes: islandLabelmap = vtkSegmentationCore.vtkOrientedImageData() islandExtent = [startExtent, startExtent+size-1, 0, 0, 0, 0] self.setupIslandLabelmap(islandLabelmap, islandExtent) self.paintEffect.modifySelectedSegmentByLabelmap(islandLabelmap, self.paintEffect.ModificationModeAdd) startExtent += size + 1 self.checkSegmentVoxelCount(0, voxelSizeSum) layerCount = self.segmentation.GetNumberOfLayers() self.assertEqual(layerCount, 1)
def TestSection_01_GenerateInputData(self): logging.info('Test section 1: GenerateInputData') self.inputSegmentationNode = slicer.mrmlScene.AddNewNodeByClass( 'vtkMRMLSegmentationNode') # Create new segments import random for segmentName in ['first', 'second', 'third']: sphereSegment = slicer.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( slicer.vtkSegmentationConverter. GetSegmentationClosedSurfaceRepresentationName(), spherePolyData) self.inputSegmentationNode.GetSegmentation().AddSegment( sphereSegment) self.assertEqual( self.inputSegmentationNode.GetSegmentation().GetNumberOfSegments(), 3) self.inputSegmentationNode.CreateDefaultDisplayNodes() displayNode = self.inputSegmentationNode.GetDisplayNode() self.assertIsNotNone(displayNode)
def createSegNodeFromContourPoints(segmentationNode, contours, name): # set up contour objects contoursPolyData = vtk.vtkPolyData() contourPoints = vtk.vtkPoints() contourLines = vtk.vtkCellArray() contoursPolyData.SetLines(contourLines) contoursPolyData.SetPoints(contourPoints) for contour in contours: startPointIndex = contourPoints.GetNumberOfPoints() contourLine = vtk.vtkPolyLine() linePointIds = contourLine.GetPointIds() for point in contour: linePointIds.InsertNextId(contourPoints.InsertNextPoint(point)) linePointIds.InsertNextId( startPointIndex) # make the contour line closed contourLines.InsertNextCell(contourLine) segment = slicer.vtkSegment() segment.SetName(name) # segment.SetColor(segmentColor) segment.AddRepresentation("Planar contour", contoursPolyData) segmentationNode.GetSegmentation().SetMasterRepresentationName( "Planar contour") segmentationNode.GetSegmentation().AddSegment(segment)
def _polydataToNewSegment(polydata, segmentationNode, segmentID): segmentation = segmentationNode.GetSegmentation() baseSegment = segmentation.GetSegment(segmentID) segment = slicer.vtkSegment() segment.SetName(baseSegment.GetName() + "_solid") segment.AddRepresentation( vtkSegmentationCorePython.vtkSegmentationConverter. GetSegmentationClosedSurfaceRepresentationName(), polydata) segmentation.AddSegment(segment)
def TestSection_03_qMRMLSegmentationGeometryWidget(self): logging.info('Test section 2: qMRMLSegmentationGeometryWidget') binaryLabelmapReprName = slicer.vtkSegmentationConverter.GetBinaryLabelmapRepresentationName( ) closedSurfaceReprName = slicer.vtkSegmentationConverter.GetClosedSurfaceRepresentationName( ) # Use MRHead and Tinypatient for testing import SampleData mrVolumeNode = SampleData.downloadSample("MRHead") [tinyVolumeNode, tinySegmentationNode] = SampleData.downloadSamples('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.mrmlScene.AddNewNodeByClass( 'vtkMRMLSegmentationNode') segmentationNode.GetSegmentation().SetMasterRepresentationName( binaryLabelmapReprName) geometryStr = slicer.vtkSegmentationConverter.SerializeImageGeometry( mrOrientedImageData) segmentationNode.GetSegmentation().SetConversionParameter( slicer.vtkSegmentationConverter. GetReferenceImageGeometryParameterName(), geometryStr) 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 = slicer.vtkOrientedImageData() segmentOrientedImageData.DeepCopy(threshold.GetOutput()) mrImageToWorldMatrix = vtk.vtkMatrix4x4() mrOrientedImageData.GetImageToWorldMatrix(mrImageToWorldMatrix) segmentOrientedImageData.SetImageToWorldMatrix(mrImageToWorldMatrix) segment = slicer.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 = slicer.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]])) slicer.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), (273.3439, 272.7890, -112.25), [[-1.0, 0.0, 0.0], [0.0, -1.0, 0.0], [0.0, 0.0, 1.0]])) slicer.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]])) slicer.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]])) slicer.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]])) slicer.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), (-86.645, 133.929, 116.786), # current origin of the segmentation is kept [[0.0, 0.0, 1.0], [-1.0, 0.0, 0.0], [0.0, -1.0, 0.0]])) slicer.vtkOrientedImageDataResample.ResampleOrientedImageToReferenceOrientedImage( segmentOrientedImageData, geometryImageData, geometryImageData, False, True) self.assertEqual(self.getForegroundVoxelCount(geometryImageData), 5223040) slicer.util.delayDisplay('Segmentation source cases - OK') # Model source with no transform shNode = slicer.vtkMRMLSubjectHierarchyNode.GetSubjectHierarchyNode( slicer.mrmlScene) outputFolderId = shNode.CreateFolderItem(shNode.GetSceneItemID(), 'ModelsFolder') success = vtkSlicerSegmentationsModuleLogic.vtkSlicerSegmentationsModuleLogic.ExportVisibleSegmentsToModels( tinySegmentationNode, outputFolderId) self.assertTrue(success) modelNode = slicer.util.getNode('Body_Contour') geometryWidget.setSourceNode(modelNode) geometryWidget.geometryImageData(geometryImageData) self.assertTrue( self.compareOutputGeometry( geometryImageData, (1, 1, 1), (-86.645, 133.929, 116.786), # current origin of the segmentation is kept [[0.0, 0.0, 1.0], [-1.0, 0.0, 0.0], [0.0, -1.0, 0.0]])) slicer.vtkOrientedImageDataResample.ResampleOrientedImageToReferenceOrientedImage( segmentOrientedImageData, geometryImageData, geometryImageData, False, True) self.assertEqual(self.getForegroundVoxelCount(geometryImageData), 5223040) # 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), (-86.645, 177.282, -12.122), [[0.0, 0.0, 1.0], [-0.7071, -0.7071, 0.0], [0.7071, -0.7071, 0.0]])) slicer.vtkOrientedImageDataResample.ResampleOrientedImageToReferenceOrientedImage( segmentOrientedImageData, geometryImageData, geometryImageData, False, True) self.assertEqual(self.getForegroundVoxelCount(geometryImageData), 5229164) # ROI source roiNode = slicer.mrmlScene.AddNewNodeByClass( "vtkMRMLAnnotationROINode", 'SourceROI') xyz = [0.0, 0.0, 0.0] center = [0.0, 0.0, 0.0] slicer.vtkMRMLSliceLogic.GetVolumeRASBox(tinyVolumeNode, xyz, center) radius = [x / 2.0 for x in xyz] roiNode.SetXYZ(center) roiNode.SetRadiusXYZ(radius) geometryWidget.setSourceNode(roiNode) geometryWidget.geometryImageData(geometryImageData) self.assertTrue( self.compareOutputGeometry( geometryImageData, (1, 1, 1), (0.0, 0.0, 0.0), [[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]])) slicer.vtkOrientedImageDataResample.ResampleOrientedImageToReferenceOrientedImage( segmentOrientedImageData, geometryImageData, geometryImageData, False, True) self.assertEqual(self.getForegroundVoxelCount(geometryImageData), 5224232) slicer.util.delayDisplay('Model and ROI source cases - OK') slicer.util.delayDisplay('Segmentation geometry widget test passed')
def splitSegments(self, minimumSize=0, maxNumberOfSegments=0, split=True): """ minimumSize: if 0 then it means that all islands are kept, regardless of size maxNumberOfSegments: if 0 then it means that all islands are kept, regardless of how many """ # This can be a long operation - indicate it to the user qt.QApplication.setOverrideCursor(qt.Qt.WaitCursor) self.scriptedEffect.saveStateForUndo() # Get modifier labelmap selectedSegmentLabelmap = self.scriptedEffect.selectedSegmentLabelmap() castIn = vtk.vtkImageCast() castIn.SetInputData(selectedSegmentLabelmap) castIn.SetOutputScalarTypeToUnsignedInt() # Identify the islands in the inverted volume and # find the pixel that corresponds to the background islandMath = vtkITK.vtkITKIslandMath() islandMath.SetInputConnection(castIn.GetOutputPort()) islandMath.SetFullyConnected(False) islandMath.SetMinimumSize(minimumSize) islandMath.Update() islandImage = slicer.vtkOrientedImageData() islandImage.ShallowCopy(islandMath.GetOutput()) selectedSegmentLabelmapImageToWorldMatrix = vtk.vtkMatrix4x4() selectedSegmentLabelmap.GetImageToWorldMatrix( selectedSegmentLabelmapImageToWorldMatrix) islandImage.SetImageToWorldMatrix( selectedSegmentLabelmapImageToWorldMatrix) islandCount = islandMath.GetNumberOfIslands() islandOrigCount = islandMath.GetOriginalNumberOfIslands() ignoredIslands = islandOrigCount - islandCount logging.info("%d islands created (%d ignored)" % (islandCount, ignoredIslands)) baseSegmentName = "Label" selectedSegmentID = self.scriptedEffect.parameterSetNode( ).GetSelectedSegmentID() segmentationNode = self.scriptedEffect.parameterSetNode( ).GetSegmentationNode() with slicer.util.NodeModify(segmentationNode): segmentation = segmentationNode.GetSegmentation() selectedSegment = segmentation.GetSegment(selectedSegmentID) selectedSegmentName = selectedSegment.GetName() if selectedSegmentName is not None and selectedSegmentName != "": baseSegmentName = selectedSegmentName labelValues = vtk.vtkIntArray() slicer.vtkSlicerSegmentationsModuleLogic.GetAllLabelValues( labelValues, islandImage) # Erase segment from in original labelmap. # Individuall islands will be added back later. threshold = vtk.vtkImageThreshold() threshold.SetInputData(selectedSegmentLabelmap) threshold.ThresholdBetween(0, 0) threshold.SetInValue(0) threshold.SetOutValue(0) threshold.Update() emptyLabelmap = slicer.vtkOrientedImageData() emptyLabelmap.ShallowCopy(threshold.GetOutput()) emptyLabelmap.CopyDirections(selectedSegmentLabelmap) self.scriptedEffect.modifySegmentByLabelmap( segmentationNode, selectedSegmentID, emptyLabelmap, slicer.qSlicerSegmentEditorAbstractEffect.ModificationModeSet) for i in range(labelValues.GetNumberOfTuples()): if (maxNumberOfSegments > 0 and i >= maxNumberOfSegments): # We only care about the segments up to maxNumberOfSegments. # If we do not want to split segments, we only care about the first. break labelValue = int(labelValues.GetTuple1(i)) segment = selectedSegment segmentID = selectedSegmentID if i != 0 and split: segment = slicer.vtkSegment() name = baseSegmentName + "_" + str(i + 1) segment.SetName(name) segment.AddRepresentation( slicer.vtkSegmentationConverter. GetSegmentationBinaryLabelmapRepresentationName(), selectedSegment.GetRepresentation( slicer.vtkSegmentationConverter. GetSegmentationBinaryLabelmapRepresentationName())) segmentation.AddSegment(segment) segmentID = segmentation.GetSegmentIdBySegment(segment) segment.SetLabelValue( segmentation.GetUniqueLabelValueForSharedLabelmap( selectedSegmentID)) threshold = vtk.vtkImageThreshold() threshold.SetInputData(islandMath.GetOutput()) threshold.ThresholdBetween(labelValue, labelValue) threshold.SetInValue(1) threshold.SetOutValue(0) threshold.Update() modificationMode = slicer.qSlicerSegmentEditorAbstractEffect.ModificationModeAdd if i == 0: modificationMode = slicer.qSlicerSegmentEditorAbstractEffect.ModificationModeSet # Create oriented image data from output modifierImage = slicer.vtkOrientedImageData() modifierImage.DeepCopy(threshold.GetOutput()) selectedSegmentLabelmapImageToWorldMatrix = vtk.vtkMatrix4x4() selectedSegmentLabelmap.GetImageToWorldMatrix( selectedSegmentLabelmapImageToWorldMatrix) modifierImage.SetGeometryFromImageToWorldMatrix( selectedSegmentLabelmapImageToWorldMatrix) # We could use a single slicer.vtkSlicerSegmentationsModuleLogic.ImportLabelmapToSegmentationNode # method call to import all the resulting segments at once but that would put all the imported segments # in a new layer. By using modifySegmentByLabelmap, the number of layers will not increase. self.scriptedEffect.modifySegmentByLabelmap( segmentationNode, segmentID, modifierImage, modificationMode) qt.QApplication.restoreOverrideCursor()
def importOsirixRoiFileToSegmentation(self, inputRoi, outputSegmentationNode, smoothing=True, labelmapOutput=False): """ Run the processing algorithm. Can be used without GUI widget. :param inputRoi: input OsiriX ROI file path or text node :param outputSegmentation: output segmentation node """ if not inputRoi or not outputSegmentationNode: raise ValueError( "Input file or output segmentation node is invalid") logging.info('Processing started') inputRoiData = None import json import plistlib if isinstance(inputRoi, str): filename, ext = os.path.splitext(inputRoi) if ext.lower() == '.json': with open(inputRoi) as f: inputRoiData = json.load(f) else: inputRoiData = plistlib.readPlist(inputRoi) elif isinstance(inputRoi, slicer.vtkMRMLTextNode): try: inputRoiData = json.loads(inputRoi.GetText()) except: inputRoiData = plistlib.readPlistFromBytes(inputRoi.GetText()) else: raise TypeError( "inputRoi is expected to be a string or vtkMRMLTextNode") outputSegmentationNode.CreateDefaultDisplayNodes() segmentation = outputSegmentationNode.GetSegmentation() segmentation.SetMasterRepresentationName( slicer.vtkSegmentationConverter.GetPlanarContourRepresentationName( )) roiDescriptions = {} # map from ROI name to RoiDescription class RoiDescription(object): def __init__(self): self.roiContourPoints = vtk.vtkPoints() self.roiContourCells = vtk.vtkCellArray() def addRoiPoints(self, roiPoints): cellPointIds = [] for roiPoint in roiPoints: cellPointIds.append( self.roiContourPoints.InsertNextPoint(roiPoint)) contourIndex = self.roiContourCells.InsertNextCell( len(cellPointIds) + 1) for cellPointId in cellPointIds: self.roiContourCells.InsertCellPoint(cellPointId) self.roiContourCells.InsertCellPoint( cellPointIds[0]) # close the contour if "Images" not in inputRoiData: for contourIndex, contour in enumerate(inputRoiData): # Get/create ROI description name = contour["Name"] try: roiDescription = roiDescriptions[name] except KeyError: roiDescription = RoiDescription() roiDescriptions[name] = roiDescription # Add points roiPoints = self._pointCoordinatesFromStringList( contour["ROI3DPoints"], '[]') if smoothing: roiPoints = self._smoothCurve(roiPoints) roiDescription.addRoiPoints(roiPoints) self.log(f"Importing {len(roiDescriptions)} ROIs", 25.0 * contourIndex / len(inputRoiData)) else: # Output of OsiriX "Export ROIs" plugin for imageIndex, image in enumerate(inputRoiData['Images']): rois = image['ROIs'] for roiIndex, roi in enumerate(rois): # Get/create ROI description name = roi["Name"] try: roiDescription = roiDescriptions[name] except KeyError: roiDescription = RoiDescription() roiDescriptions[name] = roiDescription # Add points roiPoints = self._pointCoordinatesFromStringList( roi['Point_mm'], '()') if smoothing: roiPoints = self._smoothCurve(roiPoints) roiDescription.addRoiPoints(roiPoints) self.log(f"Importing {len(roiDescriptions)} ROIs", 25.0 * imageIndex / len(inputRoiData["Images"])) colorNode = slicer.mrmlScene.GetNodeByID( slicer.modules.colors.logic().GetDefaultLabelMapColorNodeID()) for segmentIndex, name in enumerate(roiDescriptions): self.log( f"Creating segment {segmentIndex+1} of {len(roiDescriptions)}", 25.0 + 50.0 * segmentIndex / len(roiDescriptions)) roiDescription = roiDescriptions[name] colorRGBA = [0, 0, 0, 0] colorNode.GetColor(segmentIndex + 1, colorRGBA) roiPolyData = vtk.vtkPolyData() roiPolyData.SetPoints(roiDescription.roiContourPoints) roiPolyData.SetLines(roiDescription.roiContourCells) normals = vtk.vtkPolyDataNormals() normals.SetInputData(roiPolyData) normals.Update() segment = slicer.vtkSegment() segment.SetName(name) segment.SetColor(colorRGBA[:3]) segment.AddRepresentation( slicer.vtkSegmentationConverter. GetPlanarContourRepresentationName(), roiPolyData) segmentation.AddSegment(segment) self.log("Creating representations...", 80) if labelmapOutput: outputSegmentationNode.CreateBinaryLabelmapRepresentation() outputSegmentationNode.CreateClosedSurfaceRepresentation() outputSegmentationNode.GetDisplayNode( ).SetPreferredDisplayRepresentationName2D( slicer.vtkSegmentationConverter. GetBinaryLabelmapRepresentationName()) outputSegmentationNode.GetDisplayNode( ).SetPreferredDisplayRepresentationName3D( slicer.vtkSegmentationConverter. GetClosedSurfaceRepresentationName()) else: outputSegmentationNode.CreateClosedSurfaceRepresentation() outputSegmentationNode.GetDisplayNode( ).SetPreferredDisplayRepresentationName2D( slicer.vtkSegmentationConverter. GetClosedSurfaceRepresentationName()) outputSegmentationNode.GetDisplayNode( ).SetPreferredDisplayRepresentationName3D( slicer.vtkSegmentationConverter. GetClosedSurfaceRepresentationName()) logging.info('Processing completed')
def ProceduralSegmentation(self, inputDir, outputDir): # Importing Dicom into temporary database dicomDataDir = inputDir from DICOMLib import DICOMUtils loadedNodeIDs = [] with DICOMUtils.TemporaryDICOMDatabase() as db: DICOMUtils.importDicom(dicomDataDir, db) patientUIDs = db.patients() for patientUID in patientUIDs: loadedNodeIDs.extend(DICOMUtils.loadPatientByUID(patientUID)) # Loading Dicom into scene seriesVolumeNode = slicer.util.getNode(loadedNodeIDs[0]) storageVolumeNode = seriesVolumeNode.CreateDefaultStorageNode() slicer.mrmlScene.AddNode(storageVolumeNode) storageVolumeNode.UnRegister(slicer.mrmlScene) seriesVolumeNode.SetAndObserveStorageNodeID(storageVolumeNode.GetID()) # Access segmentation module slicer.util.selectModule('Segment Editor') segmentationNode = slicer.mrmlScene.AddNewNodeByClass( "vtkMRMLSegmentationNode") slicer.mrmlScene.AddNode(segmentationNode) segmentationNode.CreateDefaultDisplayNodes() # only needed for display segmentationNode.SetReferenceImageGeometryParameterFromVolumeNode( seriesVolumeNode) # TODO Automate creation of different segments in the future (using some form of -type argument) # Create spine segment segmentTypeID = "Spine" newSegment = slicer.vtkSegment() newSegment.SetName(segmentTypeID) newSegment.SetColor([0.89, 0.85, 0.78]) segmentationNode.GetSegmentation().AddSegment(newSegment, segmentTypeID) # Create segment editor widget to get access to effects segmentEditorWidget = slicer.qMRMLSegmentEditorWidget() segmentEditorWidget.setMRMLScene(slicer.mrmlScene) # Access segment editor node segmentEditorNode = slicer.mrmlScene.AddNewNodeByClass( "vtkMRMLSegmentEditorNode") slicer.mrmlScene.AddNode(segmentEditorNode) segmentEditorWidget.setMRMLSegmentEditorNode(segmentEditorNode) segmentEditorWidget.setSegmentationNode(segmentationNode) segmentEditorWidget.setMasterVolumeNode(seriesVolumeNode) # Segment Editor Effect: Thresholding segmentEditorWidget.setActiveEffectByName("Threshold") effect = segmentEditorWidget.activeEffect() effect.setParameter("MinimumThreshold", "90") effect.setParameter("MaximumThreshold", "1600") effect.self().onApply() # Setting Closed Surface Representation Values segmentationNode.GetSegmentation().SetConversionParameter( "Oversampling factor", "1.0") segmentationNode.GetSegmentation().SetConversionParameter( "Joint smoothing", "0.50") segmentationNode.GetSegmentation().SetConversionParameter( "Smoothing factor", "0.50") # Segment Editor Effect: Smoothing segmentEditorWidget.setActiveEffectByName("Smoothing") effect = segmentEditorWidget.activeEffect() # 2mm MEDIAN Smoothing effect.setParameter("SmoothingMethod", "MEDIAN") effect.setParameter("KernelSizeMm", 2.5) effect.self().onApply() # 2mm OPEN Smoothing #effect.setParameter("SmoothingMethod", "MORPHOLOGICAL_OPENING") #effect.setParameter("KernelSizeMm", 2) #effect.self().onApply # 1.5mm CLOSED Smoothing #effect.setParameter("SmoothingMethod", "MORPHOLOGICAL_CLOSING") #effect.setParameter("KernelSizeMm", 1.5) #effect.self().onApply # Create Closed Surface Representation segmentationNode.CreateClosedSurfaceRepresentation() # Export Segmentation to Model Node shNode = slicer.mrmlScene.GetSubjectHierarchyNode() exportFolderItemId = shNode.CreateFolderItem(shNode.GetSceneItemID(), "Segments") slicer.modules.segmentations.logic().ExportAllSegmentsToModels( segmentationNode, exportFolderItemId) segmentID = segmentationNode.GetSegmentation().GetNthSegmentID(0) surfaceMesh = segmentationNode.GetClosedSurfaceInternalRepresentation( segmentID) # Decimate Model decimator = vtk.vtkDecimatePro() decimator.SplittingOff() decimator.PreserveTopologyOn() decimator.SetTargetReduction(0.95) decimator.SetInputData(surfaceMesh) decimator.Update() surfaceMesh = decimator.GetOutput() # Smooth the Model smoothingFactor = 0.5 smoother = vtk.vtkWindowedSincPolyDataFilter() smoother.SetInputData(surfaceMesh) smoother.SetNumberOfIterations(50) smoother.SetPassBand(pow(10.0, -4.0 * smoothingFactor)) smoother.BoundarySmoothingOff() smoother.FeatureEdgeSmoothingOff() smoother.NonManifoldSmoothingOn() smoother.NormalizeCoordinatesOn() smoother.Update() surfaceMesh = smoother.GetOutput() # Clean up Model cleaner = vtk.vtkCleanPolyData() #cleaner.PointMergingOff() #cleaner.ConvertLinesToPointsOn() #cleaner.ConvertPolysToLinesOn() #cleaner.ConvertStripsToPolysOn() cleaner.SetInputData(surfaceMesh) cleaner.Update() surfaceMesh = cleaner.GetOutput() # Write to OBJ File outputFileName = outputDir + "segmentation.obj" writer = vtk.vtkOBJWriter() writer.SetFileName(outputFileName) writer.SetInputData(surfaceMesh) writer.Update() # Clean up segmentEditorWidget = None slicer.mrmlScene.RemoveNode(segmentEditorNode)
def cornerstoneannotationsToSlicerSegments(self, masterVolume, auth_token, jobid, projectjson, useremail): print('cornerstoneannotationsToSlicerSegments()', flush=True) # voxels = slicer.util.arrayFromVolume(masterVolume) ijkToRasMatrix = vtk.vtkMatrix4x4() masterVolume.GetIJKToRASMatrix(ijkToRasMatrix) imageData = masterVolume.GetImageData() transformVolumeRasToRas = vtk.vtkGeneralTransform() slicer.vtkMRMLTransformNode.GetTransformBetweenNodes( masterVolume.GetParentTransformNode(), None, transformVolumeRasToRas) tdioClientAPI = TDIOClientAPI() instanceindex = -1 contoursmap = {} colorsmap = {} segmentsmap = {} seriesjson = projectjson['images']['seriesList'][0] for instance in seriesjson['instanceList']: instanceindex = instanceindex + 1 instanceid = instance['instanceId'] response = tdioClientAPI.getcornerstoneannotation( 'https://app.trainingdata.io', auth_token, jobid, seriesjson['seriesId'], instanceid, useremail) cannotations = [] cannotations = response if len(cannotations) == 0: continue jsonobj = json.loads(cannotations[0]['jsonstring']) annotations = jsonobj['annotations'] print('instanceid1', instanceid, len(annotations)) for annotation in annotations: # print(annotation) toolData = annotation['toolData'] toolType = annotation['toolName'] color = annotation['selectedColor'] color = TDIOUtils.hex_to_rgb(annotation['selectedColor']) aclass = annotation['annotationClass'] label = ''.join(filter(lambda x: x in printable, aclass)) for data in toolData: if not not data['color']: if len(data['color']) == 0: continue color = TDIOUtils.hex_to_rgb(data['color']) if toolType == 'freehand': if label not in contoursmap: contoursmap[label] = [] points = getPointsFromPolygon(data) # points = [[10,10], [110,10], [110,110], [10, 110]] contour = [] for p in points: try: ras = self.ijkToRas( ijkToRasMatrix, transformVolumeRasToRas, p[0], p[1], instanceindex) # print('ras:', ras) contour.append( np.array([p[0], p[1], instanceindex], dtype=(np.int))) except Exception as ex: print(ex) contoursmap[label].append(contour) colorsmap[label] = color segmentationNode = slicer.mrmlScene.AddNewNodeByClass( "vtkMRMLSegmentationNode") segmentationNode.CreateDefaultDisplayNodes() segmentationNode.SetReferenceImageGeometryParameterFromVolumeNode( masterVolume) #I tried with and without this line labelinginterface = projectjson['labelinginterface'] if 'tools' in labelinginterface and len( labelinginterface['tools']) > 0: for tool in labelinginterface['tools']: name = tool['name'] color = TDIOUtils.hex_to_rgb(tool['color']) print(color) segment = slicer.vtkSegment() segment.SetName(name) segment.SetColor(color) segmentsmap[name] = segment # print(colorsmap, contoursmap) for key in contoursmap: segmentName = key segment = segmentsmap[key] contours = contoursmap[key] self.addContoursToSegment(ijkToRasMatrix, transformVolumeRasToRas, segment, contours, segmentName) for key in segmentsmap: segment = segmentsmap[key] segmentationNode.GetSegmentation().AddSegment(segment)