Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
stilley2 opened this issue Oct 23, 2019 · 13 comments

Comments

@stilley2
Copy link

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
Copy link
Author

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

@gdevenyi
Copy link

Hi,

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

@gdevenyi
Copy link

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.
2. could be a corner case of the code. Will investigate.

@stilley2
Copy link
Author

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
Copy link
Author

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
Copy link
Author

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

@gdevenyi
Copy link

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
Copy link

Also, I've been bitten by this bug, here's my report #69

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

@stilley2
Copy link
Author

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

@gdevenyi
Copy link

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
Copy link
Member

vfonov commented Nov 25, 2019

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

@gdevenyi
Copy link

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
Copy link

Fixed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants