# Question on STL transformation in slicer's world coordinate

**URL:** <https://discourse.slicer.org/t/question-on-stl-transformation-in-slicers-world-coordinate/39774>\
**Category:** Support\
**Created:** [October 21, 2024, 12:18pm UTC](https://discourse.slicer.org/t/question-on-stl-transformation-in-slicers-world-coordinate/39774 "2024-10-21T12:18:49Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![alientex](https://avatars.discourse-cdn.com/v4/letter/a/e79b87/32.png) [@alientex](https://discourse.slicer.org/u/alientex)\
**Post date:** [October 21, 2024, 12:18pm UTC](https://discourse.slicer.org/t/question-on-stl-transformation-in-slicers-world-coordinate/39774/1 "2024-10-21T12:18:49Z")

</div>

Hello,

First, I created a segment and converted it into a model in slicer.

Second, I have written an external script purely based on VTK, which does not rely on Slicer classes. The script reads DICOM files using `vtkDICOMImageReader`, applies a threshold using `vtkImageThreshold`, converts it to a model using VTK’s marching cubes, and finally exports it using `vtkSTLWriter`.

Now, I imported the STL generated by the script, into Slicer to compare it against the model generated earlier from the segment. However, I am unable to compare their contours in 2D because my external STL is not aligned with the model generated by Slicer. In the 3D scene, both models are far apart and do not lie on the same origin. I don’t want to use the Transform module because of its manual nature. I want to simulate, how slicer internally does transformations, within my script so that when I export any STL from my script and import it into Slicer, it has the correct transformations and aligns with the 3D Slicer-generated model.

---

<div class="post-metadata">

**Author:** ![pieper](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/pieper/32/8_2.png) [@pieper](https://discourse.slicer.org/u/pieper)\
**Post date:** [October 21, 2024, 1:13pm UTC](https://discourse.slicer.org/t/question-on-stl-transformation-in-slicers-world-coordinate/39774/2 "2024-10-21T13:13:11Z")

</div>

[https://slicer.readthedocs.io/en/latest/user\_guide/coordinate\_systems.html](https://slicer.readthedocs.io/en/latest/user_guide/coordinate_systems.html)

---

<div class="post-metadata">

**Author:** ![alientex](https://avatars.discourse-cdn.com/v4/letter/a/e79b87/32.png) [@alientex](https://discourse.slicer.org/u/alientex)\
**Post date:** [October 21, 2024, 4:03pm UTC](https://discourse.slicer.org/t/question-on-stl-transformation-in-slicers-world-coordinate/39774/3 "2024-10-21T16:03:36Z")

</div>

Thank you for providing the reference.

I have gone through it, and I was wondering how I can utilize the exact transformation matrix of Slicer. I am setting the labelmap’s origin and spacing to be the same as the one given in the `CreateClosedSurface` function of the `vtkBinaryLabelmapToClosedSurfaceConversionRule` class.

I’ve been stuck on this problem for many days. I would appreciate further help.

Here’s a picture of the models for reference (the green model is from Slicer, and the yellow one is generated from the script):

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

Thank you.

---

<div class="post-metadata">

**Author:** ![pieper](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/pieper/32/8_2.png) [@pieper](https://discourse.slicer.org/u/pieper)\
**Post date:** [October 21, 2024, 4:31pm UTC](https://discourse.slicer.org/t/question-on-stl-transformation-in-slicers-world-coordinate/39774/4 "2024-10-21T16:31:56Z")

</div>

My guess is that you just need to pick LPS on loading like this:

 ![image](https://us1.discourse-cdn.com/flex002/uploads/slicer/original/3X/9/9/9942f3967a04e3d919d25dcf09e9670ef3813736.png)

If that’s it and you want to make this automatic in the future you can add a coordinate system tag in the stl header something like this:

> <https://github.com/Slicer/Slicer/blob/0fe633e6a86ac1c4ed95a7afd6a35ead81e83b84/Libs/MRML/Core/vtkMRMLModelStorageNode.cxx#L614>

[https://slicer.readthedocs.io/en/v4.11/user\_guide/data\_loading\_and\_saving.html#models](https://slicer.readthedocs.io/en/v4.11/user_guide/data_loading_and_saving.html#models)

---

<div class="post-metadata">

**Author:** ![alientex](https://avatars.discourse-cdn.com/v4/letter/a/e79b87/32.png) [@alientex](https://discourse.slicer.org/u/alientex)\
**Post date:** [October 22, 2024, 3:47am UTC](https://discourse.slicer.org/t/question-on-stl-transformation-in-slicers-world-coordinate/39774/5 "2024-10-22T03:47:18Z")

</div>

Hello @pieper ,

I tried loading the STL by selecting both coordinate systems, but it didn’t work, as the result is still the same. I also modified my script to include the coordinate tag, and when I loaded the STL again, there was no luck.

Here’s my code for saving a mesh:

```auto
def SaveMeshToSTL(polydata, filename):
    stl_writer = vtk.vtkSTLWriter()
    stl_writer.SetFileName(filename)

    stl_writer.SetInputData(polydata)

    coordinateSystemTag = "SPACE"
    CoordinateSystem = slicer.vtkMRMLModelStorageNode().CoordinateSystemLPS
    coordinateSystemStr = slicer.vtkMRMLModelStorageNode().GetCoordinateSystemTypeAsString(CoordinateSystem)
    coordinateSytemSpecification = coordinateSystemTag + "=" + coordinateSystemStr
    header = "3D Slicer output. " + coordinateSytemSpecification
    stl_writer.SetHeader(header)

    stl_writer.SetFileType(vtk.VTK_BINARY)

    stl_writer.Write()
    print(f"Model successfully saved to {filename}")

```

The output of the function `TransformIJKToWorld` is then passed to the mesh-saving function as polydata:

```auto
def TransformIJKToWorld(polydata, oriented_data):
    labelmapGeometryTransform = vtk.vtkTransform()
    labelmapImageToWorldMatrix = vtk.vtkMatrix4x4()

    oriented_data.GetImageToWorldMatrix(labelmapImageToWorldMatrix)
    labelmapGeometryTransform.SetMatrix(labelmapImageToWorldMatrix)

    transformPolyDataFilter = vtk.vtkTransformPolyDataFilter()
    transformPolyDataFilter.SetInputData(polydata)
    transformPolyDataFilter.SetTransform(labelmapGeometryTransform)
    transformPolyDataFilter.Update()

    return transformPolyDataFilter.GetOutput()

```

@lassoan @cpinter @muratmaga, Any idea what might be the issue?

---

<div class="post-metadata">

**Author:** ![pieper](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/pieper/32/8_2.png) [@pieper](https://discourse.slicer.org/u/pieper)\
**Post date:** [October 22, 2024, 12:06pm UTC](https://discourse.slicer.org/t/question-on-stl-transformation-in-slicers-world-coordinate/39774/6 "2024-10-22T12:06:19Z")

</div>

Well, it must be something else then. You just need to trace through all the matrices and coordinates to validate your assumptions.

---

<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:** [October 22, 2024, 1:09pm UTC](https://discourse.slicer.org/t/question-on-stl-transformation-in-slicers-world-coordinate/39774/7 "2024-10-22T13:09:21Z")

</div>

vtkDICOMImageReader only works for special cases. I would not recommend spending any time with trying to debug why the image is not loaded correctly with vtkDICOMImageReader. If you are looking for a pure VTK-based solution then your best option is [GitHub - dgobbi/vtk-dicom: A set of classes for using DICOM in VTK.](https://github.com/dgobbi/vtk-dicom/). It is still very limited but works for majority of basic image acquisitions. Make sure you take into account the `PatientMatrix` provided by the reader.

If you want to reconstruct volumes from more complex acquisitions then you can use dcm2niix or Slicer. If you want an open-source solution to read not just images but other important DICOM objects then probably your only choice is Slicer (or implement yourself from pydicom level).

---

<div class="post-metadata">

**Author:** ![alientex](https://avatars.discourse-cdn.com/v4/letter/a/e79b87/32.png) [@alientex](https://discourse.slicer.org/u/alientex)\
**Post date:** [October 25, 2024, 3:18am UTC](https://discourse.slicer.org/t/question-on-stl-transformation-in-slicers-world-coordinate/39774/8 "2024-10-25T03:18:00Z")

</div>

@lassoan, your suggested solution really worked! I used the `PatientMatrix` from `vtkDICOMReader`, and it’s giving me correct results now.

Thank you!
