Different FOV errors

Summary of what happened:

I’m using two DWI data with different phase encoding directions. AP, PA, but exactly the same protocol, no fieldmap.

During preprocessing, I got an error message as below.

I have checked other threads related to it, but couldn’t find a correct answer. I’m wondering if there is a solution for this.

Thank you!

Command used (and if a helper script was used, a link to the helper script or the command generated):

singularity run --cleanenv -B /mnt qsiprep-0.19.0.sif /mnt/data /mnt/derivatives participant --participant_label sub-s027 --output-resolution 1.0 --fs-license-file /home/ubuntu/license.txt

Version:

0.19.0

Environment (Docker, Singularity, custom installation):

singularity

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

BIDS

Relevant log outputs (up to 20 lines):

   Traceback (most recent call last):
      File "/usr/local/miniconda/lib/python3.8/site-packages/nipype/interfaces/base/core.py", line 397, in run
        runtime = self._run_interface(runtime)
      File "/usr/local/miniconda/lib/python3.8/site-packages/qsiprep/interfaces/nilearn.py", line 134, in _run_interface
        new_nii = concat_imgs(self.inputs.in_files, dtype=self.inputs.dtype)
      File "/usr/local/miniconda/lib/python3.8/site-packages/nilearn/_utils/niimg_conversions.py", line 525, in concat_niimgs
        for index, (size, niimg) in enumerate(
      File "/usr/local/miniconda/lib/python3.8/site-packages/nilearn/_utils/niimg_conversions.py", line 173, in _iter_check_niimg
        raise ValueError(
    ValueError: Field of view of image #1 is different from reference FOV.
    Reference affine:
    array([[-9.99999523e-01,  6.64567068e-08, -1.97376241e-03,
             1.16642746e+02],
           [ 1.01625075e-04,  9.94690776e-01, -2.05817908e-01,
            -8.59137268e+01],
           [-9.81634832e-04,  1.02909006e-01,  1.98938060e+00,
            -7.16488419e+01],
           [ 0.00000000e+00,  0.00000000e+00,  0.00000000e+00,
             1.00000000e+00]])
    Image affine:
    array([[-9.99999523e-01, -1.72196373e-08, -1.97375729e-03,
             1.16040306e+02],
           [ 1.27203137e-04,  9.91656065e-01, -2.57823318e-01,
            -8.42580261e+01],
           [-9.78646451e-04,  1.28911719e-01,  1.98331118e+00,
            -7.37085190e+01],
           [ 0.00000000e+00,  0.00000000e+00,  0.00000000e+00,
             1.00000000e+00]])
    Reference shape:
    (224, 224, 75)
    Image shape:
    (224, 224, 75, 72)

Screenshots / relevant information:

Hi @kay1 , it looks like there are different fields of view in your images. If the scanner re-shimmed between the two acquisitions then your distortion correction is going to be off. That’s why there’s a strict check here.

If you’re confident that there wasn’t a re-shimming between your acquisitions you can manually copy the affine from one of your images into the other (eg the affine from the dir-AP_dwi to the dir-PA_dwi).

Thank you! it worked!

Got the same error. Proposed solution worked for me.
For anyone else encountering the issue, here is a script to overwrite the affines to make sure they are exactly the same if they are already quite close:
(script to be used at your own risk, adapt if necessary)

#!/usr/bin/env python3
import argparse
import os
import shutil
import numpy as np
from bids import BIDSLayout

def compare_affines(affine1, affine2, tol=1e-3):
    """Compare two affine matrices within a tolerance."""
    return np.allclose(affine1, affine2, atol=tol)

def main():
    parser = argparse.ArgumentParser(description="Check and optionally overwrite DWI affine matrices in BIDS datasets.")
    parser.add_argument("rawdata", type=str, help="Path to the BIDS dataset folder.")
    parser.add_argument("--keep-original", action="store_true", default=True,
                        help="Keep a backup of the original data before overwriting (default: True).")
    args = parser.parse_args()

    layout = BIDSLayout(args.rawdata, derivatives=False)
    subjects = layout.get_subjects()

    for subject in subjects:
        print(f"\nProcessing subject: {subject}")

        # Get all DWI files for the subject
        dwi_files = layout.get(
            subject=subject,
            datatype="dwi",
            extension=["nii", "nii.gz"],
            return_type="file"
        )

        if not dwi_files:
            print(f"  No DWI data found for subject {subject}. Skipping.")
            continue

        # Check if there are exactly two DWI files (AP and PA)
        if len(dwi_files) != 2:
            raise ValueError(f"Expected exactly 2 DWI files for subject {subject}, found {len(dwi_files)}.")

        # Sort files by direction (AP and PA)
        ap_file = None
        pa_file = None
        for f in dwi_files:
            if "dir-AP" in f:
                ap_file = f
            elif "dir-PA" in f:
                pa_file = f

        if not ap_file or not pa_file:
            raise ValueError(f"Could not identify AP and PA files for subject {subject}.")

        print(f"  Found AP: {os.path.basename(ap_file)}")
        print(f"  Found PA: {os.path.basename(pa_file)}")

        # Load the images and their affines
        from nibabel import load
        img_ap = load(ap_file)
        img_pa = load(pa_file)
        affine_ap = img_ap.affine
        affine_pa = img_pa.affine

        # Compare affines
        if np.array_equal(affine_ap, affine_pa):
            print(f"  Affines are identical for subject {subject}. Skipping.")
            continue

        if compare_affines(affine_ap, affine_pa):
            print(f"  Affines are loosely matched for subject {subject}. Skipping.")
            continue

        print(f"  Affines do not match for subject {subject}. Overwriting PA affine with AP affine.")

        # Backup if required
        if args.keep_original:
            backup_pa = pa_file.replace(".nii", "_backup.nii").replace(".nii.gz", "_backup.nii.gz")
            shutil.copy2(pa_file, backup_pa)
            print(f"  Backup created: {os.path.basename(backup_pa)}")

        # Overwrite the affine of the PA image
        from nibabel import Nifti1Image
        new_img_pa = Nifti1Image(img_pa.get_fdata(), affine_ap, img_pa.header)
        new_img_pa.to_filename(pa_file)
        print(f"  Affine of {os.path.basename(pa_file)} overwritten with affine from {os.path.basename(ap_file)}.")

if __name__ == "__main__":
    main()