Morita .Vol import and nhdr conversion - slices out of order

Hello!

I am trying to import Morita .vol files into slicer, but I am getting out of order slices.
I have followed the instructions found here as best as i can

Could somebody help me troubleshoot this?

problem - this slice has a part of it moved over left to right

problem - this slice looks ok but it should be in the middle of the order, not the first

I am pasting my original header and the nhdr I wrote. Btw why is the Z axis first in the “sizes” property?

OG Header

<JmVolume><Version value="1"/>
<Attribute>
<tfStatRadius value="20"/>
<tfStatZMax value="20"/>
<tfStatZMin value="-20"/>
<tfStatSkipLength value="0.5"/>
<tfStatSideLength value="2"/>
<tfStatIntervalLength value="2"/>
<tfXGridSize value="0.125"/>
<tfYGridSize value="0.125"/>
<tfZGridSize value="0.125"/>
<tfXLen value="60"/>
<tfYLen value="60"/>
<tfZLen value="60"/>
<strVolumeId value="0"/>
<tfInitialAngleInRadian value="2.26893"/>
<tfA value="0.00291905"/>
<tfB value="57.86"/>
<tfXCenter value="0"/>
<tfYCenter value="0"/>
<tfZCenter value="0"/>
<iZMaxValid value="2147483647"/>
<iZMinValid value="2147483647"/>
<tfAntiAliasAngleInRadian value="0"/>
<tfAntiAliasAngleInDegree value="45"/>
<tfSliceInterval value="0"/>
<tfSliceThickness value="0"/>
<iSliceMeanRange value="0"/>
</Attribute><FYI>
<XMin value="-240"/>
<XMax value="240"/>
<YMin value="-240"/>
<YMax value="240"/>
<ZMin value="-242"/>
<ZMax value="241"/>
<MinValue value="-37.7915"/>
<MaxValue value="153.509"/>
</FYI>
</JmVolume>

my nhdr

NRRD0004
# Complete NRRD file format specification at:
# http://teem.sourceforge.net/nrrd/format.html
type: short
dimension: 3
space: left-posterior-superior
sizes: 484 481 481
space directions: (0.125,0,0) (0,0.125,0) (0,0,0.125)
kinds: domain domain domain
endian: little
encoding: raw
#space origin: (0,0,0)
#space origin: (-30.0, -30.0, -30.1875)
byte skip: 800
data file: CT_0.vol

After some thought, the only problem I see is the Z axis wraparound. In total there are 484 layers. Instead of starting at layer 1, it starts at layer 444, goes up to 484 and then comes back at 1.
I tried exporting it as dicom, but the ImagePositionPatient is written in the same manner.

Any idea why that is happening and how this could be addressed?

@ChrisMak, see here.

It’s possible the “byte skip” parameter is incorrect.

Also, I can see your data rotated 45° around vertical (I→S) axis.

<tfAntiAliasAngleInDegree value="45"/>

You can use the following Python script to apply transform to align axes:

import numpy as np
from scipy.ndimage import rotate

import read_vol import load_data

path_input = "CT_0.vol"
path_output = "CT_0_rotated.raw"

def main () -> None:
    d = load_data(path_input)

    print("shape before rotation:", d.shape, d.dtype)

    # rotate around last axis (2), relative to center
    d_rot = rotate(d, angle=45, axes=(0, 1), reshape=False, order=1, cval=-32768)
    # flip very first (0) axis
    d_rot = d_rot[::-1, :, :]

    print("shape after rotation:", d_rot.shape)

    with open(path_output, "wb") as f:
        f.write(d_rot.tobytes())

if __name__ == '__main__':
    main()

Then use the following CT_0_rotated.nhdr file:

NRRD0004
# Complete NRRD file format specification at:
# http://teem.sourceforge.net/nrrd/format.html
type: signed short
dimension: 3
space: left-posterior-superior
sizes: Z Y X
space directions: (0,0,S) (0,S,0) (S,0,0)
kinds: domain domain domain
endian: little
encoding: raw
space origin: (0,0,0)
byte skip: 0
data file: CT_0_rotated.raw

Fill X, Y and Z values from “shape after rotation” script output, S is voxel size.
In your case:

  • X = Y = 240 - (-240) + 1 = 481, Z = 241 - (-242) + 1 = 484
  • S = 0.125
1 Like

It was byte skip! Thank you so much!