def load(self,loadable): """ Load the DICOM SEG object """ print('DICOM SEG load()') labelNodes = vtk.vtkCollection() uid = None try: uid = loadable.uid print ('in load(): uid = ', uid) except AttributeError: return False res = False # make the output directory outputDir = os.path.join(slicer.app.temporaryPath,"QIICR","SEG",loadable.uid) try: os.makedirs(outputDir) except: pass # produces output label map files, one per segment, and information files with # the terminology information for each segment segFileName = slicer.dicomDatabase.fileForInstance(uid) if segFileName is None: print 'Failed to get the filename from the DICOM database for ', uid return False parameters = { "inputSEGFileName": segFileName, "outputDirName": outputDir, } seg2nrrd = None try: seg2nrrd = slicer.modules.seg2nrrd except AttributeError: print 'Unable to find CLI module SEG2NRRD, unable to load DICOM Segmentation object' return False cliNode = None cliNode = slicer.cli.run(seg2nrrd, cliNode, parameters, wait_for_completion=True) if cliNode.GetStatusString() != 'Completed': print 'SEG2NRRD did not complete successfully, unable to load DICOM Segmentation' return False # create a new color node to be set up with the colors in these segments colorLogic = slicer.modules.colors.logic() segmentationColorNode = slicer.vtkMRMLColorTableNode() segmentationColorNode.SetName(loadable.name) segmentationColorNode.SetTypeToUser(); segmentationColorNode.SetHideFromEditors(0) segmentationColorNode.SetAttribute("Category", "File") segmentationColorNode.NamesInitialisedOff() slicer.mrmlScene.AddNode(segmentationColorNode) # also create a new terminology and associate it with this color node colorLogic.CreateNewTerminology(segmentationColorNode.GetName()) import glob numberOfSegments = len(glob.glob(os.path.join(outputDir,'*.nrrd'))) # resize the color table to include the segments plus 0 for the background print ('number of segments = ',numberOfSegments) segmentationColorNode.SetNumberOfColors(numberOfSegments + 1) segmentationColorNode.SetColor(0, 'background', 0.0, 0.0, 0.0, 0.0) seriesName = self.referencedSeriesName(loadable) segmentNodes = [] for segmentId in range(numberOfSegments): # load each of the segments' segmentations # Initialize color and terminology from .info file # See SEG2NRRD.cxx and EncodeSEG.cxx for how it's written. # Format of the .info file (no leading spaces, labelNum, RGBColor, SegmentedPropertyCategory and # SegmentedPropertyCategory are required): # labelNum;RGB:R,G,B;SegmentedPropertyCategory:code,scheme,meaning;SegmentedPropertyType:code,scheme,meaning;SegmentedPropertyTypeModifier:code,scheme,meaning;AnatomicRegion:code,scheme,meaning;AnatomicRegionModifier:code,scheme,meaning # R, G, B are 0-255 in file, but mapped to 0-1 for use in color node # set defaults in case of missing fields, modifiers are optional rgb = (0., 0., 0.) colorIndex = segmentId + 1 categoryCode = 'T-D0050' categoryCodingScheme = 'SRT' categoryCodeMeaning = 'Tissue' typeCode = 'T-D0050' typeCodeMeaning = 'Tissue' typeCodingScheme = 'SRT' typeModCode = '' typeModCodingScheme = '' typeModCodeMeaning = '' regionCode = 'T-D0010' regionCodingScheme = 'SRT' regionCodeMeaning = 'Entire Body' regionModCode = '' regionModCodingScheme = '' regionModCodeMeaning = '' infoFileName = os.path.join(outputDir,str(segmentId+1)+".info") print ('Parsing info file', infoFileName) with open(infoFileName, 'r') as infoFile: for line in infoFile: line = line.rstrip() if len(line) == 0: # empty line continue terms = line.split(';') for term in terms: # label number is the first thing, no key if len(term.split(':')) == 1: colorIndex = int(term) else: key = term.split(':')[0] if key == "RGB": rgb255 = term.split(':')[1].split(',') rgb = map(lambda c: float(c) / 255., rgb255) elif key == "AnatomicRegion": # Get the Region information region = term.split(':')[1] # use partition to deal with any commas in the meaning regionCode, sep, regionCodingSchemeAndCodeMeaning = region.partition(',') regionCodingScheme, sep, regionCodeMeaning = regionCodingSchemeAndCodeMeaning.partition(',') elif key == "AnatomicRegionModifier": regionMod = term.split(':')[1] regionModCode, sep, regionModCodingSchemeAndCodeMeaning = regionMod.partition(',') regionModCodingScheme, sep, regionModCodeMeaning = regionModCodingSchemeAndCodeMeaning.partition(',') elif key == "SegmentedPropertyCategory": # Get the Category information category = term.split(':')[1] categoryCode, sep, categoryCodingSchemeAndCodeMeaning = category.partition(',') categoryCodingScheme, sep, categoryCodeMeaning = categoryCodingSchemeAndCodeMeaning.partition(',') elif key == "SegmentedPropertyType": # Get the Type information types = term.split(':')[1] typeCode, sep, typeCodingSchemeAndCodeMeaning = types.partition(',') typeCodingScheme, sep, typeCodeMeaning = typeCodingSchemeAndCodeMeaning.partition(',') elif key == "SegmentedPropertyTypeModifier": typeMod = term.split(':')[1] typeModCode, sep, typeModCodingSchemeAndCodeMeaning = typeMod.partition(',') typeModCodingScheme, sep, typeModCodeMeaning = typeModCodingSchemeAndCodeMeaning.partition(',') # set the color name from the terminology colorName = typeCodeMeaning segmentationColorNode.SetColor(colorIndex, colorName, *rgb) colorLogic.AddTermToTerminology(segmentationColorNode.GetName(), colorIndex, categoryCode, categoryCodingScheme, categoryCodeMeaning, typeCode, typeCodingScheme, typeCodeMeaning, typeModCode, typeModCodingScheme, typeModCodeMeaning, regionCode, regionCodingScheme, regionCodeMeaning, regionModCode, regionModCodingScheme, regionModCodeMeaning) # end of processing a line of terminology infoFile.close() #TODO: Create logic class that both CLI and this plugin uses so that we don't need to have temporary NRRD files and labelmap nodes #if not hasattr(slicer.modules, 'segmentations'): # load the segmentation volume file and name it for the reference series and segment color labelFileName = os.path.join(outputDir,str(segmentId+1)+".nrrd") segmentName = seriesName + "-" + colorName + "-label" (success,labelNode) = slicer.util.loadLabelVolume(labelFileName, properties = {'name' : segmentName}, returnNode=True) segmentNodes.append(labelNode) # point the label node to the color node we're creating labelDisplayNode = labelNode.GetDisplayNode() if labelDisplayNode == None: print ('Warning: no label map display node for segment ',segmentId,', creating!') labelNode.CreateDefaultDisplayNodes() labelDisplayNode = labelNode.GetDisplayNode() labelDisplayNode.SetAndObserveColorNodeID(segmentationColorNode.GetID()) # TODO: initialize referenced UID (and segment number?) attribute(s) # create Subject hierarchy nodes for the loaded series self.addSeriesInSubjectHierarchy(loadable, labelNode) # create a combined (merge) label volume node (only if a segment was created) if labelNode: volumeLogic = slicer.modules.volumes.logic() mergeNode = volumeLogic.CloneVolume(labelNode, seriesName + "-label") combiner = slicer.vtkImageLabelCombine() for segmentNode in segmentNodes: combiner.SetInputConnection(0, mergeNode.GetImageDataConnection() ) combiner.SetInputConnection(1, segmentNode.GetImageDataConnection() ) combiner.Update() mergeNode.GetImageData().DeepCopy( combiner.GetOutput() ) for segmentNode in segmentNodes: segmentNode.Modified() # sets the MTime so the editor won't think they are older than mergeNode # display the mergeNode selectionNode = slicer.app.applicationLogic().GetSelectionNode() selectionNode.SetReferenceActiveLabelVolumeID( mergeNode.GetID() ) slicer.app.applicationLogic().PropagateVolumeSelection(0) # finalize the color node segmentationColorNode.NamesInitialisedOn() # TODO: the outputDir should be cleaned up if hasattr(slicer.modules, 'segmentations'): import vtkSlicerSegmentationsModuleLogic import vtkSlicerSegmentationsModuleMRML import vtkSegmentationCore segmentationNode = vtkSlicerSegmentationsModuleMRML.vtkMRMLSegmentationNode() segmentationNode.SetName(seriesName) segmentationNode.AddNodeReferenceID('colorNodeID', segmentationColorNode.GetID()) slicer.mrmlScene.AddNode(segmentationNode) segmentationDisplayNode = vtkSlicerSegmentationsModuleMRML.vtkMRMLSegmentationDisplayNode() segmentationNode.SetAndObserveDisplayNodeID(segmentationDisplayNode.GetID()) slicer.mrmlScene.AddNode(segmentationDisplayNode) segmentation = vtkSegmentationCore.vtkSegmentation() segmentation.SetMasterRepresentationName(vtkSegmentationCore.vtkSegmentationConverter.GetSegmentationBinaryLabelmapRepresentationName()) segmentationNode.SetAndObserveSegmentation(segmentation) self.addSeriesInSubjectHierarchy(loadable, segmentationNode) colorID = 1 for segmentNode in segmentNodes: segment = vtkSegmentationCore.vtkSegment() segment.SetName(segmentNode.GetName()) segmentColor = [0,0,0,0] segmentationColorNode.GetColor(colorID, segmentColor) segment.SetDefaultColor(segmentColor[0:3]) colorID += 1 #TODO: when the logic class is created, this will need to be changed logic = vtkSlicerSegmentationsModuleLogic.vtkSlicerSegmentationsModuleLogic() orientedImage = logic.CreateOrientedImageDataFromVolumeNode(segmentNode) segment.AddRepresentation(vtkSegmentationCore.vtkSegmentationConverter.GetSegmentationBinaryLabelmapRepresentationName(), orientedImage) segmentation.AddSegment(segment) segmentDisplayNode = segmentNode.GetDisplayNode() slicer.mrmlScene.RemoveNode(segmentDisplayNode) slicer.mrmlScene.RemoveNode(segmentNode) segmentation.CreateRepresentation(vtkSegmentationCore.vtkSegmentationConverter.GetSegmentationClosedSurfaceRepresentationName(), True) slicer.mrmlScene.RemoveNode(mergeNode) return True
def exportAsDICOMSEG(self, exportablesCollection): """Export the given node to a segmentation object and load it in the DICOM database This function was copied and modified from the EditUtil.py function of the same name in Slicer. """ import logging if hasattr(slicer.modules, 'segmentations'): exportable = exportablesCollection.GetItemAsObject(0) subjectHierarchyNode = slicer.mrmlScene.GetNodeByID(exportable.GetNodeID()) instanceUIDs = subjectHierarchyNode.GetAttribute("DICOM.ReferencedInstanceUIDs").split() if instanceUIDs == "": raise Exception("Editor master node does not have DICOM information") # get the list of source DICOM files inputDICOMImageFileNames = "" for instanceUID in instanceUIDs: inputDICOMImageFileNames += slicer.dicomDatabase.fileForInstance(instanceUID) + "," inputDICOMImageFileNames = inputDICOMImageFileNames[:-1] # strip last comma # save the per-structure volumes in the temp directory inputSegmentationsFileNames = "" import random # TODO: better way to generate temp file names? import vtkITK writer = vtkITK.vtkITKImageWriter() rasToIJKMatrix = vtk.vtkMatrix4x4() import vtkSegmentationCore import vtkSlicerSegmentationsModuleLogic logic = vtkSlicerSegmentationsModuleLogic.vtkSlicerSegmentationsModuleLogic() segmentationTransform = vtk.vtkMatrix4x4() segmentationNode = subjectHierarchyNode.GetAssociatedNode() mergedSegmentationImageData = segmentationNode.GetImageData() mergedSegmentationLabelmapNode = slicer.vtkMRMLLabelMapVolumeNode() segmentationNode.GetRASToIJKMatrix(rasToIJKMatrix) mergedSegmentationLabelmapNode.SetRASToIJKMatrix(rasToIJKMatrix) mergedSegmentationLabelmapNode.SetAndObserveImageData(mergedSegmentationImageData) mergedSegmentationOrientedImageData = logic.CreateOrientedImageDataFromVolumeNode(mergedSegmentationLabelmapNode) segmentation = segmentationNode.GetSegmentation() segmentIDs = vtk.vtkStringArray() segmentation.GetSegmentIDs(segmentIDs) segmentationName = segmentationNode.GetName() for i in range(0, segmentIDs.GetNumberOfValues()): segmentID = segmentIDs.GetValue(i) segment = segmentation.GetSegment(segmentID) segmentName = segment.GetName() structureName = segmentName[len(segmentationName)+1:-1*len('-label')] structureFileName = structureName + str(random.randint(0,vtk.VTK_INT_MAX)) + ".nrrd" filePath = os.path.join(slicer.app.temporaryPath, structureFileName) writer.SetFileName(filePath) segmentImageData = segment.GetRepresentation(vtkSegmentationCore.vtkSegmentationConverter.GetSegmentationBinaryLabelmapRepresentationName()) paddedImageData = vtkSegmentationCore.vtkOrientedImageData() vtkSegmentationCore.vtkOrientedImageDataResample.PadImageToContainImage(segmentImageData, mergedSegmentationOrientedImageData, paddedImageData) labelmapImageData = slicer.vtkMRMLLabelMapVolumeNode() logic.CreateLabelmapVolumeFromOrientedImageData(paddedImageData, labelmapImageData) writer.SetInputDataObject(labelmapImageData.GetImageData()) labelmapImageData.GetRASToIJKMatrix(rasToIJKMatrix) writer.SetRasToIJKMatrix(rasToIJKMatrix) logging.debug("Saving to %s..." % filePath) writer.Write() inputSegmentationsFileNames += filePath + "," inputSegmentationsFileNames = inputSegmentationsFileNames[:-1] # strip last comma # save the per-structure volumes label attributes colorNode = segmentationNode.GetNodeReference('colorNodeID') terminologyName = colorNode.GetAttribute("TerminologyName") colorLogic = slicer.modules.colors.logic() if not terminologyName or not colorLogic: raise Exception("No terminology or color logic - cannot export") inputLabelAttributesFileNames = "" for i in range(0, segmentIDs.GetNumberOfValues()): segmentID = segmentIDs.GetValue(i) segment = segmentation.GetSegment(segmentID) segmentName = segment.GetName() structureName = segmentName[len(segmentationName)+1:-1*len('-label')] labelIndex = colorNode.GetColorIndexByName( structureName ) rgbColor = [0,]*4 colorNode.GetColor(labelIndex, rgbColor) rgbColor = map(lambda e: e*255., rgbColor) # get the attributes and conver to format CodeValue,CodeMeaning,CodingSchemeDesignator # or empty strings if not defined propertyCategoryWithColons = colorLogic.GetSegmentedPropertyCategory(labelIndex, terminologyName) if propertyCategoryWithColons == '': logging.debug ('ERROR: no segmented property category found for label ',str(labelIndex)) # Try setting a default as this section is required propertyCategory = "C94970,NCIt,Reference Region" else: propertyCategory = propertyCategoryWithColons.replace(':',',') propertyTypeWithColons = colorLogic.GetSegmentedPropertyType(labelIndex, terminologyName) propertyType = propertyTypeWithColons.replace(':',',') propertyTypeModifierWithColons = colorLogic.GetSegmentedPropertyTypeModifier(labelIndex, terminologyName) propertyTypeModifier = propertyTypeModifierWithColons.replace(':',',') anatomicRegionWithColons = colorLogic.GetAnatomicRegion(labelIndex, terminologyName) anatomicRegion = anatomicRegionWithColons.replace(':',',') anatomicRegionModifierWithColons = colorLogic.GetAnatomicRegionModifier(labelIndex, terminologyName) anatomicRegionModifier = anatomicRegionModifierWithColons.replace(':',',') structureFileName = structureName + str(random.randint(0,vtk.VTK_INT_MAX)) + ".info" filePath = os.path.join(slicer.app.temporaryPath, structureFileName) # EncodeSEG is expecting a file of format: # labelNum;SegmentedPropertyCategory:codeValue,codeScheme,codeMeaning;SegmentedPropertyType:v,m,s etc attributes = "%d" % labelIndex attributes += ";SegmentedPropertyCategory:"+propertyCategory if propertyType != "": attributes += ";SegmentedPropertyType:" + propertyType if propertyTypeModifier != "": attributes += ";SegmentedPropertyTypeModifier:" + propertyTypeModifier if anatomicRegion != "": attributes += ";AnatomicRegion:" + anatomicRegion if anatomicRegionModifier != "": attributes += ";AnatomicRegionModifer:" + anatomicRegionModifier attributes += ";SegmentAlgorithmType:AUTOMATIC" attributes += ";SegmentAlgorithmName:SlicerSelfTest" attributes += ";RecommendedDisplayRGBValue:%g,%g,%g" % tuple(rgbColor[:-1]) fp = open(filePath, "w") fp.write(attributes) fp.close() logging.debug ("filePath: %s", filePath) logging.debug ("attributes: %s", attributes) inputLabelAttributesFileNames += filePath + "," inputLabelAttributesFileNames = inputLabelAttributesFileNames[:-1] # strip last comma''' try: user = os.environ['USER'] except KeyError: user = "******" segFileName = "editor_export.SEG" + str(random.randint(0,vtk.VTK_INT_MAX)) + ".dcm" segFilePath = os.path.join(slicer.app.temporaryPath, segFileName) # TODO: define a way to set parameters like description # TODO: determine a good series number automatically by looking in the database parameters = { "inputDICOMImageFileNames": inputDICOMImageFileNames, "inputSegmentationsFileNames": inputSegmentationsFileNames, "inputLabelAttributesFileNames": inputLabelAttributesFileNames, "readerId": user, "sessionId": "1", "timePointId": "1", "seriesDescription": "SlicerEditorSEGExport", "seriesNumber": "100", "instanceNumber": "1", "bodyPart": "HEAD", "algorithmDescriptionFileName": "Editor", "outputSEGFileName": segFilePath, "skipEmptySlices": False, "compress": False, } encodeSEG = slicer.modules.encodeseg cliNode = None cliNode = slicer.cli.run(encodeSEG, cliNode, parameters, delete_temporary_files=False) waitCount = 0 while cliNode.IsBusy() and waitCount < 20: slicer.util.delayDisplay( "Running SEG Encoding... %d" % waitCount, 1000 ) waitCount += 1 if cliNode.GetStatusString() != 'Completed': raise Exception("encodeSEG CLI did not complete cleanly") logging.info("Added segmentation to DICOM database (%s)", segFilePath) slicer.dicomDatabase.insert(segFilePath)
def exportAsDICOMSEG(self, exportablesCollection): """Export the given node to a segmentation object and load it in the DICOM database This function was copied and modified from the EditUtil.py function of the same name in Slicer. """ if hasattr(slicer.modules, 'segmentations'): exportable = exportablesCollection.GetItemAsObject(0) subjectHierarchyNode = slicer.mrmlScene.GetNodeByID( exportable.GetNodeID()) instanceUIDs = subjectHierarchyNode.GetAttribute( "DICOM.ReferencedInstanceUIDs").split() if instanceUIDs == "": raise Exception( "Editor master node does not have DICOM information") # get the list of source DICOM files inputDICOMImageFileNames = "" for instanceUID in instanceUIDs: inputDICOMImageFileNames += slicer.dicomDatabase.fileForInstance( instanceUID) + "," inputDICOMImageFileNames = inputDICOMImageFileNames[: -1] # strip last comma # save the per-structure volumes in the temp directory inputSegmentationsFileNames = "" import random # TODO: better way to generate temp file names? import vtkITK writer = vtkITK.vtkITKImageWriter() rasToIJKMatrix = vtk.vtkMatrix4x4() import vtkSegmentationCore import vtkSlicerSegmentationsModuleLogic logic = vtkSlicerSegmentationsModuleLogic.vtkSlicerSegmentationsModuleLogic( ) segmentationNode = subjectHierarchyNode.GetAssociatedNode() mergedSegmentationImageData = segmentationNode.GetImageData() mergedSegmentationLabelmapNode = slicer.vtkMRMLLabelMapVolumeNode() segmentationNode.GetRASToIJKMatrix(rasToIJKMatrix) mergedSegmentationLabelmapNode.SetRASToIJKMatrix(rasToIJKMatrix) mergedSegmentationLabelmapNode.SetAndObserveImageData( mergedSegmentationImageData) mergedSegmentationOrientedImageData = logic.CreateOrientedImageDataFromVolumeNode( mergedSegmentationLabelmapNode) segmentation = segmentationNode.GetSegmentation() segmentIDs = vtk.vtkStringArray() segmentation.GetSegmentIDs(segmentIDs) segmentationName = segmentationNode.GetName() for i in range(0, segmentIDs.GetNumberOfValues()): segmentID = segmentIDs.GetValue(i) segment = segmentation.GetSegment(segmentID) segmentName = segment.GetName() structureName = segmentName[len(segmentationName) + 1:-1 * len('-label')] structureFileName = structureName + str( random.randint(0, vtk.VTK_INT_MAX)) + ".nrrd" filePath = os.path.join(slicer.app.temporaryPath, structureFileName) writer.SetFileName(filePath) segmentImageData = segment.GetRepresentation( vtkSegmentationCore.vtkSegmentationConverter. GetSegmentationBinaryLabelmapRepresentationName()) paddedImageData = vtkSegmentationCore.vtkOrientedImageData() vtkSegmentationCore.vtkOrientedImageDataResample.PadImageToContainImage( segmentImageData, mergedSegmentationOrientedImageData, paddedImageData) labelmapImageData = slicer.vtkMRMLLabelMapVolumeNode() logic.CreateLabelmapVolumeFromOrientedImageData( paddedImageData, labelmapImageData) writer.SetInputDataObject(labelmapImageData.GetImageData()) labelmapImageData.GetRASToIJKMatrix(rasToIJKMatrix) writer.SetRasToIJKMatrix(rasToIJKMatrix) logging.debug("Saving to %s..." % filePath) writer.Write() inputSegmentationsFileNames += filePath + "," inputSegmentationsFileNames = inputSegmentationsFileNames[: -1] # strip last comma # save the per-structure volumes label attributes colorNode = segmentationNode.GetNodeReference('colorNodeID') terminologyName = colorNode.GetAttribute("TerminologyName") colorLogic = slicer.modules.colors.logic() if not terminologyName or not colorLogic: raise Exception( "No terminology or color logic - cannot export") inputLabelAttributesFileNames = "" for i in range(0, segmentIDs.GetNumberOfValues()): segmentID = segmentIDs.GetValue(i) segment = segmentation.GetSegment(segmentID) segmentName = segment.GetName() structureName = segmentName[len(segmentationName) + 1:-1 * len('-label')] labelIndex = colorNode.GetColorIndexByName(structureName) rgbColor = [ 0, ] * 4 colorNode.GetColor(labelIndex, rgbColor) rgbColor = map(lambda e: e * 255., rgbColor) # get the attributes and convert to format CodeValue,CodeMeaning,CodingSchemeDesignator # or empty strings if not defined propertyCategoryWithColons = colorLogic.GetSegmentedPropertyCategory( labelIndex, terminologyName) if propertyCategoryWithColons == '': logging.debug( 'ERROR: no segmented property category found for label ', str(labelIndex)) # Try setting a default as this section is required propertyCategory = "C94970,NCIt,Reference Region" else: propertyCategory = propertyCategoryWithColons.replace( ':', ',') propertyTypeWithColons = colorLogic.GetSegmentedPropertyType( labelIndex, terminologyName) propertyType = propertyTypeWithColons.replace(':', ',') propertyTypeModifierWithColons = colorLogic.GetSegmentedPropertyTypeModifier( labelIndex, terminologyName) propertyTypeModifier = propertyTypeModifierWithColons.replace( ':', ',') anatomicRegionWithColons = colorLogic.GetAnatomicRegion( labelIndex, terminologyName) anatomicRegion = anatomicRegionWithColons.replace(':', ',') anatomicRegionModifierWithColons = colorLogic.GetAnatomicRegionModifier( labelIndex, terminologyName) anatomicRegionModifier = anatomicRegionModifierWithColons.replace( ':', ',') structureFileName = structureName + str( random.randint(0, vtk.VTK_INT_MAX)) + ".info" filePath = os.path.join(slicer.app.temporaryPath, structureFileName) # EncodeSEG is expecting a file of format: # labelNum;SegmentedPropertyCategory:codeValue,codeScheme,codeMeaning;SegmentedPropertyType:v,m,s etc attributes = "%d" % labelIndex attributes += ";SegmentedPropertyCategory:" + propertyCategory if propertyType != "": attributes += ";SegmentedPropertyType:" + propertyType if propertyTypeModifier != "": attributes += ";SegmentedPropertyTypeModifier:" + propertyTypeModifier if anatomicRegion != "": attributes += ";AnatomicRegion:" + anatomicRegion if anatomicRegionModifier != "": attributes += ";AnatomicRegionModifier:" + anatomicRegionModifier attributes += ";SegmentAlgorithmType:AUTOMATIC" attributes += ";SegmentAlgorithmName:SlicerSelfTest" attributes += ";RecommendedDisplayRGBValue:%g,%g,%g" % tuple( rgbColor[:-1]) fp = open(filePath, "w") fp.write(attributes) fp.close() logging.debug("filePath: %s", filePath) logging.debug("attributes: %s", attributes) inputLabelAttributesFileNames += filePath + "," inputLabelAttributesFileNames = inputLabelAttributesFileNames[: -1] # strip last comma''' try: user = os.environ['USER'] except KeyError: user = "******" segFileName = "editor_export.SEG" + str( random.randint(0, vtk.VTK_INT_MAX)) + ".dcm" segFilePath = os.path.join(slicer.app.temporaryPath, segFileName) # TODO: define a way to set parameters like description # TODO: determine a good series number automatically by looking in the database parameters = { "inputDICOMImageFileNames": inputDICOMImageFileNames, "inputSegmentationsFileNames": inputSegmentationsFileNames, "inputLabelAttributesFileNames": inputLabelAttributesFileNames, "readerId": user, "sessionId": "1", "timePointId": "1", "seriesDescription": "SlicerEditorSEGExport", "seriesNumber": "100", "instanceNumber": "1", "bodyPart": "HEAD", "algorithmDescriptionFileName": "Editor", "outputSEGFileName": segFilePath, "skipEmptySlices": False, "compress": False, } encodeSEG = slicer.modules.encodeseg cliNode = None cliNode = slicer.cli.run(encodeSEG, cliNode, parameters, delete_temporary_files=False) waitCount = 0 while cliNode.IsBusy() and waitCount < 20: slicer.util.delayDisplay( "Running SEG Encoding... %d" % waitCount, 1000) waitCount += 1 if cliNode.GetStatusString() != 'Completed': raise Exception("encodeSEG CLI did not complete cleanly") logging.info("Added segmentation to DICOM database (%s)", segFilePath) slicer.dicomDatabase.insert(segFilePath)