How to save .seg.nrrd with script?

Hi,
I am trying to save a segmentation node using the slicer.util.SaveNode where the node is a vtkMRMLSegmentationNode but I get this weird error even though it appears to save the segmentation. it might be a bug somewhere else, but I can’t quite figure it out:

Saved node case4_ventricle in /home/sansomk/caseFiles/mri/VWI_proj/case4/image_vols/case4_ventricle.seg.nrrd
Warning: In /work/Stable/Slicer-4100/Libs/MRML/Core/vtkMRMLSegmentationNode.cxx, line 599
vtkMRMLSegmentationNode (0x86c6270): GenerateMergedLabelmap: Segment not found: vtkMRMLSegmentationNode1

Bad table range: [0, -1]

GetOutputImageData: Lookup table exists but empty!

Bad table range: [0, -1]

GetOutputImageData: Lookup table exists but empty!

error: [/home/sansomk/tools/Slicer-4.10.0-linux-amd64/bin/SlicerApp-real] exit abnormally - Report the problem.

so the problem is that it fails on:
slicer.vtkSlicerSegmentationsModuleLogic.ExportSegmentsToLabelmapNode(segmentationNode, segmentIDs, maskVolumeNode, inputVolumeNode)

I think maybe the problem is that segmentsIDs should be a array of each segment string…?

so this was the solution:

segmentIDs = vtk.vtkStringArray()
for segID in range(segmentationNode.GetSegmentation().GetNumberOfSegments()):
    segmentIDs.InsertNextValue(segmentationNode.GetSegmentation().GetNthSegmentID(segID))

Thanks for reporting the problem.

Using Slicer (revision 3699716), after loading MRHead sample data and creating two segments, then using slicer.util.saveNode, I am not able to reproduce the problem.

Could you provide more details about the workflow leading to this error ?

Which exact version of Slicer are you using ?

>>> slicer.util.saveNode(slicer.mrmlScene.GetNodeByID("vtkMRMLSegmentationNode1"), "/tmp/foo.seg.nrrd")
True

image

Looking at the header of the saved nrrd file also confirms the segments are saved:

$ head -n 30 /tmp/foo.seg.nrrd
NRRD0005
# Complete NRRD file format specification at:
# http://teem.sourceforge.net/nrrd/format.html
type: unsigned char
dimension: 4
space: right-anterior-superior
sizes: 2 74 1 116
space directions: none (0,-1,0) (-0,0,-1) (1.2999954223632799,-0,0)
kinds: list domain domain domain
encoding: gzip
space origin: (-86.6448974609375,23.928604125976989,-10.214302062987983)
measurement frame: (1,0,0) (0,1,0) (0,0,1)
Segment0_Color:=0.501961 0.682353 0.501961
Segment0_ColorAutoGenerated:=1
Segment0_Extent:=0 52 0 0 76 115
Segment0_ID:=Segment_1
Segment0_Name:=Segment_1
Segment0_NameAutoGenerated:=1
Segment0_Tags:=TerminologyEntry:Segmentation category and type - 3D Slicer General Anatomy list~SRT^T-D0050^Tissue~SRT^T-D0050^Tissue~^^~Anatomic codes - DICOM master list~^^~^^|
Segment1_Color:=0.945098 0.839216 0.568627
Segment1_ColorAutoGenerated:=1
Segment1_Extent:=3 73 0 0 0 65
Segment1_ID:=Segment_2
Segment1_Name:=Segment_2
Segment1_NameAutoGenerated:=1
Segment1_Tags:=TerminologyEntry:Segmentation category and type - 3D Slicer General Anatomy list~SRT^T-D0050^Tissue~SRT^T-D0050^Tissue~^^~Anatomic codes - DICOM master list~^^~^^|
Segmentation_ContainedRepresentationNames:=Binary labelmap|Closed surface|
Segmentation_ConversionParameters:=Compute surface normals|1|Compute surface normals. 1 (default) = surface normals are computed. 0 = surface normals are not computed (slightly faster but produces less smooth surface display).&Crop to reference image geometry|0|Crop the model to the extent of reference geometry. 0 (default) = created labelmap will contain the entire model. 1 = created labelmap extent will be within reference image extent.&Decimation factor|0.0|Desired reduction in the total number of polygons. Range: 0.0 (no decimation) to 1.0 (as much simplification as possible). Value of 0.8 typically reduces data set size by 80% without losing too much details.&Fractional labelmap oversampling factor|1|Determines the oversampling of the reference image geometry. All segments are oversampled with the same value (value of 1 means no oversampling).&Oversampling factor|1|Determines the oversampling of the reference image geometry. If it's a number, then all segments are oversampled with the same value (value of 1 means no oversampling). If it has the value "A", then automatic oversampling is calculated.&Reference image geometry|0;0;1.29999542236328;-86.6448974609375;-1;0;0;133.928604125977;0;-1;0;116.785697937012;0;0;0;1;0;255;0;255;0;129;|Image geometry description string determining the geometry of the labelmap that is created in course of conversion. Can be copied from a volume, using the button.&Smoothing factor|0.5|Smoothing factor. Range: 0.0 (no smoothing) to 1.0 (strong smoothing).&Threshold fraction|0.5|Determines the threshold that the closed surface is created at as a fractional value between 0 and 1.&
Segmentation_MasterRepresentation:=Binary labelmap
Segmentation_ReferenceImageExtentOffset:=110 127 0

Version 4.10

What I determined is that I was passing the segmentationNode instead of a list of the segments that make up the segmentationNode.
Does that make sense? I am using a modified version of the slicer case iterator module.

You can use slicer.vtkSlicerSegmentationsModuleLogic.ExportSegmentsToLabelmapNode method if you want to export selected segments.

To export all segments, use slicer.vtkSlicerSegmentationsModuleLogic.ExportAllSegmentsToLabelmapNode method.