Overlapping Segmentions Export to NIFTI

Hi,

Apologies if this has been answered elsewhere, but my search can only find answers regarding NON-overlapping segmentations.

I have segmented a DICOM image and have 4 different segmentations. These all overlap.

I need to export as NIFTI (as that is the only filetype compatible with my colleagues Radiomics software). If I “export to file” as NIFTI some data is obviously lost due to the overlap. I have been able to compensate for this by hiding all layers but one, exporting to file, change to another layer, export to file and repeat for the 4 layers.

Is it possible to reduce the number of steps, i.e. export each segmentation to a separate NIFTI file rather than hiding/unhiding each one and manually saving?

Many thanks in advance,

Pete

Nifti is a very rigid neuroimaging file format. There is no clean way of encoding 4D segmentations and metadata in it. On the other hand, nrrd is a simple, much more flexible, general-purpose file format that can store all the necessary metadata. Unless there is a very very strong community pressure to improve Nifti support (and preferably accompanied by improvement of the Nifti file format), we will probably not invest time into it.

Since .nrrd file readers are available in all development environments (and due to simplicity of the file format, parsers can be implemented with very small effort, if additional dependencies to existing nrrd readers are unacceptable), it should be no problem to add nrrd support to your colleagues radiomics software. What programming language that software is implemented in and what libraries it is using already?

You can of course write a Python script that saves each segment in a separate volume (it would probably take 3-4 lines of code). You can find all the code pieces that you need in the Slicer script repository.

Thanks for your helpful and explanatory answer. I believe it is custom software based off Matlab analysis.

Unfortunately I think the python scripting is probably beyond my skills but I will take a look.

There are several nrrd file readers for Matlab. For example, you can try this one (used by SlicerMatlabBridge): nrrdread.m

Thanks for that suggestion I will pass it on to my colleague.

I have had a go with the python code and have been partially successful but get a syntax error for final line:

segmentationNode = getNode('Segmentation')
segmentNames = ["Single", "Multi"]
segmentIds = vtk.vtkStringArray()
for segmentName in segmentNames:
    segmentId = segmentationNode.GetSegmentation().GetSegmentIdBySegmentName(segmentName)
    segmentIds.InsertNextValue(segmentId)
slicer.vtkSlicerSegmentationsModuleLogic.ExportSegmentsToLabelmapNode(segmentationNode, segmentIds, labelmapVolumeNode, referenceVolumeNode)

For clarity my segmentation is called “Segmentation” and it contains segments named “Single”, “Multi”. My ultimate goal is to export each segment as a separate nifti (nii.gz) as they do overlap.

Is anyone able to point to what I am doing wrong? Do I need to create a labelmapVolumeNode first?

Many thanks in advance,

Pete

What was the error message?

This was all that was listed in the error console:

 File "<console>", line 4
    slicer.vtkSlicerSegmentationsModuleLogic.ExportSegmentsToLabelmapNode(segmentationNode, segmentIds, labelmapVolumeNode, referenceVolumeNode)
         ^
SyntaxError: invalid syntax

This works for me with a recent Slicer Preview Release:

segmentationNode = getNode('Segmentation')
labelmapVolumeNode = slicer.mrmlScene.AddNewNodeByClass('vtkMRMLLabelMapVolumeNode')
referenceVolumeNode = slicer.mrmlScene.GetFirstNodeByClass('vtkMRMLScalarVolumeNode')
segmentNames = ["Segment_1", "Segment_2"]
for segmentName in segmentNames:
    segmentIds = vtk.vtkStringArray()
    segmentId = segmentationNode.GetSegmentation().GetSegmentIdBySegmentName(segmentName)
    segmentIds.InsertNextValue(segmentId)
    slicer.vtkSlicerSegmentationsModuleLogic.ExportSegmentsToLabelmapNode(segmentationNode, segmentIds, labelmapVolumeNode, referenceVolumeNode)
1 Like

Many thanks, that does export to a new Labelmap, but it is still a combined one. I am trying to get it to export each segment (single and multi) to their own Labelmap so I can then export them easily as separate files. Sorry if I am being stupid.

You need to add a line in the for loop after the ExportSegmentsToLabelmapNode... line to write to file, or use a method that writes selected segments to file directly using ExportSegmentsBinaryLabelmapRepresentationToFiles method.

1 Like

Great, that was a big help. I have it exporting to file using ExportSegmentsBinaryLabelmapRepresentationToFiles as you suggested. It always saves the file as Segmentation.nii.gz. Is there a way to specify the file name, so I can run the script more than once to export individual segments as their segment name or ID? Meaning it won’t overwrite itself

extension = "nii.gz"
useCompression = "true"
destinationFolder = "/Users/pete/Public/Test"
segmentationNode = getNode('Segmentation')
segmentNames = ["Mask"]
segmentIds = vtk.vtkStringArray()
for segmentName in segmentNames:
    segmentId = segmentationNode.GetSegmentation().GetSegmentIdBySegmentName(segmentName)
    segmentIds.InsertNextValue(segmentId)
slicer.vtkSlicerSegmentationsModuleLogic.ExportSegmentsBinaryLabelmapRepresentationToFiles(destinationFolder, segmentationNode, segmentIds, extension, useCompression)

Filename is the same as the segmentation node name, so if you want to change the filename then you can temporarily rename the segmentation node.

Great idea, working perfectly now. Thanks so much for your extensive help. In case anyone else wants to do something similar, here is my final code:

# ***** THE FINAL SCRIPT *****

# Required to have 3 segments - "Mask", "Single", "Multi"

# Save Image data as Image Data.nii.gz

node = slicer.mrmlScene.GetFirstNodeByClass('vtkMRMLScalarVolumeNode')
file_path = "/Users/pete/OneDrive/ImageData.nii.gz"
properties = {'useCompression': 1}; #use compression
slicer.util.saveNode(node, file_path, properties)

# Get segmentation called "Segmentation" and rename to "Single"

segmentationNode = getNode('Segmentation')
segmentationNode.GetName()
segmentationNode.SetName('Single')

# get segment "Single" and export to Single.nii.gz

extension = "nii.gz"
useCompression = "true"
destinationFolder = "/Users/pete/OneDrive"
segmentationNode = getNode('Single')
segmentNames = ["Single"]
segmentIds = vtk.vtkStringArray()
for segmentName in segmentNames:
    segmentId = segmentationNode.GetSegmentation().GetSegmentIdBySegmentName(segmentName)
    segmentIds.InsertNextValue(segmentId)
    slicer.vtkSlicerSegmentationsModuleLogic.ExportSegmentsBinaryLabelmapRepresentationToFiles(destinationFolder, segmentationNode, segmentIds, extension, useCompression)

# Get segmentation called "Single" and rename to "Multi"

segmentationNode = getNode('Single')
segmentationNode.GetName()
segmentationNode.SetName('Multi')

# get segment "Multi" and export to Multi.nii.gz

segmentationNode = getNode('Multi')
segmentNames = ["Multi"]
segmentIds = vtk.vtkStringArray()
for segmentName in segmentNames:
    segmentId = segmentationNode.GetSegmentation().GetSegmentIdBySegmentName(segmentName)
    segmentIds.InsertNextValue(segmentId)
    slicer.vtkSlicerSegmentationsModuleLogic.ExportSegmentsBinaryLabelmapRepresentationToFiles(destinationFolder, segmentationNode, segmentIds, extension, useCompression)

# Get segmentation called "Multi" and rename to "Mask"

segmentationNode = getNode('Multi')
segmentationNode.GetName()
segmentationNode.SetName('Mask')

# get segment "Mask" and export to Mask.nii.gz

segmentationNode = getNode('Mask')
segmentNames = ["Mask"]
segmentIds = vtk.vtkStringArray()
for segmentName in segmentNames:
    segmentId = segmentationNode.GetSegmentation().GetSegmentIdBySegmentName(segmentName)
    segmentIds.InsertNextValue(segmentId)
    slicer.vtkSlicerSegmentationsModuleLogic.ExportSegmentsBinaryLabelmapRepresentationToFiles(destinationFolder, segmentationNode, segmentIds, extension, useCompression)

# Get segmentation called "Mask" and rename to "Segmentation"

segmentationNode = getNode('Mask')
segmentationNode.GetName()
segmentationNode.SetName('Segmentation')
segmentationNode.GetName()
2 Likes

Thanks Pete,

fed that into ChatGPT and maybe it is interesting what the bot said:

ChatGPT:

I removed the unnecessary lines of code where the segmentation node
is re-assigned to a new node with the same name and made some other
minor changes to improve the readability of the script.
Let me know if you have any questions!

# ***** THE FINAL SCRIPT *****

# Required to have 3 segments - "Mask", "Single", "Multi"

# Save Image data as Image Data.nii.gz

node = slicer.mrmlScene.GetFirstNodeByClass('vtkMRMLScalarVolumeNode')
file_path = "/Users/pete/OneDrive/ImageData.nii.gz"
properties = {'useCompression': 1} # use compression
slicer.util.saveNode(node, file_path, properties)

# Get segmentation called "Segmentation"

segmentationNode = getNode('Segmentation')

# Rename segmentation to "Single"
segmentationNode.SetName('Single')

# get segment "Single" and export to Single.nii.gz

extension = "nii.gz"
useCompression = "true"
destinationFolder = "/Users/pete/OneDrive"
segmentNames = ["Single"]
segmentIds = vtk.vtkStringArray()
for segmentName in segmentNames:
    segmentId = segmentationNode.GetSegmentation().GetSegmentIdBySegmentName(segmentName)
    segmentIds.InsertNextValue(segmentId)
slicer.vtkSlicerSegmentationsModuleLogic.ExportSegmentsBinaryLabelmapRepresentationToFiles(destinationFolder, segmentationNode, segmentIds, extension, useCompression)

# Rename segmentation to "Multi"
segmentationNode.SetName('Multi')

# get segment "Multi" and export to Multi.nii.gz

segmentNames = ["Multi"]
segmentIds = vtk.vtkStringArray()
for segmentName in segmentNames:
    segmentId = segmentationNode.GetSegmentation().GetSegmentIdBySegmentName(segmentName)
    segmentIds.InsertNextValue(segmentId)
slicer.vtkSlicerSegmentationsModuleLogic.ExportSegmentsBinaryLabelmapRepresentationToFiles(destinationFolder, segmentationNode, segmentIds, extension, useCompression)

# Rename segmentation to "Mask"
segmentationNode.SetName('Mask')

# get segment "Mask" and export to Mask.nii.gz

segmentNames = ["Mask"]
segmentIds = vtk.vtkStringArray()
for segmentName in segmentNames:
    segmentId = segmentationNode.GetSegmentation().GetSegmentIdBySegmentName(segmentName)
    segmentIds.InsertNextValue(segmentId)
slicer.vtkSlicerSegmentationsModuleLogic.ExportSegmentsBinaryLabelmapRepresentationToFiles(destinationFolder, segmentationNode, segmentIds, extension, useCompression)

# Rename segmentation to "Segmentation"
segmentationNode.SetName('Segmentation')