BIC-MNI / minc-tools

Basic minc-tools from former minc repository
Other
29 stars 25 forks source link

mnc2nii label creates wrong affine matrix when direction_cosines is not specified #99

Closed stilley2 closed 4 years ago

stilley2 commented 4 years ago

The files here example.zip are the exact same, except out_ndc.mnc does not have the direction cosines specified. The spec says that the direction cosines should be assumed to be [1, 0, 0], [0, 1, 0], and [0, 0, 1] if they are not present. These assumed values are the same as in out.mnc, so the two files should have the same coordinate-world transform. However, mnc2nii treats them differently, reversing the axis order (RAS vs SAR orientation). This was tested with minc toolkit 1.9.17. I tried to build a newer version of minc-tools but couldn't get it to compile.

stilley2 commented 4 years ago

FYI it seems that inormalize removes the direction_cosines if they are the default, which is how I ran into this problem.

gdevenyi commented 4 years ago

Hi,

Can you post the mincheader outputs of a good vs bad file?

gdevenyi commented 4 years ago

THe question about this bug is twofold:

  1. Is a minc file without direction cosines a valid minc file?
  2. What does https://github.com/BIC-MNI/minc-tools/blob/develop/conversion/nifti1/mnc2nii.c#L581-L582 return if a file has no direction cosine.

This could be classified as an inormalize bug depending on 1.

  1. could be a corner case of the code. Will investigate.
stilley2 commented 4 years ago

Good file header (out.mnc)

hdf5 out {
dimensions:
    xspace = 100 ;
    yspace = 101 ;
    zspace = 102 ;
variables:
    double image(zspace, yspace, xspace) ;
        image:version = "MINC Version    1.0" ;
        image:vartype = "group________" ;
        image:valid_range = 0., 1030199. ;
        image:varid = "MINC standard variable" ;
        image:complete = "true_" ;
        image:dimorder = "zspace,yspace,xspace" ;
    double image-min ;
        image-min:version = "MINC Version    1.0" ;
        image-min:vartype = "var_attribute" ;
        image-min:varid = "MINC standard variable" ;
    double image-max ;
        image-max:version = "MINC Version    1.0" ;
        image-max:vartype = "var_attribute" ;
        image-max:varid = "MINC standard variable" ;
    int xspace ;
        xspace:version = "MINC Version    1.0" ;
        xspace:vartype = "dimension____" ;
        xspace:start = -40. ;
        xspace:spacing = "regular__" ;
        xspace:alignment = "centre" ;
        xspace:direction_cosines = 1., 0., 0. ;
        xspace:comments = "X increases from patient left to right" ;
        xspace:units = "mm" ;
        xspace:varid = "MINC standard variable" ;
        xspace:length = 100 ;
        xspace:step = 1. ;
    int yspace ;
        yspace:version = "MINC Version    1.0" ;
        yspace:vartype = "dimension____" ;
        yspace:start = -41. ;
        yspace:spacing = "regular__" ;
        yspace:alignment = "centre" ;
        yspace:direction_cosines = 0., 1., 0. ;
        yspace:comments = "Y increases from patient posterior to anterior" ;
        yspace:units = "mm" ;
        yspace:varid = "MINC standard variable" ;
        yspace:length = 101 ;
        yspace:step = 1. ;
    int zspace ;
        zspace:version = "MINC Version    1.0" ;
        zspace:vartype = "dimension____" ;
        zspace:start = -42. ;
        zspace:spacing = "regular__" ;
        zspace:alignment = "centre" ;
        zspace:direction_cosines = 0., 0., 1. ;
        zspace:comments = "Z increases from patient inferior to superior" ;
        zspace:units = "mm" ;
        zspace:varid = "MINC standard variable" ;
        zspace:length = 102 ;
        zspace:step = 1. ;
    int acquisition ;
        acquisition:version = "MINC Version    1.0" ;
        acquisition:vartype = "group________" ;
        acquisition:varid = "MINC standard variable" ;
    int patient ;
        patient:version = "MINC Version    1.0" ;
        patient:vartype = "group________" ;
        patient:varid = "MINC standard variable" ;
    int study ;
        study:version = "MINC Version    1.0" ;
        study:vartype = "group________" ;
        study:varid = "MINC standard variable" ;

// global attributes:
        :ident = "stilley2:localhost.localdomain:2019.10.23.17.23.27:28228:1" ;
        :minc_version = "2.4.04" ;
        :history = "Wed Oct 23 17:23:27 2019>>> nii2mnc in.nii out.mnc\n",
            "" ;
data:

 image-min = 0 ;

 image-max = 1030199 ;

 xspace = 0 ;

 yspace = 0 ;

 zspace = 0 ;

 acquisition = 0 ;

 patient = 0 ;

 study = 0 ;
}

bad file header (out_ndc.mnc)

hdf5 out_ndc {
dimensions:
    xspace = 100 ;
    yspace = 101 ;
    zspace = 102 ;
variables:
    double image(zspace, yspace, xspace) ;
        image:version = "MINC Version    1.0" ;
        image:vartype = "group________" ;
        image:valid_range = 0., 1030199. ;
        image:varid = "MINC standard variable" ;
        image:complete = "true_" ;
        image:dimorder = "zspace,yspace,xspace" ;
    double image-min ;
        image-min:version = "MINC Version    1.0" ;
        image-min:vartype = "var_attribute" ;
        image-min:varid = "MINC standard variable" ;
    double image-max ;
        image-max:version = "MINC Version    1.0" ;
        image-max:vartype = "var_attribute" ;
        image-max:varid = "MINC standard variable" ;
    int xspace ;
        xspace:version = "MINC Version    1.0" ;
        xspace:vartype = "dimension____" ;
        xspace:start = -40. ;
        xspace:spacing = "regular__" ;
        xspace:alignment = "centre" ;
        xspace:comments = "X increases from patient left to right" ;
        xspace:units = "mm" ;
        xspace:varid = "MINC standard variable" ;
        xspace:length = 100 ;
        xspace:step = 1. ;
    int yspace ;
        yspace:version = "MINC Version    1.0" ;
        yspace:vartype = "dimension____" ;
        yspace:start = -41. ;
        yspace:spacing = "regular__" ;
        yspace:alignment = "centre" ;
        yspace:comments = "Y increases from patient posterior to anterior" ;
        yspace:units = "mm" ;
        yspace:varid = "MINC standard variable" ;
        yspace:length = 101 ;
        yspace:step = 1. ;
    int zspace ;
        zspace:version = "MINC Version    1.0" ;
        zspace:vartype = "dimension____" ;
        zspace:start = -42. ;
        zspace:spacing = "regular__" ;
        zspace:alignment = "centre" ;
        zspace:comments = "Z increases from patient inferior to superior" ;
        zspace:units = "mm" ;
        zspace:varid = "MINC standard variable" ;
        zspace:length = 102 ;
        zspace:step = 1. ;
    int acquisition ;
        acquisition:version = "MINC Version    1.0" ;
        acquisition:vartype = "group________" ;
        acquisition:varid = "MINC standard variable" ;
    int patient ;
        patient:version = "MINC Version    1.0" ;
        patient:vartype = "group________" ;
        patient:varid = "MINC standard variable" ;
    int study ;
        study:version = "MINC Version    1.0" ;
        study:vartype = "group________" ;
        study:varid = "MINC standard variable" ;

// global attributes:
        :ident = "stilley2:localhost.localdomain:2019.10.23.17.23.27:28228:1" ;
        :minc_version = "2.4.04" ;
        :history = "Wed Oct 23 17:23:27 2019>>> nii2mnc in.nii out.mnc\n",
            "" ;
data:

 image-min = 0 ;

 image-max = 1030199 ;

 xspace = 0 ;

 yspace = 0 ;

 zspace = 0 ;

 acquisition = 0 ;

 patient = 0 ;

 study = 0 ;
}
stilley2 commented 4 years ago

From here: "direction_cosines - Numeric vector with 3 elements giving the direction cosines of the axes. Although axes are labeled x, y and z, they may in fact have a significantly different orientation - this attribute allows the direction relative to the true axes to be specified exactly. The vectors should be normalized unit vectors.

If these attributes are not present, they are assumed to have the following default values:

For xspace: (1, 0, 0), for yspace: (0, 1, 0), and for zspace: (0, 0, 1)"

So I believe the issue is 2, a corner case in mnc2nii

stilley2 commented 4 years ago

Additionally, I believe other programs besides inormalize do this, although I haven't tracked them down.

gdevenyi commented 4 years ago

Thanks, my next stop was to check the file format docs.

We need to determine now if the problem is in mnc2nii or in miattget.

gdevenyi commented 4 years ago

Also, I've been bitten by this bug, here's my report https://github.com/BIC-MNI/minc-tools/issues/69

You figured out the root cause in terms of the difference in files :)

stilley2 commented 4 years ago

If you're interested, here's my temporary workaround to set the default direction_cosine

gdevenyi commented 4 years ago

Working on this today, some updates:

  1. miattget does not modify the direction cosines if direction cosines are not specified in the minc file, it remains to be seen if the API should return the spec-specified values if none are in the file
  2. The loop around this code which sets the cosines depends on the ordering of the dimensions in the minc file, so, for your files, "zspace,yspace,xspace", the direction cosines end up being defined as "0 0 1; 0 1 0; 1 0 0", which is wrong, it should be "1 0 0; 0 1 0; 0 0 1" and since miattget doesn't fix that. If I do, mincresahpe -dimorder xspace,yspace,zspace out_ndc.mnc reshape.mnc, mnc2nii correctly converts that file, despite there still being no direction cosines in the file.

So there are two possible solutions here

  1. Fix mnc2nii to always use the same x,y,z apparent ordering. This may have other interactions in the code, so I don't like it.
  2. Fix miattget to return the default cosines when none are in the file. I prefer this, but I need to go and learn where this code is.
vfonov commented 4 years ago

miattget is low level call it's not supposed to know about default values of some attributes.

gdevenyi commented 4 years ago

Thanks @vfonov I dug through the code and came to the same conclusion. I also found that mnc2nii uses minc1 API so ordering control isn't available.

As such I've been digging through the logic to see how I can fix nii2mnc

gdevenyi commented 4 years ago

Fixed.