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

I am not able to read a nrrd file saved from Slicer (volume sequence) #71

Closed
jcnils opened this issue Nov 6, 2018 · 13 comments
Closed
Assignees

Comments

@jcnils
Copy link
Contributor

jcnils commented Nov 6, 2018

To read the nrrd volume works perfectly if I save it as single volume using Slicer, but if I save it as volume sequence I find the following errors:

#both return the same errors

filedata, fileheader = nrrd.read(VOL0)
fileheader = nrrd.read_header(VOL0)

File "...\nrrd\reader.py", line 209, in read_header
header = read_header(fh, custom_field_map)
File "...\nrrd\reader.py", line 261, in read_header
raise NRRDError(dup_message)
nrrd.errors.NRRDError: Duplicate header field: 'space'

filedata = nrrd.read_data(VOL0)

filedata = nrrd.read_data(VOL0)

File "...\nrrd\reader.py", line 313, in read_data
raise NRRDError('Header is missing required field: "%s".' % field)
nrrd.errors.NRRDError: Header is missing required field: "dimension".

When I realized that the problem is with sequences, I thought sequences are not the focus of the library, but I am opening this just in case.
Thanks

@addisonElliott
Copy link
Collaborator

Will need to look at this later. Can you provide a copy of the NRRD file that is causing problems?

@tashrifbillah
Copy link
Contributor

I think it's already telling us that there is a duplicate header field. @jcnils
Can you modify the header to omit any duplicity and write back with nrrd.write() and then check?

@addisonElliott
Copy link
Collaborator

Also, @ihnorton made a PR (#65) that allows overriding of duplicate field headers, but it is not well documented.

nrrd.ALLOW_DUPLICATE_FIELD = True

# Will ignore duplicate fields now
nrrd.read(...)

@jcnils
Copy link
Contributor Author

jcnils commented Nov 7, 2018

Thank you for the reply @addisonElliott , I asked the lab for the anonymized data or one volume sequence with the phantom. But I got the same problem with the dataset from 3D Slicer.

@tashrifbillah I could not find a way to edit the header on the 3D Slicer natively, and I still need a way to load the binaries in an array before writing it back. I will try to do it using the simpleitk.io

CTP-cardio.zip

#CTP is just one image from the sequence, and works properly


CTP = r'CTP-cardio.nrrd'
CTPSEQ = r'CTP-cardio.seq.nrrd'

def main():

    filedata, fileheader = nrrd.read(CTP)

    print (fileheader)

    nrrd.ALLOW_DUPLICATE_FIELD = True

    print(nrrd.ALLOW_DUPLICATE_FIELD)

    filedata, fileheader = nrrd.read(CTPSEQ)

    print(fileheader)



if __name__ == "__main__":
    main()

@jcnils
Copy link
Contributor Author

jcnils commented Nov 7, 2018

@tashrifbillah I managed to read it using simpleitk, then write it as you told. I was able to open the new file with pynrrd.

I noticed that simpleitk and 3d slicer deal with the sequence as being components instead of an x+1 array, in this case a 3D data with 26 components.

When I export it to a numpy array it becomes a 4D array instead, and can be written/read by pynrrd. But I cannot open it as a sequence on the 3D slicer again, instead I get a really weird image.

import SimpleITK as sitk
import numpy as np
import nrrd

CTPSEQ = r'CTP-cardio.seq.nrrd'

reader = sitk.ImageFileReader()
reader.SetFileName(CTPSEQ)
image = reader.Execute()
nda = sitk.GetArrayFromImage(image)
print (nda)
filename = 'testdata.nrrd'

nrrd.write(filename, nda)

@addisonElliott
Copy link
Collaborator

addisonElliott commented Nov 8, 2018

Alright, finally got some time to take a look at this. I was able to get your NRRD file loaded without using SimpleITK. There are two ways to do this.

Method 1

The first way is to edit the NRRD file manually to remove the duplicate fields. Not sure how familiar you are with the NRRD file format, but the headers is just text at the beginning of the file. Thus, you can open the NRRD file with your text editor and remove the additional space line.

Here is what the header of the CTP-cardio-seg.nrrd looks like:

NRRD0005
# Complete NRRD file format specification at:
# http://teem.sourceforge.net/nrrd/format.html
type: int
dimension: 4
space: right-anterior-superior
sizes: 26 102 102 61
space directions: none (1.9531249999999991,0,0) (0,1.9531249999999991,0) (0,0,1.9531249999999991)
kinds: list domain domain domain
labels: "frame" "" "" ""
endian: little
encoding: gzip
space origin: (-137.16099548339844,-36.806499481201172,-309.71899414062506)
measurement frame: (1,0,0) (0,1,0) (0,0,1)
axis 0 index type:=numeric
axis 0 index values:=0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
space:=right-anterior-superior

The duplicate line is the space field at the very bottom. If you remove that line and try again, it works fine.

Method 2

If you want to ignore any duplicate field errors like I mentioned, then there is some code to do this. The snippet of code I gave you earlier was wrong and doesn't work. Here is what does work:

import nrrd

CTPSEQ = 'CTP-cardio.seq.nrrd'

nrrd.reader.ALLOW_DUPLICATE_FIELD = True
data, header = nrrd.read(CTPSEQ)
nrrd.reader.ALLOW_DUPLICATE_FIELD = False

Note: In your snippet, you use r to prefix the string. This is used for regex strings. Not necessary for a normal string.

With that in mind, you're welcome to keep using SimpleITK but it takes a few more lines that what is required for pynrrd. In addition, I'm not sure if saving the NRRD file will cause issues with loading it in 3D Slicer again. I have loaded .seg.nrrd files and saved them before using pynrrd and I was able to load it back into 3D Slicer.

@addisonElliott
Copy link
Collaborator

@ihnorton @tashrifbillah I don't understand why but Slicer sometimes adds duplicate fields to NRRD files. For new users who just want to load in their NRRD, I think it can be difficult to know to use the ALLOW_DUPLICATE_FIELD switch.

What do you think about the following?

  • Adding documentation for ALLOW_DUPLICATE_FIELD switch with explicit warning that the user should verify that the duplicate fields are the same data.
  • One benefit to pynrrd is being able to load NRRD files in a single line with nrrd.read. For duplicate fields in the header, this paradigm is broken and now a second line must be used to activate the feature. Add a allow_duplicate_field entry to the nrrd.read method.
    • Once again, maybe this includes a warning in the documentation that it should be used at the user's risk.

@ihnorton
Copy link
Contributor

ihnorton commented Nov 8, 2018

@jcnils what version of Slicer are you using? I think I fixed the duplicate field issue in the last few months (but I didn't try with sequences).

@ihnorton
Copy link
Contributor

ihnorton commented Nov 8, 2018

@addisonElliott documentation and a suggestion in the duplicate field error would be helpful, for people using software versions with this issue.

@jcnils
Copy link
Contributor Author

jcnils commented Nov 8, 2018

@ihnorton We are using the 4.8.1 in the lab, accordingly to our supervisor there are some modules and libraries not working with the 4.11, in my case I am also using the dtcwt library but the 4.11 didn't install it properly using the pip.

I will post the difficulties we are facing about the last version on slicer forum. It will be ideal to use the newer versions.

this example do not work on slicer 4.11:

pip._internal import main as pipmain
pipmain(['install', 'dtc'])

import dtcwt
trans = dtcwt.Transform3d()

I tried to save the sequence with the 4.11 and it works, no duplicated header. Thank you very much.

@jcnils
Copy link
Contributor Author

jcnils commented Nov 8, 2018

@addisonElliott Thank you ! Both methods are working perfectly.

I managed to open it back on slicer by also writing the header.

I am using this documentation https://media.readthedocs.org/pdf/pynrrd/latest/pynrrd.pdf, it is very useful.

def main():

    nrrd.reader.ALLOW_DUPLICATE_FIELD = True

    print(nrrd.reader.ALLOW_DUPLICATE_FIELD)

    filedata, fileheader = nrrd.read(CTPSEQ)

    print(filedata)
    print(fileheader)

    nrrd.write('output.nrrd', filedata, fileheader)#slicer open this one
    nrrd.write('output_noheader.nrrd', filedata) #slicer cannot open this one

Thank you very much, devs on the lab will be very pleased, since we decided to change file formats to .nrrd people are looking for some reliable way to get the arrays, and this library is perfect for it.

@jcnils jcnils closed this as completed Nov 8, 2018
@addisonElliott
Copy link
Collaborator

Going to leave this open as a reminder to document and add code example for ALLOW_DUPLICATE_FIELD.

Will try and get the PR going this weekend, unless @jcnils is up for the task.

@addisonElliott addisonElliott reopened this Nov 8, 2018
@addisonElliott addisonElliott self-assigned this Nov 8, 2018
@jcnils
Copy link
Contributor Author

jcnils commented Nov 8, 2018

Of course.
I was fixing my example and typing the email to send it to my coworkers on how to use it.

addisonElliott pushed a commit that referenced this issue Nov 9, 2018

Unverified

This commit is not signed, but one or more authors requires that any commit attributed to them is signed.
Documentation update to include the ALLOW_DUPLICATE_FIELD information (#71 )

Create docstring for ALLOW_DUPLICATE_FIELD and compile it into the API reference page. Includes example of how to use field and information on the getting started page about its purpose.

Fix small issue with ALLOW_DUPLICATE_FIELD test that referenced by wrong name.

Also updated the API reference to show the ALLOW_DUPLICATE_FIELD docstring in addition to it being displayed in the table of contents for the reading section.

Update references to True/False & ALLOW_DUPLICATE_FIELD so Sphinx appropriately links to these items.

Also found a small mistake in the tests that was missed originally I decided to fix here. Wasn't worth the extra effort of a separate PR.
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

4 participants