Skip to content

discrepancy in writing/reading CIFTI #603

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

Closed
mgxd opened this issue Feb 23, 2018 · 11 comments
Closed

discrepancy in writing/reading CIFTI #603

mgxd opened this issue Feb 23, 2018 · 11 comments

Comments

@mgxd
Copy link
Member

mgxd commented Feb 23, 2018

I'm using data from Nifti/Gifti files to generate a Cifti2Image - my approach is inspired by

def test_dtseries():
series_map = create_series_map((0, ))
geometry_map = create_geometry_map((1, ))
matrix = ci.Cifti2Matrix()
matrix.append(series_map)
matrix.append(geometry_map)
hdr = ci.Cifti2Header(matrix)
data = np.random.randn(13, 9)
img = ci.Cifti2Image(data, hdr)
with InTemporaryDirectory():
ci.save(img, 'test.dtseries.nii')

This outputs a seemingly fine CIFTI file, which is successfully interpreted as a Cift2Image when opened with nibabel.cifti2.load, but when using nibabel.load it is interpreted as a Nifti2Image instead.

> nb.cifti2.load('test.dtseries.nii')
<nibabel.cifti2.cifti2.Cifti2Image at 0x2ad17ea6add8>
> nb.load('test.dtseries.nii')
<nibabel.nifti2.Nifti2Image at 0x2ad24bdadb00>

Here's the sniff of the test-generated image I grabbed while debugging

(b'\x1c\x02\x00\x00n+2\x00\r\n\x1a\n@\x00@\x00\x06\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\r\x00\x00\x00\x00\x00\x00\x00\t\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf0?\x00\x00\x00\x00\x00\x00\xf0?\x00\x00\x00\x00\x00\x00\xf0?\x00\x00\x00\x00\x00\x00\xf0?\x00\x00\x00\x00\x00\x00\xf0?\x00\x00\x00\x00\x00\x00\xf0?\x00\x00\x00\x00\x00\x00\xf0?\x00\x00\x00\x00\x00\x00\xf0?\x80\x06\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf0?\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00`\x04\x00\x00 \x00\x00\x00<CIFTI Version="2.0"><Matrix><MatrixIndicesMap AppliesToMatrixDimension="0" IndicesMapToDataType="CIFTI_INDEX_TYPE_SERIES" NumberOfSeriesPoints="13" SeriesExponent="-3" SeriesStart="18.2" SeriesStep="10.5" SeriesUnit="SECOND" /><MatrixIndicesMap AppliesToMatrixDimension="1" IndicesMapToDataType="CIFTI_INDEX_TYPE_BRAIN_MODELS"><BrainModel BrainStructure="CIFTI_STRUCTURE_THALAMUS_LEFT" IndexCount="4" IndexOffset="0" ModelType="CIFTI_MODEL_TYPE_VOXELS"><VoxelIndicesIJK>6', 'test.dtseries.nii')

Making of note of this here as it will require a bit more inspection.

@satra
Copy link
Member

satra commented Feb 23, 2018

it also needs to be added that a cifti file from hcp is loaded fine by nb.load

@effigies
Copy link
Member

effigies commented Feb 23, 2018

What's the intent code of your image?

def _valid_intent_code(klass, intent_code):
""" Return True if `intent_code` matches our class `klass`
"""
return intent_code >= 3000 and intent_code < 3100
@classmethod
def may_contain_header(klass, binaryblock):
if not super(_Cifti2AsNiftiHeader, klass).may_contain_header(binaryblock):
return False
hdr = klass(binaryblock=binaryblock[:klass.sizeof_hdr])
return klass._valid_intent_code(hdr.get_intent('code')[0])

Try:

img = nb.cifti2.load('test.dtseries.nii')
nb.cifti2._parse_cifti2._Cifti2AsNiftiHeader(img.header).get_intent('code')

You may need to tweak that line to observe the right result, but I think that's likely to be the check that's failing.

@mgxd
Copy link
Member Author

mgxd commented Feb 23, 2018

@effigies

an hcp file:

(Pdb) hdr.get_intent('code')[0]
3002

our generated file:

(Pdb) hdr.get_intent('code')[0]
0

@satra
Copy link
Member

satra commented Feb 23, 2018

aha - so that's what needs to be set.

@effigies
Copy link
Member

I see. So we're not exposing some necessary NIFTI functionality through Cifti2Header, such as set_intent.

This may require some thinking about how to properly provide access to both the binary and XML portions of the header, but in the short term, you should be able to take your Cifti2Image, coerce it to a Nifti2Image, and set the intent code.

@satra
Copy link
Member

satra commented Feb 23, 2018

however, there is img.nifti_header. we should be able to use that.

@effigies
Copy link
Member

Ah. I guess that was the API that was settled on way back when. @mgxd, does using img.nifti_header.set_intent('NIFTI_INTENT_CONNECTIVITY_DENSE_SERIES') resolve your issue?

@mgxd
Copy link
Member Author

mgxd commented Feb 23, 2018

Looks good, I'll update the tests to include this.

@acamargofb
Copy link

Hi there, I want to save the values of the ciftifile (voxels values) in a matrix. I can read the file with the command
img = nib.cifti2.load(cifti_file)
but how can I get the voxels values ?

Thanks a lot and have a nice day,

Aldo

@acamargofb
Copy link

I solved my problem using the following commands:

new_img = nib.Cifti2Image(np.transpose(matrix), header=img.header, nifti_header=img.nifti_header)
new_img.to_filename('/path/filename.dscalar.nii')
But now my problem is that the output does not show the negative value. How can I do that ?

@effigies
Copy link
Member

Sorry I missed this before. I would recommend creating a new issue rather than posting to a closed thread. When you do, could you provide your full code, with what your inputs are and what you're trying to do?

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