Ejemplo n.º 1
0
    def test_prepare_fieldmap_2_echoes(self):
        """Test 2 echoes works."""

        # Import 2 echoes and rescale
        fname_phase1 = os.path.join(__dir_testing__, 'sub-fieldmap', 'fmap',
                                    'sub-fieldmap_phase1.nii.gz')
        nii_phase1 = nib.load(fname_phase1)
        phase1 = (nii_phase1.get_fdata() * 2 * math.pi / 4095) - math.pi
        fname_phase2 = os.path.join(__dir_testing__, 'sub-fieldmap', 'fmap',
                                    'sub-fieldmap_phase2.nii.gz')
        nii_phase2 = nib.load(fname_phase2)
        phase2 = (nii_phase2.get_fdata() * 2 * math.pi / 4095) - math.pi

        # Load mag data to speed it prelude
        fname_mag = os.path.join(__dir_testing__, 'sub-fieldmap', 'fmap',
                                 'sub-fieldmap_magnitude1.nii.gz')
        mag = nib.load(fname_mag).get_fdata()

        echo_times = [0.0025, 0.0055]

        fieldmap = prepare_fieldmap([phase1, phase2],
                                    echo_times,
                                    nii_phase1.affine,
                                    mag=mag)

        assert fieldmap.shape == phase1.shape
Ejemplo n.º 2
0
def prepare_fieldmap_cli(phase, fname_mag, unwrapper, fname_output, fname_mask, threshold, gaussian_filter, sigma):
    """Creates fieldmap (in Hz) from phase images. This function accommodates multiple echoes (2 or more) and phase
    difference. This function also accommodates 4D phase inputs, where the 4th dimension represents the time, in case
    multiple field maps are acquired across time for the purpose of real-time shimming experiments.

    phase: Input path of phase nifti file(s), in ascending order: echo1, echo2, etc.
    """

    # Import phase
    list_phase = []
    echo_times = []
    for i_echo in range(len(phase)):
        nii_phase, json_phase, phase_img = read_nii(phase[i_echo], auto_scale=True)
        # Add pi since read_nii returns phase between 0 and 2pi whereas prepare_fieldmap accepts between -pi to pi
        phase_img -= math.pi

        list_phase.append(phase_img)
        # Special case for echo_times if input is a phasediff
        if len(phase) == 1:
            # Check that the input phase is indeed a phasediff, by checking the existence of two echo times in the
            # metadata
            if not ('EchoTime1' in json_phase) or not ('EchoTime2' in json_phase):
                raise RuntimeError(
                    "The JSON file of the input phase should include the fields EchoTime1 and EchoTime2 if"
                    "it is a phase difference.")
            echo_times = [json_phase['EchoTime1'], json_phase['EchoTime2']]  # [s]
        else:
            echo_times.append(json_phase['EchoTime'])

    # Get affine from nii
    affine = nii_phase.affine

    # If fname_mag is not an input define mag as None
    if fname_mag is not None:
        mag = nib.load(fname_mag).get_fdata()
    else:
        mag = None

    # Import mask
    if fname_mask is not None:
        mask = nib.load(fname_mask).get_fdata()
    else:
        mask = None

    fieldmap_hz = prepare_fieldmap(list_phase, echo_times, affine, mag=mag, unwrapper=unwrapper, mask=mask,
                                   threshold=threshold, gaussian_filter=gaussian_filter, sigma=sigma)

    # Save NIFTI
    nii_fieldmap = nib.Nifti1Image(fieldmap_hz, affine)
    nib.save(nii_fieldmap, fname_output)

    # Save json
    json_fieldmap = json_phase
    if len(phase) > 1:
        for i_echo in range(len(echo_times)):
            json_fieldmap[f'EchoTime{i_echo + 1}'] = echo_times[i_echo]
    fname_json = fname_output.rsplit('.nii', 1)[0] + '.json'
    with open(fname_json, 'w') as outfile:
        json.dump(json_fieldmap, outfile, indent=2)
Ejemplo n.º 3
0
    def test_prepare_fieldmap_with_mag(self):
        """Test mag works."""
        fieldmap = prepare_fieldmap([self.phase],
                                    self.echo_times,
                                    self.affine,
                                    mag=self.mag)

        assert fieldmap.shape == self.phase.shape
Ejemplo n.º 4
0
    def test_prepare_fieldmap_1_echo(self):
        """Test default works."""
        fieldmap = prepare_fieldmap([self.phase], self.echo_times, self.affine)

        assert fieldmap.shape == self.phase.shape
        # If the behaviour of the called function is modified, this assertion below should capture it:
        assert np.all(
            np.isclose(
                fieldmap[30:35, 40, 0, 0],
                np.array([
                    18.51355514, 13.84794053, 9.48013154, 5.11232207,
                    0.64524454
                ])))
Ejemplo n.º 5
0
    def test_prepare_fieldmap_wrong_range(self):
        """Test error when range is not between -pi and pi."""

        # This should return an error
        try:
            fieldmap = prepare_fieldmap([self.phase - math.pi],
                                        self.echo_times, self.affine)
        except RuntimeError:
            # If an exception occurs, this is the desired behaviour
            return 0

        # If there isn't an error, then there is a problem
        print("\nRange is not between -pi and pi but does not throw an error.")
        assert False
Ejemplo n.º 6
0
    def test_prepare_fieldmap_phasediff_1_echotime(self):
        """EchoTime of length one for phasediff should fail."""

        # This should return an error
        try:
            fieldmap = prepare_fieldmap([self.phase], [self.echo_times[0]],
                                        self.affine)
        except RuntimeError:
            # If an exception occurs, this is the desired behaviour
            return 0

        # If there isn't an error, then there is a problem
        print("\necho_time has the wrong shape but does not throw an error.")
        assert False
Ejemplo n.º 7
0
    def test_prepare_fieldmap_wrong_echo_times(self):
        """Wrong number of echo times."""

        echo_times = [0.001, 0.002, 0.003]

        # This should return an error
        try:
            fieldmap = prepare_fieldmap([self.phase], echo_times, self.affine)
        except RuntimeError:
            # If an exception occurs, this is the desired behaviour
            return 0

        # If there isn't an error, then there is a problem
        print(
            "\nEcho_times has too many elements but does not throw an error.")
        assert False
Ejemplo n.º 8
0
    def test_prepare_fieldmap_3_echoes(self):
        """3 echoes are not implemented so the test should fail."""

        echo_times = [0.001, 0.002, 0.003]

        # This should return an error
        try:
            fieldmap = prepare_fieldmap([self.phase, self.phase, self.phase],
                                        echo_times, self.affine)
        except NotImplementedError:
            # If an exception occurs, this is the desired behaviour
            return 0

        # If there isn't an error, then there is a problem
        print("\n3 echoes are not implemented.")
        assert False
Ejemplo n.º 9
0
    def test_prepare_fieldmap_mask_wrong_shape(self):
        """Mask has the wrong shape."""

        # This should return an error
        try:
            fieldmap = prepare_fieldmap([self.phase],
                                        self.echo_times,
                                        self.affine,
                                        mask=np.zeros_like([5, 5]))
        except RuntimeError:
            # If an exception occurs, this is the desired behaviour
            return 0

        # If there isn't an error, then there is a problem
        print("\nMask has the wrong shape but does not throw an error.")
        assert False
Ejemplo n.º 10
0
    def test_prepare_fieldmap_gaussian_filter(self):
        """ Test output of gaussian filter optional argument"""

        fieldmap = prepare_fieldmap([self.phase],
                                    self.echo_times,
                                    self.affine,
                                    gaussian_filter=True,
                                    sigma=1)

        assert fieldmap.shape == self.phase.shape
        # If the behaviour of the called function is modified, this assertion below should capture it:
        assert np.all(
            np.isclose(
                fieldmap[30:35, 40, 0, 0],
                np.array([
                    19.46307638, 15.46251356, 11.05021768, 6.28096375,
                    1.30868717
                ])))