I am trying out laynii’s LN2_PHASE_JOLT on low-resolution multi-echo fMRI data (2 mm isotropic voxels), and I noticed that there are hard boundaries in the resulting phase jump/jolt images. I’m wondering if this is a known issue in these derivatives, or if I need to do some processing first. I was under the impression that phase unwrapping was unnecessary for phase jump/jolt calculation, but if necessary I can do that first.
Command used (and if a helper script was used, a link to the helper script or the command generated):
Could you let me know what is the range of the values in your input nifti? Eg are they between 0-4095, or -pi to pi, or something else?
When these hard edges occur, it is often due to discrepancy between the input values and the programs setup/parameters. You do not need to unwrap first, thats the whole point of this program as the unwrapping in handled during derivative computation across voxel pairs through circular subtraction.
The values are between 0 and 4094. The only processing I’ve done is to split no-excitation-pulse volumes out of the end of the run with nibabel, which might have changed the intercept and slope in the NIfTI. (The contents are still fine though)
The sequence is 2D, but I did notice that the -2D flag was experimental. Could that be the problem?
Hmm, it might be that you have a non standard 2D axis, or the slope and intercept indeed can cause trouble. I think this might need to be solved by me looking into your input nifti carefully.
Do you mind sending me an example nifti? Either though here or LayNii issues on github?
The odd boundaries are caused by the input image having zeroed-out negative values (thanks @tsalo for sending me and example nifti). The correct voxel value range should be -4096 to +4096, but the input only contains values from 0 to 4096. After further inspection, it appears that the negative values have been set to zero in the NIfTI file (see screenshot, red are exact 0’s). This means that meaningful phase operations cannot be performed with these NIfTIs, as too much data is unnaturally missing. This explains the hard edges and perfectly smooth black regions visible in the original post.
The issue is likely due to a dicom to nifti conversion bug, or maybe a small step that required nifti read-write after conversion.
I was setting the slope and intercept of my phase files when I saved them out so that I could run NORDIC on them, but I didn’t realize that the phase NIfTIs were using unsigned ints. When I changed the slope and intercept, the datatype wasn’t automatically updated, so all of the negative values were being dropped.
Here’s some code to break things the way I did:
import nibabel as nb
N_NOISE_VOLS = 3
img = nb.load("/path/to/phase/file.nii.gz")
img = img.slicer[..., :-N_NOISE_VOLS]
img.header.set_slope_inter(1, 0)
img.to_filename("out.nii.gz") # negative values are set to zero
What I should have done (and am now doing) is set the datatype to allow negative integers.
import nibabel as nb
import numpy as np
N_NOISE_VOLS = 3
img = nb.load("/path/to/phase/file.nii.gz")
img = img.slicer[..., :-N_NOISE_VOLS]
img.header.set_slope_inter(1, 0)
img.header.set_data_dtype(np.int16)
img.to_filename("out.nii.gz") # negative values are retained
@ofgulban thank you for figuring this out! The jump and jolt results look much better now.