mhe / pynrrd

Simple pure-python module for reading and writing nrrd files.
https://pynrrd.readthedocs.io/
MIT License
116 stars 51 forks source link

Write NRRD file with header 'space origin' has format bug #82

Closed gliu2 closed 5 years ago

gliu2 commented 5 years ago

Writing an NRRD with the 'space origin' header key (to specify spatial translation of CT scan) requires an input of type NRRD vector for the CT origin. However using the function nrrd.format_optional_vector creates a vector as a string (e.g. '(3,4,1)') which triggers the following error when writing an NRRD file:

TypeError: ufunc 'isnan' not supported for the input types, and the inputs could not be safely coerced to any supported types according to the casting rule ''safe''

This is the code I am running:

nrrd.write(os.path.join(foldername, filename), M_out, detached_header=False, header={'sizes': size_image, 'spacings': spacing, 'space origin':nrrd.format_optional_vector(origin)})

I believe this bug can be corrected by changing line 81 of formatters.py from: if x is None or np.all(np.isnan(x)): to: if x is None or np.all(pd.isnull(x)): after adding an 'import panda as pd' line to beginning of code.

Thanks

addisonElliott commented 5 years ago

Is there a reason you need to call nrrd.format_optional_vector on the code?

nrrd.format_<TYPE_HERE> will automatically be called by nrrd.write for known datatypes. I cannot see a use case where the user would want to supply the formatted string themselves.

The nrrd.format_<TYPE_HERE> functions are provided in case the user wants to use them for custom fields in the NRRD header.

So you should be able to do this:

nrrd.write(os.path.join(foldername, filename), M_out, detached_header=False, header={
    'sizes':  size_image, 
    'spacings': spacing, 
    'space origin': origin
})
gliu2 commented 5 years ago

No particular reason for calling nrrd.format_optional_vector on the code. My NRRD output, when I specify 'space origin': origin (where origin is a vector ndarray of floats) produces an NRRD image that does not visualize in 3D Slicer. When I remove that key (just have 'sizes' and 'spacings' in the header) the NRRD output does visualize in 3D Slicer. Therefore I was trying other inputs to to the 'space origin' key.

addisonElliott commented 5 years ago

Okay, I understand. As far as I can tell, this is probably not an issue with the pynrrd library.

If you want to experiment, open the NRRD file in your notepad editor and manually add a space origin: (0, 0, 0) line or something similar. Once you get that working in 3D Slicer, then you should be able to write Python code that will do it.

My first guess as to why it won't display in 3D Slicer is that 3D Slicer is not not centering the camera over the object for some reason. When the origin is missing, I assume it defaults to (0, 0, 0) and then 3D Slicer displays the camera there.

ihnorton commented 5 years ago

See here for some background: https://www.slicer.org/wiki/Coordinate_systems

@gliu2 if you need to DICOM->NRRD conversion, you will probably save a lot time using dcm2niix -- which now has both Nifti and NRRD output (both supported by Slicer), or one of Slicer's built-in importers. At very least those converters will give you a good baseline to compare to.

If you are writing NRRDs from scratch (e.g. for simulation output or something), and you get stuck, I suggest posting on https://discourse.slicer.org for help with making a NRRD that Slicer will interpret correctly. Addison's suggestion to manually edit is spot-on.