Load MRML V1.0 scene in Slicer 4

Operating system: Debian 9.2
Slicer version: 4.8.0
Expected behavior: Scene is loaded in Slicer
Actual behavior: Error parsing XML in stream at line 1, column 0, byte index 0: syntax error

Hello,

I have some old MRML V1.0 scenes which I am unable to load into Slicer 4.

The files begin with the following lines:

MRML V1.0
Volume (

When I try to open the file in Slicer 4.8 I get the following error:

Error parsing XML in stream at line 1, column 0, byte index 0: syntax error

The MRML files I have are obviously not XML files so I’m guessing that they were created with an older version of Slicer (circa 1999).

Is there any way to open these files in newer versions of Slicer? Otherwise, is there a script available that can be used to convert the MRML V1.0 files to the newer XML MRML format?

There is no script to port 1999 versions of MRML into the modern Slicer.

Thanks Andrey. I might try to translate the files manually or write my own script. Do you know if there is a description of the MRML format that lists the allowable XML elements? All I have found so far is the documentation on the wiki:

https://www.slicer.org/wiki/Documentation/Nightly/Developers/MRML

and the class documentation:

http://apidocs.slicer.org/master/classvtkMRMLNode.html

Are there any other references that might help with this?

Both old and new scene is human-readable, so writing a converter should be possible just by looking at the files. If you are not sure about what is a corresponding element or atrribute in current Slicer scenes then you can ask it here.

A quick google suggests there was a MRML1 importer in Slicer 2, which I have been able to run semi-recently (Windows might be the best bet, actually). This could provide an import pathway or possibly example code to start from.

(it’s going to be really tricky to go from 2->3->4 so if you have a lot of data then a custom importer directly to Slicer 4 probably makes sense).

FWIW slicer3 could import slicer2 mrml scenes (at least most of the data) and there’s a docker image that can run slicer3.

(I haven’t tried a slicer2 docker, but that might be good to do for historical reasons).

Here’s the slicer3 importer code for reference:

Thank you for all your suggestions.

Below is an example of one of the scenes I have tried to convert manually. I can load the XML file into Slicer 4.8 without errors but the image is not loaded. However, in the Data module, the node “brain1st” is created with the correct image spacing. Are there any obvious mistakes in the MRML file, or could it be that Slicer does not recognise the file format of the volume data? There are 60 slices named brain1st.001, brain1st.002 etc.

Original MRML v1.0 (Slicer 1 or 2):

MRML V1.0
Volume (
        name brain1st
        labelMap 1
        filePrefix brain1st
        headerSize 0
        imageRange 1 60
        spacing 0.9375 0.9375 2.5
        rasToIjkMatrix 0 1.06667 0 122.773 -1.06667 0 -0 140.8 0 -0 0.4 23.14 -0 0 -0 1
        rasToVtkMatrix -0 1.06667 -0 122.773 1.06667 -0 0 115.2 -0 0 0.4 23.14 0 -0 0 1
        options slicer interpolate 0 lutID 6
)

Converted MRML v2.0 (Slicer 4):

<?xml version="1.0" standalone="no"?>
<!DOCTYPE MRML SYSTEM "mrml20.dtd">
<MRML>
<Volume
        name="brain1st"
        labelMap="1"
        filePrefix="brain1st"
        headerSize="0"
        imageRange="1 60"
        spacing="0.9375 0.9375 2.5"
        rasToIjkMatrix="0 1.06667 0 122.773 -1.06667 0 -0 140.8 0 -0 0.4 23.14 -0 0 -0 1"
        rasToVtkMatrix="-0 1.06667 -0 122.773 1.06667 -0 0 115.2 -0 0 0.4 23.14 0 -0 0 1"
        interpolate="no">
        <!-- Not used: -->
        <!-- options slicer interpolate 0 lutID 6 -->
</Volume>
</MRML>

When I load the new MRML file in Slicer 4.8 I get the following output in the terminal:

"MRML Scene" Reader has successfully read the file ".../brain1st/brain1st.xml.mrml" "[0.34s]" 

Input port 0 of algorithm vtkImageMapToColors(0x2ed5040) has 0 connections but is not optional.

No scalar values found for texture input!

If I try to load the image data alone (without the MRML scene file) I get the following error:

ReadData: This is not a nrrd file

ReadData: Failed to instantiate a file reader

ReadData: Cannot read file as a volume of type Volume[fullName = .../brain1st/brain1st.001]
        Number of files listed in the node = 0.
        File reader says it was able to read 0 files.
        File reader used the archetype file name of .../brain1st/brain1st.001 []
ITK exception info: error in unknown
Could not create IO object for reading file .../brain1st/brain1st.001
Tried to create one of the following:
    NiftiImageIO
    NrrdImageIO
    GiplImageIO
    JPEGImageIO
    GDCMImageIO
    BMPImageIO
    LSMImageIO
    PNGImageIO
    TIFFImageIO
    VTKImageIO
    StimulateImageIO
    BioRadImageIO
    MetaImageIO
    MRCImageIO
    MINCImageIO
    MGHImageIO
    MRMLIDImageIO
You probably failed to set a file suffix, or
    set the suffix to an unsupported type.

Is there a way to set the file type without changing the file extension? If not with the GUI, perhaps using Python?

Isaiah, I did find some similar code in my search so I got the Slicer2 source from Steve’s github page but ran into some trouble trying to compile it. I fixed a lot of the errors but eventually gave up hoping to find a better way to import the files into the new Slicer. Did you compile Slicer2 from source or did you use a precompiled binary for Windows?

Steve, I tried to load the scene and image in Slicer 3.6.3 but this did not work either. I will try again to compile Slicer 2. Would you expect there to be any problems building Slicer 2 or 3 on Debian 9 (stretch)?

Slicer uses ITK’s file readers to read images and they determine what reader to use based on the file extension. You could probably instantiate a specific reader using Python scripting, but it would be easier to just set the proper extension for your image (and a good idea in general).

What is the file format of brain1st.001?

@lassoan slicer2 used a (bad) convention of “.%03d” as the names of uncompressed raw images. The imageRange field tells what files are expected.

@benzwick if you writing a script to process these it would probably be easiest to implement a new parser for the old MRML files and populate the slicer4 MRML scene. Are there other data objects in the old scenes or just image volumes?

@lassoan I agree that changing the extension is a better idea although there are a large number of files that will need to be renamed. I don’t know the file format of brain1st.001 etc. I searched and tried using a few different tools and image viewers to open the files. If anyone has any suggestions for how to determine the file type that would help a lot!

@pieper If the images files are uncompressed raw images as you suggest what would be the correct file extension? Also, is NRRD still the recommended image format? If so, is there a way to convert the images to NRRD format? This might make it a bit easier to manage the data in the long term.

The only other data objects in the scene files that I have found so far are models e.g:

Model (
        name brain
        fileName .../brain.vtk
)

Files without extension may be headerless raw file but it may be DICOM as well. The first task should be to find out what the format is.

If they are raw files then they can be read as nrrd file. To load that file, you just create a NRRD header file: a text file with .nhdr extension that describes image size, spacing, orientation, and name of the raw file that contains voxel data.

Large number of files is not an issue, as you would process them using a Python script anyway.

Yes, the slicer2 convention was headerless raw files. Creating a .nhdr file to point to the originals is a good way to approach the problem.

http://teem.sourceforge.net/nrrd/format.html#detached

I have created a NRRD header file as suggested (see below). I now have the following questions:

  • Can I put the transformation matrix in the NRRD header or do I need to put it in the new MRML scene file?

  • Are the type (short), endian (little) and byte skip (-1) correct for reading Slicer 1/2 raw data?

  • When I save the image as NRRD or NHDR in Slicer (see example below) the saved NRRD header uses the ‘left-posterior-superior’ (LPS) space instead of the ‘right-anterior-superior’ (RAS) space. Is this the expected behaviour? The wiki (https://www.slicer.org/wiki/Coordinate_systems) states that Slicer uses the RAS coordinate system. Is there a way to keep the original basis when saving the image or is it better to use LPS?

  • Is there a way to determine the image sizes (number of pixels in each direction) from the raw data? (I used trial and error based on some knowledge of the expected image size)

Volume object in original MRML file:

MRML V1.0
Volume (
        name 1st
        filePrefix ./0021stSPGR/I
        imageRange 1 60
        spacing 0.937500 0.937500 2.5
        rasToIjkMatrix 0 1.06667 0 122.773 -1.06667 0 -0 140.8 0 -0 0.4 23.14 -0 0 -0 1
        rasToVtkMatrix -0 1.06667 -0 122.773 1.06667 -0 0 115.2 -0 0 0.4 23.14 0 -0 0 1
        scanOrder OB
        scanOrigin 132 -115.1 -57.85
        scanOrientation 0 1 0 0 1 0 0 0 0 0 1 0 0 0 0 1
)

NHDR created manually:

NRRD0004
# Complete NRRD file format specification at:
# http://teem.sourceforge.net/nrrd/format.html
type: short
dimension: 3
space: right-anterior-superior
sizes: 256 256 60
space directions: (0.9375,0,0) (0,0.9375,0) (0,0,2.5)
kinds: domain domain domain
endian: little
byte skip: -1
encoding: raw
space origin: (-132,-115.1,-57.85)
# TODO:
# rasToIjkMatrix 0 1.06667 0 122.773 -1.06667 0 -0 140.8 0 -0 0.4 23.14 -0 0 -0 1
# rasToVtkMatrix -0 1.06667 -0 122.773 1.06667 -0 0 115.2 -0 0 0.4 23.14 0 -0 0 1
# scanOrder OB
# scanOrientation 0 1 0 0 1 0 0 0 0 0 1 0 0 0 0 1
data file: I.%03d 1 60 1

NHDR saved using Slicer 4.8:

NRRD0004
# Complete NRRD file format specification at:
# http://teem.sourceforge.net/nrrd/format.html
type: short
dimension: 3
space: left-posterior-superior
sizes: 256 256 60
space directions: (-0.9375,0,0) (0,-0.9375,0) (0,0,2.5)
kinds: domain domain domain
endian: little
encoding: gzip
space origin: (132,115.09999999999997,-57.850000000000001)
data file: 0021stSPGR.raw.gz

Put it in the NRRD header.

I don’t think skip (-1) is correct. If there is no image header then use skip: 0.
If you don’t get short or endian correct then you can see very characteristic striping artifacts. There are not too many combination, so you can do trial and error.

Yes, this is expected. Slicer uses ITK image readers and ITK uses LPS coordinate system (it is converted to to/from RAS when writing/reading the file in Slicer).

You should be able to find image size in the scene file (maybe in storage node, if there was such thing at that time). It seems that the old importer code used slice size of 256x256 if no “dimensions” tag was present. You can get the number of slices from the total file length divided by slice size and voxel size.

How can I put the transformation/orientation information in the header? In other words, how do I specify the following MRMLv1.0 data in the NRRD header:

rasToIjkMatrix 0 1.06667 0 122.773 -1.06667 0 -0 140.8 0 -0 0.4 23.14 -0 0 -0 1
rasToVtkMatrix -0 1.06667 -0 122.773 1.06667 -0 0 115.2 -0 0 0.4 23.14 0 -0 0 1
scanOrder OB
scanOrigin 132 -115.1 -57.85
scanOrientation 0 1 0 0 1 0 0 0 0 0 1 0 0 0 0 1

Does scanOrigin in the MRML correspond to space origin in the NRRD file? I assume that the rasToIjkMatrix is what I need to include but I couldn’t even apply the transform manually in Slicer (the image is squashed and not rotated correctly).

@lassoan When I use byte skip: 0 the image is split down the middle and the two halves are swapped. I checked the data files for this case and they all contain some header data (not all of my images have these headers). Each raw slice file begins with IMGF. I guess it might be GE MR Signa 5.x Image data (http://www.dclunie.com/medical-image-faq/html/part4.html) as it is most likely that a GE Signa system was used to acquire the images. The size of the image is 256 x 256 x 2 = 131072 but the file size is 138976 bytes so the additional 7904 bytes must be the header. When I use byte skip: 7904 the image loads and looks OK. If I use byte skip: -1 the image appears the same as when using the actual header size. It seems easier to use the latter. Would there be any benefit in specifying the actual header length (7904) instead of reading the file backwards (-1)?

Changing the endianness does not have an obvious effect on the appearance of the image (especially if the data type is unsigned short) but the data probe confirms it is actually big-endian.

It seems that you’ve found the file format description!

  • 4 - int - byte displacement to pixel data => this tells you the byte skip value (but if you know that the image data is at the end of the file then byte skip: -1 should work, too)
  • 8 - int - width => first component of sizes
  • 12 - int - height => second component of sizes
  • 16 - int - depth (bits) => you can use this for determining type

Yes.

rasToVtkMatrix  =
  -0 1.06667 -0 122.773
  1.06667 -0 0 115.2
  -0 0 0.4 23.14
  0 -0 0 1

The top-left 3x3 part of this matrix goes into space directions. The first 3 values in the last column goes to space origin.

FWIW, dcm2nii supports some variant of this file format. Might be worth trying as a point of reference.

https://www.nitrc.org/projects/dcm2nii/

(that’s the old pascal version, not the new dcm2niix)

I assumed something along those lines. However, in the MRML file there is rasToIjkMatrix as well as scanOrigin. My guess is that only scanOrigin would be used by Slicer and rasToIjkMatrix would be ignored - is this correct? The spacing and rasToIjkMatrix values in the MRML file seem to be related by 1/1.06667 = 0.9375 and 1/0.4 = 2.5. Also, can I ignore scanOrder and scanOrientation as well?

The following header seems to work now and the image orientation roughly matches some of the related VTK models:

NRRD0004
# Complete NRRD file format specification at:
# http://teem.sourceforge.net/nrrd/format.html
type: short
dimension: 3
space: right-anterior-superior
sizes: 256 256 60
kinds: domain domain domain
endian: big
byte skip: -1
encoding: raw
space directions: (0,0.9375,0) (-0.9375,0,0) (0,0,2.5) 
space origin: (132,-115.1,-57.85)
data file: I.%03d 1 60 1

Through trial and error using the NRRD format I established that the data is big-endian. It seems that dcm2nii interprets the data as little-endian. When I load the converted NIfTI image into Slicer some pixels have negative values which appear as black spots in bright areas such as the skull, and the values in dark areas are 0, 256, 512, 768 etc. (the same happens if I specify little-endian in the NRRD header). If I specify big-endian in the NRRD header there are no negative pixels and the dark areas are 0, 1, 2, 3 etc. I couldn’t find an option for dcm2nii to change this. Also, the orientation of the image is different than using the above NRRD header.

By the way, the link above appears to refer to the newer dcm2niix. The old dcm2nii can be found here: dcm2nii DICOM to NIfTI conversion. Both dcm2niix and dcm2nii (packaged with mricron) are also available in the NeuroDebian repository.