Cannot load nrrd segmentations created with Simple ITK

I’m trying to create a segmentation (externally) in Python and then import it into Slicer through the data module, but Slicer keeps crashing. As far as I can tell, this seems to be related to how SimpleITK converts NumPy array to Images, but I don’t know what to do differently to make it work with Slicer.

For example, given a segmentation NRRD saved from Slicer, Segmentation.seg.nrrd, the following code works:

import SimpleITK as sitk
seg_vol = sitk.ReadImage(DATA_DIR + 'Segmentation.seg.nrrd')
writer = sitk.ImageFileWriter()
writer.Execute(seg_vol, DATA_DIR + 'Segmentation_v2.seg.nrrd', True)

… and I import Segmentation_v2.seg.nrrd into Slicer without problems.

However, if I convert the sitk image to a Numpy array and back again…

seg_vol = sitk.ReadImage(DATA_DIR + 'Segmentation.seg.nrrd')

# there and back again:
seg_nda = sitk.GetArrayFromImage(seg_vol)
seg_reverse = sitk.GetImageFromArray(seg_nda)
seg_reverse.CopyInformation(seg_vol)

writer = sitk.ImageFileWriter()
writer.Execute(seg_vol, DATA_DIR + 'Segmentation_v3.seg.nrrd', True)

… then Slicer crashes when I try to import the segmentation, and I get a bunch of nasty error messages in my terminal:

Warning: In /Volumes/Dashboards/Preview/Slicer-0/Libs/MRML/Core/vtkMRMLSegmentationStorageNode.cxx, line 586
vtkMRMLSegmentationStorageNode (0x7faecf985ed0): ReferenceImageExtentOffset attribute was not found in NRRD segmentation file. Assume no offset.

Warning: In /Volumes/Dashboards/Preview/Slicer-0/Libs/MRML/Core/vtkMRMLSegmentationStorageNode.cxx, line 663
vtkMRMLSegmentationStorageNode (0x7faecf985ed0): Segment ID is missing for segment 0 adding segment with ID: SegmentAuto

Warning: In /Volumes/Dashboards/Preview/Slicer-0/Libs/MRML/Core/vtkMRMLSegmentationStorageNode.cxx, line 674
vtkMRMLSegmentationStorageNode (0x7faecf985ed0): Segment name is missing for segment 0

Warning: In /Volumes/Dashboards/Preview/Slicer-0/Libs/MRML/Core/vtkMRMLSegmentationStorageNode.cxx, line 724
vtkMRMLSegmentationStorageNode (0x7faecf985ed0): Segment extent is missing for segment 0

Segmentation fault: 11

Am I missing something obvious? Any solutions/suggestions welcome.

Segmentation is stored as a 4D volume (to allow overlap between segments) and contain additional metadata (segment names, colors, etc).

If you have a labelmap in a 3D volume, with each segment represented by a different label value, then probably the easiest is to load that the file a labelmap volume and import it into segmentation:

segmentationNode = slicer.mrmlScene.AddNewNodeByClass('vtkMRMLSegmentationNode')
[success, labelmapVolumeNode] = slicer.util.loadLabelVolume('c:/Users/abc/Documents/SomeLabelmap.nrrd', returnNode=True)
slicer.modules.segmentations.logic().ImportLabelmapToSegmentationNode(labelmapVolumeNode, segmentationNode)
slicer.mrmlScene.RemoveNode(labelmapVolumeNode)
2 Likes

I have exactly the same issue with my segmentations.
If I save it like this (without .seg exstention):

writer = sitk.ImageFileWriter()
writer.Execute(seg_vol, 'Segmentation.nrrd', True)

then if I load it manually in Slicer, first, I need to load it as “Volume” and import it further as “Segmentation” in Segmentations module. However, if I use CaseIterator Module then it is done automatically.

Is there any way to embed the code snipped from above into my SimpleITK pipeline and use it outside Slicer software?
Or, to put it differently, is it possible to install the following packages in my python environment and then use it simply like that: import vtk, qt, ctk, slicer?
Am I missing something?

If you use a recent Slicer version, then all you need to do is save the segmentation using .seg.nrrd extension. Slicer will automatically load it as a segmentation. If you want to specify segment names and colors then you can add that information as custom fields in the header.

All the custom fields are specified here. You can find an example of reading segmentation custom fields from plain Python (using pynrrd, without any Slicer dependency).You could implement writing of custom fields similarly.

Slicer modules rely on having an application that provides a lot of features that the plain Python executable does not. Some libraries could be Python-wrapped and used without a Slicer application (in any Python interpreter). We might offer this in the future, but it is not high priority for us since you can install any Python packages in Slicer’s Python environment (pip_install('...')) and use it from there, along with everything else that Slicer provides. You can use Slicer’s Python environment using Slicer GUI, console, or Jupyter notebooks.