# Converting .stl files to binary label maps in .nii format using Python

**URL:** <https://discourse.slicer.org/t/converting-stl-files-to-binary-label-maps-in-nii-format-using-python/13038>\
**Category:** Support\
**Tags:** segmentation, python, binarylabelmap, stl\
**Created:** [August 17, 2020, 8:29am UTC](https://discourse.slicer.org/t/converting-stl-files-to-binary-label-maps-in-nii-format-using-python/13038 "2020-08-17T08:29:34Z")\
**Posts on this page:** 13\
**Page:** 1

<div class="post-metadata">

**Author:** ![DC-3T](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/dc-3t/32/7786_2.png) [@DC-3T](https://discourse.slicer.org/u/DC-3T)\
**Post date:** [August 17, 2020, 8:29am UTC](https://discourse.slicer.org/t/converting-stl-files-to-binary-label-maps-in-nii-format-using-python/13038/1 "2020-08-17T08:29:34Z")

</div>

Dear all,

I hope you’re doing well. I’ve spent the last week or two struggling to convert a large number of .stl files (~1,000) drawn in 3D Slicer 4.10.2 into .nii binary label maps using Python. The .stl data were derived from segmentations drawn on Dixon MRI .nii data that I’m using as the reference volumes for the conversions. I spent some time working with the example code from the Wiki ([Documentation](https://www.slicer.org/wiki/Documentation/Nightly/ScriptRepository#Segmentations)), but with little success. Looking through the forum here I found some good tips (e.g. [Load a .stl file and save it to a binary label map](https://discourse.slicer.org/t/load-a-stl-file-and-save-it-to-a-binary-label-map-through/11315)), and I came up with the following script:

```auto
stl_list = sys.argv[2:] # Get list of .stl files
dixon_path = os.path.join(sys.argv[1], 'mDIXONvol.nii.gz')
dixonVolumeNode = slicer.util.loadVolume(dixon_path, returnNode=True)[1]

for stl_file_name in stl_list:
	t = time()

	# Extract abbreviated ROI name from .stl filename	
	stl_name = os.path.splitext(stl_file_name.split("_")[-1])[0]
	
	segmentation = slicer.util.loadSegmentation(stl_file_name, returnNode=True)[1]
	ids = vtk.vtkStringArray()
	segmentation.GetDisplayNode().GetVisibleSegmentIDs(ids)	

	outputLabelmapVolumeNode = slicer.mrmlScene.AddNewNodeByClass('vtkMRMLLabelMapVolumeNode')
	slicer.modules.segmentations.logic().ExportSegmentsToLabelmapNode(segmentation, ids, outputLabelmapVolumeNode, dixonVolumeNode)
	slicer.util.saveNode(outputLabelmapVolumeNode, os.path.join(cwd, stl_name + ".nii.gz"))
	print("Converted " + stl_name + ".stl to " + stl_name + ".nii in " + str(round(time() - t, 3)) + "s")
exit()

```

Unfortunately, this leads to blank .nii files (all zeros), which becomes apparent when I load the .nii labelmaps in the 3D Slicer GUI. I can’t figure out why this is happening. I do, however, get the following warning during processing:

```auto
CalculateOutputGeometry: No image geometry specified, default geometry is calculated (0.333381665360425;0;0;30.7908134460449;0;0.333381665360425;0;-72.2878036499023;0;0;0.333381665360425;-9.96676349639893;0;0;0;1;0;160;0;179;0;543;)

```

I’m not sure why this warning is appearing, given that I’m using the original reference volumes for the conversion. Could there be a coordinate system issue here? I’d really appreciate any insights you might be able to share here.

With gratitude,  
Donnie

---

<div class="post-metadata">

**Author:** ![lassoan](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/lassoan/32/13_2.png) [@lassoan](https://discourse.slicer.org/u/lassoan)\
**Post date:** [August 17, 2020, 12:54pm UTC](https://discourse.slicer.org/t/converting-stl-files-to-binary-label-maps-in-nii-format-using-python/13038/2 "2020-08-17T12:54:35Z")

</div>

The scripts are probably intended for latest Slicer Preview Release. Let us know if you have trouble making them work with that Slicer version.

---

<div class="post-metadata">

**Author:** ![DC-3T](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/dc-3t/32/7786_2.png) [@DC-3T](https://discourse.slicer.org/u/DC-3T)\
**Post date:** [August 18, 2020, 4:11pm UTC](https://discourse.slicer.org/t/converting-stl-files-to-binary-label-maps-in-nii-format-using-python/13038/3 "2020-08-18T16:11:04Z")

</div>

Thanks very much for the tip. Using Slicer 4.11 I’m still getting empty .nii volumes with the script above, but I’ll have another go at the code from the script repository and I’ll report back.

---

<div class="post-metadata">

**Author:** ![DC-3T](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/dc-3t/32/7786_2.png) [@DC-3T](https://discourse.slicer.org/u/DC-3T)\
**Post date:** [August 18, 2020, 4:25pm UTC](https://discourse.slicer.org/t/converting-stl-files-to-binary-label-maps-in-nii-format-using-python/13038/4 "2020-08-18T16:25:25Z")

</div>

Just to give some helpful context, using the ‘Model to LabelMap’ tool in the GUI produces the desired results, so the underlying data appear to be OK.

 ![image](https://us1.discourse-cdn.com/flex002/uploads/slicer/original/3X/8/1/8196103add5d7cc525a91ba4d7fc24248c3a3581.jpeg)

---

<div class="post-metadata">

**Author:** ![lassoan](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/lassoan/32/13_2.png) [@lassoan](https://discourse.slicer.org/u/lassoan)\
**Post date:** [August 19, 2020, 2:01am UTC](https://discourse.slicer.org/t/converting-stl-files-to-binary-label-maps-in-nii-format-using-python/13038/5 "2020-08-19T02:01:47Z")

</div>

This works well for me:

```auto
stl_file_name = ...
output_file_name = ...
reference_volume_path = ...

referenceVolumeNode = slicer.util.loadVolume(reference_volume_path)
segmentationNode = slicer.util.loadSegmentation(stl_file_name)
outputLabelmapVolumeNode = slicer.mrmlScene.AddNewNodeByClass('vtkMRMLLabelMapVolumeNode')
slicer.modules.segmentations.logic().ExportVisibleSegmentsToLabelmapNode(segmentationNode, outputLabelmapVolumeNode, referenceVolumeNode)
slicer.util.saveNode(outputLabelmapVolumeNode, output_file_name)

```

Try this and if it works for you, too, then start modifying it line-by-line to see where it goes wrong.

---

<div class="post-metadata">

**Author:** ![DC-3T](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/dc-3t/32/7786_2.png) [@DC-3T](https://discourse.slicer.org/u/DC-3T)\
**Post date:** [August 19, 2020, 10:17am UTC](https://discourse.slicer.org/t/converting-stl-files-to-binary-label-maps-in-nii-format-using-python/13038/6 "2020-08-19T10:17:50Z")

</div>

Thanks very much for the code. I gave it a try, and I’m still getting the following message: “CalculateOutputGeometry: No image geometry specified, default geometry is calculated”. The output volume is still just an array of zeros as well. I’m not sure why this happens, and I’ve confirmed that the reference volumes and models are all loaded correctly…

I was, however, able to get the example code from the script repository to work in Slicer 4.11, after some modifications. Here is my working code:

```auto
referenceVolumeNode = slicer.util.loadVolume(ref_volume)
inputModel = slicer.util.loadModel(stl_file)

# Convert model to labelmap
seg = slicer.mrmlScene.AddNewNodeByClass('vtkMRMLSegmentationNode')
seg.SetReferenceImageGeometryParameterFromVolumeNode(referenceVolumeNode)
slicer.modules.segmentations.logic().ImportModelToSegmentationNode(inputModel, seg)
seg.CreateBinaryLabelmapRepresentation()
outputLabelmapVolumeNode = slicer.mrmlScene.AddNewNodeByClass('vtkMRMLLabelMapVolumeNode')
slicer.modules.segmentations.logic().ExportVisibleSegmentsToLabelmapNode(seg, outputLabelmapVolumeNode, referenceVolumeNode)

# Set image directions to correct flip L-R issue
imageDirections = [[-1,0,0], [0,1,0], [0,0,1]] 
outputLabelmapVolumeNode.SetIJKToRASDirections(imageDirections)
	
slicer.util.saveNode(outputLabelmapVolumeNode, "seg.nii.gz"))

```

Aside from the unexpected left-right flip, which I’ve corrected here, the code works like a charm. Thanks very much for your help!

---

<div class="post-metadata">

**Author:** ![lassoan](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/lassoan/32/13_2.png) [@lassoan](https://discourse.slicer.org/u/lassoan)\
**Post date:** [August 19, 2020, 12:56pm UTC](https://discourse.slicer.org/t/converting-stl-files-to-binary-label-maps-in-nii-format-using-python/13038/7 "2020-08-19T12:56:22Z")

</div>

Thanks for sharing the script that worked for you. Probably the very latest Slicer Preview Release (that you download today or later) would work with the shorter script I provided (@Sam_Horvath pushed a fix for properly handling STL files in either RAS or LPS coordinate system).

---

<div class="post-metadata">

**Author:** ![DC-3T](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/dc-3t/32/7786_2.png) [@DC-3T](https://discourse.slicer.org/u/DC-3T)\
**Post date:** [September 2, 2020, 3:40pm UTC](https://discourse.slicer.org/t/converting-stl-files-to-binary-label-maps-in-nii-format-using-python/13038/8 "2020-09-02T15:40:09Z")

</div>

Sorry for the slow reply. I downloaded the latest Slicer Preview Release (2020-09-01) to test the shorter script you provided and the code now works! The “CalculateOutputGeometry: No image geometry specified, default geometry is calculated” message still appears, but the resulting label maps are perfect, and do not exhibit the left-right flip I mentioned above. Thanks again for your help with this issue.

---

<div class="post-metadata">

**Author:** ![rohand24](https://avatars.discourse-cdn.com/v4/letter/r/97f17d/32.png) [@rohand24](https://discourse.slicer.org/u/rohand24)\
**Post date:** [July 15, 2021, 5:42pm UTC](https://discourse.slicer.org/t/converting-stl-files-to-binary-label-maps-in-nii-format-using-python/13038/9 "2021-07-15T17:42:54Z")

</div>

Hi,

Thank you for this thread. I am able to convert my Model ‘.stl’ files to Segmentations ‘.seg.nrrd’ files.  
I am not facing the direction related issue. But I wanted to know how to set the Segmentation labelmap geometry using python code, rather than using Segment Editor in GUI.

My Code -

referenceVolumeNode = slicer.mrmlScene.GetFirstNodeByClass(‘vtkMRMLScalarVolumeNode’) #Gets the already loaded DICOM Volume  
inputModel = slicer.util.loadModel(model\_filepath) # .stl filepath

seg = slicer.mrmlScene.AddNewNodeByClass(‘vtkMRMLSegmentationNode’)  
seg.SetReferenceImageGeometryParameterFromVolumeNode(referenceVolumeNode)  
slicer.modules.segmentations.logic().ImportModelToSegmentationNode(inputModel, seg)  
seg.SetReferenceImageGeometryParameterFromVolumeNode(referenceVolumeNode)  
seg.CreateBinaryLabelmapRepresentation()  
labelmapVolumeNode = slicer.mrmlScene.AddNewNodeByClass(“vtkMRMLLabelMapVolumeNode”)  
slicer.modules.segmentations.logic().ExportVisibleSegmentsToLabelmapNode(seg, labelmapVolumeNode, referenceVolumeNode)

slicer.util.saveNode(referenceVolumeNode, output\_volume\_filepath))  
slicer.util.saveNode(seg, output\_segmentation\_filepath)

My segmentation geometry is currently:

![image](https://us1.discourse-cdn.com/flex002/uploads/slicer/original/3X/5/b/5bd1f1bee5bf5f5bc0333e141439caa602eca5fb.png)

I need to set my segmentation geometry to this, using python script code.

![image](https://us1.discourse-cdn.com/flex002/uploads/slicer/original/3X/2/d/2d555a028357f93abb5493eb0b71d88b7c365d44.png)

Kindly help.

Thank you.

---

<div class="post-metadata">

**Author:** ![lassoan](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/lassoan/32/13_2.png) [@lassoan](https://discourse.slicer.org/u/lassoan)\
**Post date:** [July 15, 2021, 6:28pm UTC](https://discourse.slicer.org/t/converting-stl-files-to-binary-label-maps-in-nii-format-using-python/13038/10 "2021-07-15T18:28:29Z")

</div>

See a complete example for specifying segmentation geometry in the [script repository](https://slicer.readthedocs.io/en/latest/developer_guide/script_repository.html#rasterize-a-model-and-save-it-to-a-series-of-image-files).

---

<div class="post-metadata">

**Author:** ![lassoan](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/lassoan/32/13_2.png) [@lassoan](https://discourse.slicer.org/u/lassoan)\
**Post date:** [February 18, 2023, 4:54am UTC](https://discourse.slicer.org/t/converting-stl-files-to-binary-label-maps-in-nii-format-using-python/13038/11 "2023-02-18T04:54:26Z")

</div>

A post was merged into an existing topic: [stl file stores the annotation results of CT data, and I want to convert it to nii format for deep learning.](https://discourse.slicer.org/t/stl-file-stores-the-annotation-results-of-ct-data-and-i-want-to-convert-it-to-nii-format-for-deep-learning/27898/2)

---

<div class="post-metadata">

**Author:** ![xiaoli](https://avatars.discourse-cdn.com/v4/letter/x/f04885/32.png) [@xiaoli](https://discourse.slicer.org/u/xiaoli)\
**Post date:** [July 15, 2024, 6:10am UTC](https://discourse.slicer.org/t/converting-stl-files-to-binary-label-maps-in-nii-format-using-python/13038/12 "2024-07-15T06:10:01Z")

</div>

Hello sir, I don’t know if you have time, but I would like to ask you a question.  
After converting STL data to Nii.gz data, my own STL file was complete, but I found that many neural tubes were broken after conversion. I don’t know how to reduce this kind of breakage. Do you have a good solution

---

<div class="post-metadata">

**Author:** ![sajad\_amiri](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/sajad_amiri/32/78661_2.png) [@sajad\_amiri](https://discourse.slicer.org/u/sajad_amiri)\
**Post date:** [August 25, 2024, 8:29pm UTC](https://discourse.slicer.org/t/converting-stl-files-to-binary-label-maps-in-nii-format-using-python/13038/13 "2024-08-25T20:29:43Z")

</div>

Hello friends,  
I have a folder containing STL masks of lesions from my dataset, and I want to extract Radiomics features. Should I first convert the STLs to binary masks? If it’s not necessary to convert them for feature extraction, please let me know how to extract features directly from STL files and a reference image. I would greatly appreciate a Python code for batch processing rather than single-image mode. Thank you!
