Odd boundaries in LN2_PHASE_JOLT outputs

Summary of what happened:

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):

LN2_PHASE_JOLT \
    -input $echo_file \
    -int13 \
    -phase_jump \
    -2D \
    -output $out_prefix

Version:

v2.8.0

Environment (Docker, Singularity / Apptainer, custom installation):

Linux64 distribution. No container.

Data formatted according to a validatable standard? Please provide the output of the validator:

n/a

Relevant log outputs (up to 20 lines):

n/a

Screenshots / relevant information:

Phase jump

Phase jolt

1 Like

Hi @tsalo ,

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?

1 Like

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?

1 Like

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.

Phase jolt

Phase jump

1 Like

Cool. Great that this is figured out. Yes the output looks correct now :smiley: