Model files are now saved in LPS coordinate system

While Slicer uses RAS coordinate system internally, images, transforms, and markups files are stored in LPS coordinate system, because DICOM and all medical image computing software (maybe except a few very old ones) uses LPS coordinate system in files.

However, Slicer has been still using its internal RAS coordinate system in mesh files (STL, VTK, VTP, OBJ, PLY), which caused issues when interfacing with third-party software.

Starting from tomorrow (Slicer-4.11.0-2020-02-26, revision 28794), Slicer Preview Release will save models in LPS coordinate system, and assume mesh files to be in LPS coordinate system by default.

Slicer started embedding coordinate system name in mesh files a few years ago (see SPACE=RAS in the file header), so all the files that Slicer saved in recent years will load correctly and any scene files created with any version of Slicer will also load the models with correct orientation, too.

Manual setting of coordinate system (in Add data dialog / Options column) is only needed when loading a mesh file without a scene that were created by Slicer-4.6 (2017-09-27) and earlier; and obj files created by Slicer-4.6 and Slicer-4.8 (between 2016-10-11 and 2018-03-26), or files are created by third-party software in RAS coordinate system.

See more details and list of modified files in this commit.

solid 3D Slicer output. SPACE=LPS
facet normal 0.670457 -0.150029 0.726621
outer loop
vertex 86.7619 22.6655 32.2962
vertex 85.9753 22.2651 32.9394

If you encounter orientation issues when loading a model file, you have the following options:

  • Option A: Specify the coordinate system when you open the model file. In ā€œAdd dataā€ dialog, click ā€œShow Optionsā€ and then choose ā€œRASā€ as coordinate system.

  • Option B: Update the third-party software that generate the mesh to save coordinates in LPS coordinate system instead of RAS coordinate system. Conversion is simple inverting the sign of the first two coordinates.

  • Option C: Write ā€œSPACE=RASā€ in the comment/description field in the mesh file (for STL, OBJ, PLY, VTK file; for VTP files, add in the first value of a vtkStringArray field array named ā€œSPACEā€) to indicate that the values are stored in RAS coordinate system. This option is useful if coordinates have to be stored in RAS coordinate system (for example, for compatibility with other software).

Examples of file headers that specify what coordinate system is used (click on the arrow on the left to expand)

Example of an STL file header that stores coordinates in RAS coordinate system:

solid 3D Slicer output. SPACE=RAS
 facet normal 0.670457 -0.150029 0.726621
  outer loop
   vertex 86.7619 22.6655 32.2962
   vertex 85.9753 22.2651 32.9394
...

Example of an OBJ file header that stores coordinates in RAS coordinate system:

# 3D Slicer output. SPACE=RAS

mtllib Segment_1.mtl

v 83.3949 8.0714 -7.2143
v 83.3949 9.0714 -7.2143
v 83.3949 10.0714 -7.2143
...

Example of a VTK file header that stores coordinates in RAS coordinate system:

# vtk DataFile Version 4.2
3D Slicer output. SPACE=RAS
BINARY
DATASET POLYDATA
POINTS 7192 float 
...

Example of a PLY file header that stores coordinates in RAS coordinate system:

ply
format binary_little_endian 1.0
comment VTK generated PLY File
comment SPACE=RAS
obj_info vtkPolyData points and polygons: vtk4.0
element vertex 13327
property float x
property float y
...

Example of a VTP file header that stores coordinates in RAS coordinate system:

<?xml version="1.0"?>
<VTKFile type="PolyData" version="0.1" byte_order="LittleEndian" header_type="UInt32">
  <PolyData>
    <FieldData>
      <Array type="String" Name="SPACE" NumberOfTuples="1" format="ascii">
        82 65 83 0
      </Array>
    </FieldData>
    <Piece NumberOfPoints="13327" NumberOfVerts="0" NumberOfLines="0" NumberOfStrips="0" NumberOfPolys="26650">
      <PointData>
...

See C++ code examples of writing coordinate system information when saving a mesh file here.

5 Likes

Will Slicer convert to using LPS internally at some point? It seems as though it would make sense given how many other applications use LPS.

Compatibility with other applications is taken care of by using LPS in files. It would make things simpler to switch to LPS internally, too. It is just a matter of development priorities. There are other things that would make bigger impact for Slicer developers (such as switching to VTK oriented image data) and users (better widgets, measurements, 4D support, etc.).

1 Like

@lassoan Hi Andras, the link at the end seems that it is unavailable. Could you please provide that since I am trying to find a way to read/write files in different spaces using python? Thanks a lot.

Iā€™ve udpated the link. If you want to load an STL/OBJ/PLY/VTK/VTU file that does not have embedded cordinate system information in it and is stored in RAS coordinate system then you can load it like this:

modelNode = slicer.modules.models.logic().AddModel(
  "something.stl", slicer.vtkMRMLStorageNode.CoordinateSystemRAS)
1 Like

Good to know, I was having some problems recently related to this. It would be nice if this option is also available for markups.

1 Like

Yes, the same automatic LPS/RAS coordinate system switch is available for markups, too.

1 Like

if you add fiducials like
markupsNode3 = slicer.mrmlScene.AddNewNodeByClass(ā€œvtkMRMLMarkupsFiducialNodeā€)
markupsNode3.CreateDefaultDisplayNodes()

how to get the RAS coordinates for fiducials.

Thanks

how to save node in RAS coordinate system.

Regards,
Saima Safdar

You can specified the desired coordinate system in SetCoordinateSystem method of the storage node.

I would not recommend saving in RAS though, as in medical image computing, data files generally use LPS.

Is there a specific procedure or read/write method to make ā€œSPACE=RASā€ in the operation of option C?
Thank you.

If you run your Python script in Slicer then you can use the vtkMRMLModelStorageNode. It can save models in LPS or RAS and always saves the coordinate system name in the header.

If you run code in a different environment then you can write the coordinate system specification in the file header yourself. If you use VTK then you can copy Slicerā€™s implementation.

Since I donā€™t understand this operation well, can you please provide me with a sample program?

The source code that I linked to shows what Slicer does and you can do exactly the same in your software. If you need more help then you can create a standalone example by copy-pasting the relevant code parts from Slicerā€™s implementation into a similar VTK example and post the link here so that we can have a look and comment on it.

@lassoan Hi, i try OptionA with markups however it does not surve the coordinate system choice.
What can i do if i want to read my markups(saved by LPS) into RAS?
Thank you for your time!

Could you upload your markup file to somewhere (Dropbox, OneDrive, Google drive) and post the link here?

@lassoan

thank you!

Iā€™ve checked the file and everything looks good. The control point coordinates in the .mrk.json file are defined in LPS coordinate system (first control point: [195.993, 6.125, -90.188]). When Slicer loads the file, it converts the coordinates into RAS coordinate system (first control point: [-195.993, -6.125, -90.188]).

{
...
    "markups": [ {
            "type": "Fiducial",
            "coordinateSystem": "LPS", ...
            "controlPoints": [
                { ... "position": [195.99323699260385, 6.125348335657372, -90.18842609112076], ... },
                { ... "position": [150.0713619926038, 71.15759015694647, -79.89948566143325], ... }, ...]
...
}

If you specify the control points in RAS coordinate system then in the file set "coordinateSystem": "RAS".

1 Like

@lassoan
I see whats going now! Thank you so much for the information.

1 Like