Skip to content

Registration Module

Base Image Normalization API

affine_registration(fixed_image, moving_image, moving_mask=None, template_mask=None, fast_method=True)

Register two images using an affine transformation. This method applies a 3D affine transformation in order to register the moving image to the fixed image.

Parameters:

Name Type Description Default
fixed_image ImageIO

np.ndarray The fixed image as the reference space.

required
moving_image ImageIO

np.ndarray The moving image to be registered.

required
moving_mask ImageIO

np.ndarray, optional The mask of the moving image. If not provided, the moving image will be used as the mask.

None
template_mask ImageIO

np.ndarray, optional The mask of the fixed image. If not provided, the fixed image will be used as the mask.

None

Raises:

Type Description
Exception

fixed_image and moving_image must be a numpy array.

Returns

resampled_image : np.ndarray The moving image transformed into the template image space. transformation_matrix : np.ndarray The transformation matrix mapping from moving to template space.

Source code in asltk/registration/__init__.py
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
def affine_registration(
    fixed_image: ImageIO,
    moving_image: ImageIO,
    moving_mask: ImageIO = None,
    template_mask: ImageIO = None,
    fast_method: bool = True,
):
    """
    Register two images using an affine transformation. This method applies
    a 3D affine transformation in order to register the moving image to the
    fixed image.

    Args:
        fixed_image: np.ndarray
            The fixed image as the reference space.
        moving_image: np.ndarray
            The moving image to be registered.
        moving_mask: np.ndarray, optional
            The mask of the moving image. If not provided, the moving image
            will be used as the mask.
        template_mask: np.ndarray, optional
            The mask of the fixed image. If not provided, the fixed image
            will be used as the mask.

    Raises:
        Exception: fixed_image and moving_image must be a numpy array.

    Returns
    -------
    resampled_image : np.ndarray
        The moving image transformed into the template image space.
    transformation_matrix : np.ndarray
        The transformation matrix mapping from moving to template space.
    """
    if not isinstance(fixed_image, ImageIO) or not isinstance(
        moving_image, ImageIO
    ):
        raise Exception(
            'fixed_image and moving_image must be an ImageIO object.'
        )
    if moving_mask is not None and not isinstance(moving_mask, ImageIO):
        raise Exception('moving_mask must be an ImageIO object.')
    if template_mask is not None and not isinstance(template_mask, ImageIO):
        raise Exception('template_mask must be an ImageIO object.')

    affine_type = 'AffineFast' if fast_method else 'Affine'
    warped_image, transformation_matrix = space_normalization(
        moving_image,
        fixed_image,
        transform_type=affine_type,
        moving_mask=moving_mask,
        template_mask=template_mask,
    )

    return warped_image, transformation_matrix

apply_transformation(moving_image, reference_image, transforms, **kwargs)

Apply a transformation list set to an image.

This method applies a list of transformations to a moving image to align it with a reference image. The transformations are typically obtained from a registration process, such as rigid or affine registration.

Note

The transforms parameter should be a list of transformation matrices obtained from a registration process. The transformations are applied in the order they are provided in the list.

Tip

Additional parameters can be passed to the ants.apply_transforms function using the kwargs parameter. This allows for customization of the transformation process, such as specifying interpolation methods, handling of missing data, etc. See more in the ANTsPy documentation: https://antspy.readthedocs.io/en/latest/registration.html#ants.apply_transforms

Parameters:

Name Type Description Default
image

np.ndarray The image to be transformed.

required
reference_image ImageIO

np.ndarray The reference image to which the transformed image will be aligned. If not provided, the original image will be used as the reference.

required
transforms list

list The transformation matrix list.

required

Returns:

Name Type Description
transformed_image

np.ndarray The transformed image.

Source code in asltk/registration/__init__.py
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
def apply_transformation(
    moving_image: ImageIO,
    reference_image: ImageIO,
    transforms: list,
    **kwargs,
):
    """
    Apply a transformation list set to an image.

    This method applies a list of transformations to a moving image
    to align it with a reference image. The transformations are typically
    obtained from a registration process, such as rigid or affine
    registration.

    Note:
        The `transforms` parameter should be a list of transformation matrices
        obtained from a registration process. The transformations are applied
        in the order they are provided in the list.

    Tip:
        Additional parameters can be passed to the `ants.apply_transforms`
        function using the `kwargs` parameter. This allows for customization of
        the transformation process, such as specifying interpolation methods,
        handling of missing data, etc. See more in the ANTsPy documentation:
        https://antspy.readthedocs.io/en/latest/registration.html#ants.apply_transforms

    Args:
        image: np.ndarray
            The image to be transformed.
        reference_image: np.ndarray
            The reference image to which the transformed image will be aligned.
            If not provided, the original image will be used as the reference.
        transforms: list
            The transformation matrix list.

    Returns:
        transformed_image: np.ndarray
            The transformed image.
    """
    if not isinstance(moving_image, ImageIO):
        raise TypeError('moving image must be an ImageIO object.')

    if not isinstance(reference_image, (ImageIO, BrainAtlas)):
        raise TypeError(
            'reference_image must be an ImageIO object or a BrainAtlas object.'
        )

    if isinstance(reference_image, BrainAtlas):
        reference_image = ImageIO(reference_image.get_atlas()['t1_data'])

    if not isinstance(transforms, list):
        raise TypeError(
            'transforms must be a list of transformation matrices.'
        )

    corr_image = ants.apply_transforms(
        fixed=reference_image.get_as_ants(),
        moving=moving_image.get_as_ants(),
        transformlist=transforms,
        **kwargs,  # Additional parameters for ants.apply_transforms
    )

    out_image = clone_image(reference_image)
    out_image.update_image_data(np.transpose(corr_image.numpy(), (2, 1, 0)))

    return out_image

rigid_body_registration(fixed_image, moving_image, moving_mask=None, template_mask=None)

Register two images using a rigid body transformation. This methods applies a Euler 3D transformation in order to register the moving image to the fixed image.

Note

The registration assumes that the moving image can be adjusted using only rotation and translation, without any scaling or shearing. This is suitable for cases in algiment among temporal volumes, such as in ASL data, where the images are acquired in the same space and only small movements are expected.

Parameters:

Name Type Description Default
fixed_image ImageIO

np.ndarray The fixed image as the reference space.

required
moving_image ImageIO

np.ndarray The moving image to be registered.

required
moving_mask ImageIO

np.ndarray, optional The mask of the moving image. If not provided, the moving image will be used as the mask.

None
template_mask ImageIO

np.ndarray, optional The mask of the fixed image. If not provided, the fixed image will be used as the mask.

None

Raises:

Type Description
Exception

fixed_image and moving_image must be a numpy array.

Exception

moving_mask must be a numpy array.

Exception

template_mask must be a numpy array.

Returns

normalized_image : np.ndarray The moving image transformed into the template image space. transforms : list A list of transformation mapping from moving to template space.

Source code in asltk/registration/__init__.py
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
def rigid_body_registration(
    fixed_image: ImageIO,
    moving_image: ImageIO,
    moving_mask: ImageIO = None,
    template_mask: ImageIO = None,
):
    """
    Register two images using a rigid body transformation. This methods applies
    a Euler 3D transformation in order to register the moving image to the
    fixed image.

    Note:
        The registration assumes that the moving image can be adjusted using
        only rotation and translation, without any scaling or shearing. This
        is suitable for cases in algiment among temporal volumes, such as in
        ASL data, where the images are acquired in the same space and only
        small movements are expected.

    Args:
        fixed_image: np.ndarray
            The fixed image as the reference space.
        moving_image: np.ndarray
            The moving image to be registered.
        moving_mask: np.ndarray, optional
            The mask of the moving image. If not provided, the moving image
            will be used as the mask.
        template_mask: np.ndarray, optional
            The mask of the fixed image. If not provided, the fixed image
            will be used as the mask.

    Raises:
        Exception: fixed_image and moving_image must be a numpy array.
        Exception: moving_mask must be a numpy array.
        Exception: template_mask must be a numpy array.

    Returns
    -------
    normalized_image : np.ndarray
        The moving image transformed into the template image space.
    transforms : list
        A list of transformation mapping from moving to template space.
    """
    if not isinstance(fixed_image, ImageIO) or not isinstance(
        moving_image, ImageIO
    ):
        raise Exception(
            'fixed_image and moving_image must be an ImageIO object.'
        )

    if moving_mask is not None and not isinstance(moving_mask, ImageIO):
        raise Exception('moving_mask must be an ImageIO object.')
    if template_mask is not None and not isinstance(template_mask, ImageIO):
        raise Exception('template_mask must be an ImageIO object.')

    normalized_image, trans_maps = space_normalization(
        moving_image,
        fixed_image,
        transform_type='Rigid',
        moving_mask=moving_mask,
        template_mask=template_mask,
    )

    return normalized_image, trans_maps

space_normalization(moving_image, template_image, moving_mask=None, template_mask=None, transform_type='SyNBoldAff', **kwargs)

Perform brain normalization to register the moving image into the template image space.

This function uses ANTsPy to register a moving image to a template image. Optional masks can be provided for both images. The registration process supports different transformation types.

This is the base method for space normalization, which can be used for different types of images, such as M0, T1w, and ASL images. The method is designed to be flexible and can be used for different types of images, as long as the moving image and template image are provided in the correct format.

Note

For more specific cases, such as ASL data normalization, one can use other methods, such as in asl_normalization module.

Note

Usually the space normalization is performed between the M0 and T1w images. The M0 image is one of the images obtained in the ASL acquisition and the T1w image is the anatomical image template.

Important

The transform_type parameter allows for different types of transformations, such as 'SyN', 'BSpline', etc. The default is 'SyNBoldAff', which is suitable for registering ASL images to a T1-weighted template. All the definitions of the transformation types can be found in the ANTsPy documentation: https://antspy.readthedocs.io/en/latest/registration.html

Important

This method always assumes a template image as a BrainAtlas object. One may pass a string with the name of the atlas, and the method will automatically load the atlas and use the T1-weighted image as the template image. If a different template image is needed, it should be passed as a BrainAtlas object, however, it depends on the ASLtk Kaggle dataset structure, so it is not recommended to raise an issue in the official ASLtk repository if the template image is not presented in the BrainAtlas format.

Parameters

moving_image : np.ndarray The moving image. template_image : BrainAtlas or str or np.ndarray The template image as BrainAtlas object, string with the atlas name or a numpy array. moving_mask : np.ndarray, optional The moving mask in the same space as the moving image. If not provided, no mask is used. template_mask : np.ndarray, optional The template mask in the same space as the template image. If not provided, no mask is used. transform_type : str, optional Type of transformation ('SyN', 'BSpline', etc.). Default is 'SyNBoldAff'. verbose : bool, optional Whether to print detailed orientation analysis. Default is False.

Returns

normalized_image : np.ndarray The moving image transformed into the template image space. transform : list A list of transformation mapping from moving to template space.

Source code in asltk/registration/__init__.py
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
def space_normalization(
    moving_image: ImageIO,
    template_image: BrainAtlas,
    moving_mask: ImageIO = None,
    template_mask: ImageIO = None,
    transform_type: str = 'SyNBoldAff',
    **kwargs,
):
    """
    Perform brain normalization to register the moving image into the
    template image space.

    This function uses ANTsPy to register a moving image to a template
    image. Optional masks can be provided for both images. The
    registration process supports different transformation types.

    This is the base method for space normalization, which can be used
    for different types of images, such as M0, T1w, and ASL images.
    The method is designed to be flexible and can be used for different
    types of images, as long as the moving image and template image are
    provided in the correct format.

    Note:
        For more specific cases, such as ASL data normalization, one can
        use other methods, such as in `asl_normalization` module.

    Note:
        Usually the space normalization is performed between the M0 and T1w
        images. The M0 image is one of the images obtained in the ASL
        acquisition and the T1w image is the anatomical image template.

    Important:
        The `transform_type` parameter allows for different types of
        transformations, such as 'SyN', 'BSpline', etc. The default is 'SyNBoldAff',
        which is suitable for registering ASL images to a T1-weighted template.
        All the definitions of the transformation types can be found in the
        ANTsPy documentation: https://antspy.readthedocs.io/en/latest/registration.html

    Important:
        This method always assumes a template image as a BrainAtlas object.
        One may pass a string with the name of the atlas, and the method will
        automatically load the atlas and use the T1-weighted image as the
        template image. If a different template image is needed, it should be
        passed as a BrainAtlas object, however, it depends on the ASLtk
        Kaggle dataset structure, so it is not recommended to raise an issue
        in the official ASLtk repository if the template image is not presented
        in the BrainAtlas format.

    Parameters
    ----------
    moving_image : np.ndarray
        The moving image.
    template_image : BrainAtlas or str or np.ndarray
        The template image as BrainAtlas object, string with the atlas name or
        a numpy array.
    moving_mask : np.ndarray, optional
        The moving mask in the same space as the moving image. If not provided,
        no mask is used.
    template_mask : np.ndarray, optional
        The template mask in the same space as the template image. If not provided,
        no mask is used.
    transform_type : str, optional
        Type of transformation ('SyN', 'BSpline', etc.). Default is 'SyNBoldAff'.
    verbose : bool, optional
        Whether to print detailed orientation analysis. Default is False.

    Returns
    -------
    normalized_image : np.ndarray
        The moving image transformed into the template image space.
    transform : list
        A list of transformation mapping from moving to template space.
    """
    if not isinstance(moving_image, ImageIO) or not isinstance(
        template_image, (BrainAtlas, str, ImageIO)
    ):
        raise TypeError(
            'moving_image must be an ImageIO object and template_image must be a BrainAtlas object, a string with the atlas name, or an ImageIO object.'
        )

    # Load template image first
    template_array = None
    if isinstance(template_image, BrainAtlas):
        template_file = template_image.get_atlas()['t1_data']
        template_array = ImageIO(template_file)
    elif isinstance(template_image, str):
        template_file = BrainAtlas(template_image).get_atlas()['t1_data']
        template_array = ImageIO(template_file)
        # template_array = ants.image_read('/home/antonio/Imagens/loamri-samples/20240909/mni_2mm.nii.gz')
    elif isinstance(template_image, ImageIO):
        template_array = template_image
    else:
        raise TypeError(
            'template_image must be a BrainAtlas object, a string with the atlas name, or an ImageIO object.'
        )

    if (
        moving_image.get_as_numpy().ndim != 3
        or template_array.get_as_numpy().ndim != 3
    ):
        raise ValueError(
            'Both moving_image and template_image must be 3D arrays.'
        )

    corrected_moving_image = clone_image(moving_image)

    # Load masks if provided
    if isinstance(moving_mask, ImageIO):
        moving_mask = moving_mask.get_as_ants()
    if isinstance(template_mask, ImageIO):
        template_mask = template_mask.get_as_ants()

    # Perform registration
    registration = ants.registration(
        fixed=template_array.get_as_ants(),
        moving=corrected_moving_image.get_as_ants(),
        type_of_transform=transform_type,
        mask=moving_mask,
        mask_fixed=template_mask,
        **kwargs,  # Additional parameters for ants.registration
    )

    # Passing the warped image and forward transforms
    out_warped = clone_image(template_array)
    ants_numpy = registration['warpedmovout'].numpy()
    out_warped.update_image_data(np.transpose(ants_numpy, (2, 1, 0)))

    return out_warped, registration['fwdtransforms']

ASL Normalization API

asl_template_registration(asl_data, atlas_reference='MNI2009', additional_maps=None, asl_data_mask=None, verbose=False)

Register ASL data to common atlas space.

This function applies a elastic normalization to fit the subject head space into the atlas template space.

Note

This method takes in consideration the ASLData object, which contains the pcasl and/or m0 image. The registration is performed using primarily the m0image if available, otherwise it uses the pcasl image. Therefore, choose wisely the ref_vol parameter, which should be a valid index for the best pcaslvolume reference to be registered to the atlas.

Parameters:

Name Type Description Default
asl_data ASLData

ASLData The ASLData object containing the pcasl and/or m0 image to be corrected.

required
ref_vol

(int, optional) The index of the reference volume to which all other volumes will be registered. Defaults to 0.

required
asl_data_mask ImageIO

np.ndarray A single volume image mask. This can assist the normalization method to converge into the atlas space. If not provided, the full image is adopted.

None
atlas_name

str The atlas type to be considered. The BrainAtlas class is applied, then choose the atlas_name based on the ASLtk brain atlas list.

required
verbose bool

(bool, optional) If True, prints progress messages. Defaults to False.

False

Raises:

Type Description
TypeError

If the input is not an ASLData object.

ValueError

If ref_vol is not a valid index.

RuntimeError

If an error occurs during registration.

Returns:

Name Type Description
tuple

ASLData object with corrected volumes and a list of transformation matrices.

Source code in asltk/registration/asl_normalization.py
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
def asl_template_registration(
    asl_data: ASLData,
    atlas_reference: Union[str, BrainAtlas] = 'MNI2009',
    additional_maps: List[ImageIO] = None,
    asl_data_mask: ImageIO = None,
    verbose: bool = False,
):
    """
    Register ASL data to common atlas space.

    This function applies a elastic normalization to fit the subject head
    space into the atlas template space.


    Note:
        This method takes in consideration the ASLData object, which contains
        the pcasl and/or m0 image. The registration is performed using primarily
        the `m0`image if available, otherwise it uses the `pcasl` image.
        Therefore, choose wisely the `ref_vol` parameter, which should be a valid index
        for the best `pcasl`volume reference to be registered to the atlas.

    Args:
        asl_data: ASLData
            The ASLData object containing the pcasl and/or m0 image to be corrected.
        ref_vol: (int, optional)
            The index of the reference volume to which all other volumes will be registered.
            Defaults to 0.
        asl_data_mask: np.ndarray
            A single volume image mask. This can assist the normalization method to converge
            into the atlas space. If not provided, the full image is adopted.
        atlas_name: str
            The atlas type to be considered. The BrainAtlas class is applied, then choose
            the `atlas_name` based on the ASLtk brain atlas list.
        verbose: (bool, optional)
            If True, prints progress messages. Defaults to False.

    Raises:
        TypeError: If the input is not an ASLData object.
        ValueError: If ref_vol is not a valid index.
        RuntimeError: If an error occurs during registration.

    Returns:
        tuple: ASLData object with corrected volumes and a list of transformation matrices.
    """
    if not isinstance(asl_data, ASLData):
        raise TypeError('Input must be an ASLData object.')

    if asl_data('m0') is None:
        raise ValueError(
            'M0 image is required for normalization. Please provide an ASLData with a valid M0 image.'
        )

    if not (
        isinstance(atlas_reference, BrainAtlas)
        or isinstance(atlas_reference, str)
    ):
        raise TypeError(
            'atlas_reference must be a BrainAtlas object or a string.'
        )
    if (
        isinstance(atlas_reference, str)
        and atlas_reference not in BrainAtlas('MNI2009').list_atlas()
    ):
        raise ValueError(
            f"atlas_reference '{atlas_reference}' is not a valid atlas name. "
            f"Available atlases: {BrainAtlas('MNI2009').list_atlas()}"
        )

    if additional_maps is not None:
        if not all(
            [
                isinstance(additional_map, ImageIO)
                and additional_map.get_as_numpy().shape
                == asl_data('m0').get_as_numpy().shape
                for additional_map in additional_maps
            ]
        ):
            raise TypeError(
                'All additional_maps must be ImageIO objects and have the same shape as the M0 image.'
            )
    else:
        additional_maps = []

    if isinstance(atlas_reference, BrainAtlas):
        atlas = atlas_reference
    else:
        atlas = BrainAtlas(atlas_reference)

    atlas_img = ImageIO(atlas.get_atlas()['t1_data'])

    def norm_function(vol, _):
        return space_normalization(
            moving_image=vol,
            template_image=atlas,
            moving_mask=asl_data_mask,
            template_mask=None,
            transform_type='SyN',
            check_orientation=True,
            verbose=verbose,
        )

    # Create a new ASLData to allocate the normalized image
    new_asl = asl_data.copy()

    tmp_vol_list = [asl_data('m0')]

    # Apply the normalization transformation to the M0 volume and update the new ASLData
    m0_vol_corrected, trans_m0_mtx = __apply_array_normalization(
        tmp_vol_list, 0, norm_function, None
    )
    new_asl.set_image(m0_vol_corrected[0], 'm0')

    # Apply the normalization transformation to all chosen volumes
    raw_volumes, _ = collect_data_volumes(asl_data('pcasl'))

    additional_maps_normalized = []
    raw_volumes_normalized = []
    with Progress() as progress:
        task = progress.add_task(
            '[green]Applying normalization to chosen volumes...',
            total=len(raw_volumes) + len(additional_maps),
        )
        for raw in raw_volumes:
            norm_vol = apply_transformation(
                moving_image=raw,
                reference_image=atlas_img,
                transforms=trans_m0_mtx,
            )
            raw_volumes_normalized.append(norm_vol)
            progress.update(task, advance=1)

        for additional_map in additional_maps:
            norm_additional_map = apply_transformation(
                moving_image=additional_map,
                reference_image=atlas_img,
                transforms=trans_m0_mtx,
            )
            additional_maps_normalized.append(norm_additional_map)
            progress.update(task, advance=1)

    # Update the new ASLData with the normalized volumes
    norm_array = np.array(
        [vol.get_as_numpy() for vol in raw_volumes_normalized]
    )
    new_asl.set_image(norm_array, 'pcasl')

    return new_asl, trans_m0_mtx, additional_maps_normalized

head_movement_correction(asl_data, ref_vol=None, method='snr', roi=None, verbose=False)

Correct head movement in ASL data using rigid body registration.

This function applies rigid body registration to correct head movement in ASL data. It registers each volume in the ASL data to a reference volume.

Hence, it can be helpfull to correct for head movements that may have occurred during the acquisition of ASL data. Note: The reference volume is selected based on the ref_vol parameter, which should be a valid index of the total number of volumes in the ASL data. The ref_vol value for 0 means that the first volume will be used as the reference.

Parameters:

Name Type Description Default
asl_data ASLData

ASLData) The ASLData object containing the pcasl image to be corrected.

required
ref_vol ImageIO

(np.ndarray, optional) The reference volume to which all other volumes will be registered. If not defined, the m0 volume will be used. In case the m0 volume is not available, the volume is defined by the method parameter.

None
method str

(str, optional) The method to select the reference volume. Options are 'snr' or 'mean'. If 'snr', the volume with the highest SNR is selected. If 'mean', the volume with the highest mean signal is selected.

'snr'
verbose bool

(bool, optional) If True, prints progress messages. Defaults to False.

False

Raises:

Type Description
TypeError

If the input is not an ASLData object.

ValueError

If no valid reference volume is provided.

RuntimeError

If the normalization fails.

Returns:

Name Type Description
tuple

ASLData object with corrected volumes and a list of transformation matrices.

Source code in asltk/registration/asl_normalization.py
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
def head_movement_correction(
    asl_data: ASLData,
    ref_vol: ImageIO = None,
    method: str = 'snr',
    roi: ImageIO = None,
    verbose: bool = False,
):
    """
    Correct head movement in ASL data using rigid body registration.

    This function applies rigid body registration to correct head movement
    in ASL data. It registers each volume in the ASL data to a reference volume.

    Hence, it can be helpfull to correct for head movements that may have
    occurred during the acquisition of ASL data.
    Note:
        The reference volume is selected based on the `ref_vol` parameter,
        which should be a valid index of the total number of volumes in the ASL data.
        The `ref_vol` value for 0 means that the first volume will be used as the reference.

    Args:
        asl_data: ASLData)
            The ASLData object containing the pcasl image to be corrected.
        ref_vol: (np.ndarray, optional)
            The reference volume to which all other volumes will be registered.
            If not defined, the `m0` volume will be used.
            In case the `m0` volume is not available, the volume is defined by the method parameter.
        method: (str, optional)
            The method to select the reference volume. Options are 'snr' or 'mean'.
            If 'snr', the volume with the highest SNR is selected.
            If 'mean', the volume with the highest mean signal is selected.
        verbose: (bool, optional)
            If True, prints progress messages. Defaults to False.

    Raises:
        TypeError: If the input is not an ASLData object.
        ValueError: If no valid reference volume is provided.
        RuntimeError: If the normalization fails.

    Returns:
        tuple: ASLData object with corrected volumes and a list of transformation matrices.
    """

    # Check if the input is a valid ASLData object.
    if not isinstance(asl_data, ASLData):
        raise TypeError('Input must be an ASLData object.')

    # Collect all the volumes in the pcasl image
    total_vols, _ = collect_data_volumes(asl_data('pcasl'))
    trans_proportions = _collect_transformation_proportions(
        total_vols, method, roi
    )

    # If ref_vol is not provided, use the m0 volume or the first pcasl volume
    ref_volume = None
    if ref_vol is None:
        if asl_data('m0') is not None:
            ref_volume = asl_data('m0')
        elif total_vols:
            vol_from_method, _ = select_reference_volume(
                asl_data, ref_vol, method=method
            )
            ref_volume = vol_from_method
        else:
            raise ValueError(
                'No valid reference volume provided. Please provide a valid m0 or ASLData volume.'
            )
    else:
        ref_volume = ref_vol

    # Check if the reference volume is a valid volume.
    if (
        not isinstance(ref_volume, ImageIO)
        or ref_volume.get_as_numpy().shape
        != total_vols[0].get_as_numpy().shape
    ):
        raise ValueError(
            'ref_vol must be a valid volume from the total asl data volumes.'
        )

    def norm_function(vol, ref_volume):
        return rigid_body_registration(vol, ref_volume)

    corrected_vols, trans_mtx = __apply_array_normalization(
        total_vols, ref_volume, norm_function, trans_proportions
    )

    new_asl_data = asl_data.copy()
    # Create the new ASLData object with the corrected volumes
    corrected_vols_array = np.array(
        [vol.get_as_numpy() for vol in corrected_vols]
    ).reshape(asl_data('pcasl').get_as_numpy().shape)

    adjusted_pcasl = clone_image(asl_data('pcasl'))
    adjusted_pcasl.update_image_data(corrected_vols_array)
    new_asl_data.set_image(adjusted_pcasl, 'pcasl')

    return new_asl_data, trans_mtx