Skip to content

ASLtk base classes and functions

ASLData class API

ASLData

Source code in asltk/asldata.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
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
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
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
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
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
class ASLData:
    def __init__(
        self,
        **kwargs,
    ):
        """ASLData constructor

        The basic data needed to represent ASL data are:
        - The full path to load the image file
        - The Labeling Duration (LD) array
        - The Post-labeling Delay (PLD) array

        If none of these are provided, a null ASLData object is created, which can be further populated using the get/set methods.

        The constructor supports classic ASL data, multi-TE, and Diffusion-Weighted (DW) ASL protocols.
        There are specific get/set methods for TE/DW data. If TE/DW is not provided, those properties are set to `None`.
        To provide TE or DW values, use the `te_values` or `dw_values` keyword arguments.

        Examples:
            By default, the LD and PLD arrays are empty lists.

            >>> data = ASLData()
            >>> data.get_ld()
            []
            >>> data.get_pld()
            []

            >>> data = ASLData(te_values=[13.0, 20.2, 50.5, 90.5, 125.2])
            >>> data.get_te()
            [13.0, 20.2, 50.5, 90.5, 125.2]

            >>> data = ASLData(dw_values=[13.0, 20.2, 50.5, 90.5, 125.2])
            >>> data.get_dw()
            [13.0, 20.2, 50.5, 90.5, 125.2]

        Other parameters:
            pcasl (str, optional): The ASL data full path with filename. Defaults to ''.
            m0 (str, optional): The M0 data full path with filename. Defaults to ''.
            ld_values (list, optional): The LD values. Defaults to [].
            pld_values (list, optional): The PLD values. Defaults to [].
            te_values (list, optional): The TE values. Defaults to None.
            dw_values (list, optional): The DW values. Defaults to None.
            average_m0 (bool, optional): If True, average the M0 image across the first dimension. This may be helpful for MRI acquisitions that collect an subset sample of M0 volumes and take the average of it. Defaults to False.
        """
        self._asl_image = None
        self._m0_image = None
        self._parameters = {
            'ld': [],
            'pld': [],
            'te': None,
            'dw': None,
        }

        logger = get_logger('asldata')
        logger.info('Creating ASLData object')

        if kwargs.get('pcasl') is not None:
            if isinstance(kwargs.get('pcasl'), str):
                pcasl_path = kwargs.get('pcasl')
                logger.info(f'Loading ASL image from: {pcasl_path}')
                self._asl_image = ImageIO(image_path=pcasl_path)
                if self._asl_image is not None:
                    log_data_info(
                        'ASL image',
                        self._asl_image.get_as_numpy().shape,
                        pcasl_path,
                    )
            elif isinstance(kwargs.get('pcasl'), np.ndarray):
                self._asl_image = ImageIO(image_array=kwargs.get('pcasl'))
                logger.info('ASL image loaded')
                log_data_info(
                    'ASL image', self._asl_image.get_as_numpy().shape
                )

        if kwargs.get('m0') is not None:
            average_m0 = kwargs.get('average_m0', False)
            if self._asl_image:
                self._asl_image._average_m0 = average_m0

            if isinstance(kwargs.get('m0'), str):
                m0_path = kwargs.get('m0')
                logger.info(f'Loading M0 image from: {m0_path}')
                self._m0_image = ImageIO(
                    image_path=m0_path, average_m0=average_m0
                )

                # Check if M0 image is 4D and warn if so
                if (
                    self._m0_image is not None
                    and len(self._m0_image.get_as_numpy().shape) > 3
                ):
                    warnings.warn('M0 image has more than 3 dimensions.')

                if self._m0_image is not None:
                    log_data_info(
                        'M0 image',
                        self._m0_image.get_as_numpy().shape,
                        m0_path,
                    )
            elif isinstance(kwargs.get('m0'), np.ndarray):
                self._m0_image = ImageIO(
                    image_array=kwargs.get('m0'), average_m0=average_m0
                )
                logger.info('M0 image loaded as numpy array')
                log_data_info(
                    'M0 image',
                    self._m0_image.get_as_numpy().shape,
                    'numpy array',
                )

        self._parameters['ld'] = (
            [] if kwargs.get('ld_values') is None else kwargs.get('ld_values')
        )
        self._parameters['pld'] = (
            []
            if kwargs.get('pld_values') is None
            else kwargs.get('pld_values')
        )

        if self._parameters['ld'] or self._parameters['pld']:
            logger.info(
                f"ASL timing parameters - LD: {self._parameters['ld']}, PLD: {self._parameters['pld']}"
            )

        self._check_ld_pld_sizes(
            self._parameters['ld'], self._parameters['pld']
        )
        if kwargs.get('te_values'):
            te_values = kwargs.get('te_values')
            self._parameters['te'] = te_values
            logger.info(f'Multi-TE parameters set: {te_values}')

        if kwargs.get('dw_values'):
            dw_values = kwargs.get('dw_values')
            self._parameters['dw'] = dw_values
            logger.info(f'Diffusion-weighted parameters set: {dw_values}')

        logger.debug('ASLData object created successfully')

    def set_image(self, image: Union[str, np.ndarray], spec: str, **kwargs):
        """Insert an image necessary to define the ASL data processing.

        The `spec` parameters specifies what is the type of image to be used in
        ASL processing step. Choose one of the options: `m0` for the M0 volume,
        `pcasl` for the pCASL data.

        Note:
            The image can be a full path to the image file or a numpy array.
            In case the image parameter is a path, then the method will load
            the image file directly and associate it with the `spec` parameter.
            However, if the image is a numpy array, then the method will
            pass it to the ASLData object image data regarding the `spec`
            parameter as well.

        Examples:
            >>> data = ASLData()
            >>> path_m0 = './tests/files/m0.nii.gz' # M0 file with shape (5,35,35)
            >>> data.set_image(path_m0, spec='m0')
            >>> data('m0').get_as_numpy().shape
            (5, 35, 35)

        Args:
            image (str): The image to be used.
            spec (str): The type of image being used in the ASL processing.
        """
        if isinstance(image, str) and os.path.exists(image):
            if spec == 'm0':
                self._m0_image = ImageIO(image, **kwargs)
            elif spec == 'pcasl':
                self._asl_image = ImageIO(image, **kwargs)
        elif isinstance(image, np.ndarray):
            warnings.warn(
                'Using numpy array as image input does not preserve metadata or image properties.'
            )
            if spec == 'm0':
                self._m0_image = ImageIO(image_array=image, **kwargs)
            elif spec == 'pcasl':
                self._asl_image = ImageIO(image_array=image, **kwargs)
        elif isinstance(image, ImageIO):
            if spec == 'm0':
                self._m0_image = image
            elif spec == 'pcasl':
                self._asl_image = image
        else:
            raise ValueError(
                f'Invalid image type or path: {image}. '
                'Please provide a valid file path or a numpy array.'
            )

    def get_ld(self):
        """Obtain the LD array values"""
        return self._parameters['ld']

    def set_ld(self, ld_values: list):
        """Set the LD values.

        The proper way to inform the values here is using a list of int or
        float data. The total quantity of values depends on the image
        acquisition protocol.

        The list length for LD must be equal to PLD list length.

        Args:
            ld_values (list): The values to be adjusted for LD array
        """
        self._check_input_parameter(ld_values, 'LD')
        self._parameters['ld'] = ld_values

    def get_pld(self):
        """Obtain the PLD array values"""
        return self._parameters['pld']

    def set_pld(self, pld_values: list):
        """Set the PLD values.

        The proper way to inform the values here is using a list of int or
        float data. The total quantity of values depends on the image
        acquisition protocol.

        The list length for PLD must be equal to LD list length.

        Args:
            pld_values (list): The values to be adjusted for PLD array
        """
        self._check_input_parameter(pld_values, 'PLD')
        self._parameters['pld'] = pld_values

    def get_te(self):
        """Obtain the TE array values"""
        return self._parameters['te']

    def set_te(self, te_values: list):
        """Set the TE values.

        The proper way to inform the values here is using a list of int or
        float data. The total quantity of values depends on the image
        acquisition protocol.

        Args:
            te_values (list): The values to be adjusted for TE array
        """
        self._check_input_parameter(te_values, 'TE')
        self._parameters['te'] = te_values

    def get_dw(self):
        """Obtain the Diffusion b values array"""
        return self._parameters['dw']

    def set_dw(self, dw_values: list):
        """Set the Diffusion b values.

        The proper way to inform the values here is using a list of int or
        float data. The total quantity of values depends on the image
        acquisition protocol.

        Args:
            dw_values (list): The values to be adjusted for DW array
        """
        self._check_input_parameter(dw_values, 'DW')
        self._parameters['dw'] = dw_values

    def copy(self):
        """
        Make a copy of the ASLData object.
        This method creates a deep copy of the ASLData object, including all
        its attributes and data. It is useful when you want to preserve the
        original object while working with a modified version.

        Note:
            This method uses `copy.deepcopy` to ensure that all nested objects
            are also copied, preventing any unintended side effects from
            modifying the original object.

        Examples:
            >>> data = ASLData(pcasl='./tests/files/t1-mri.nrrd')
            >>> data_copy = data.copy()
            >>> type(data_copy)
            <class 'asltk.asldata.ASLData'>


        Returns:
            ASLData: A new instance of ASLData that is a deep copy of the original object.
        """
        return copy.deepcopy(self)

    def __call__(self, spec: str):
        """Object caller to expose the image data.

        Examples:
            >>> data = ASLData(pcasl='./tests/files/t1-mri.nrrd')
            >>> type(data('pcasl'))
            <class 'asltk.utils.io.ImageIO'>
            >>> type(data('pcasl').get_as_numpy())
            <class 'numpy.ndarray'>

            >>> np.min(data('pcasl').get_as_numpy())
            0

        Returns:
            (numpy.ndarray): The data placed in the ASLData object
        """
        if spec == 'pcasl':
            return self._asl_image
        elif spec == 'm0':
            return self._m0_image

    def __len__(self):
        """Return the number of volumes in the ASL data.

        This method returns the number of volumes in the ASL data based on
        the pCASL image format.

        Returns:
            int: The number of volumes in the ASL data considering the `pcasl` data.
        """
        if self._asl_image is not None:
            return len(collect_data_volumes(self._asl_image)[0])
        else:
            return 0

    def _check_input_parameter(self, values, param_type):
        for v in values:
            if not isinstance(v, int) and not isinstance(v, float):
                raise ValueError(
                    f'{param_type} values is not a list of valid numbers.'
                )
            if v <= 0:
                raise ValueError(
                    f'{param_type} values must be postive non zero numbers.'
                )

    def _check_ld_pld_sizes(self, ld, pld):
        logger = get_logger('asldata')
        if len(ld) != len(pld):
            error_msg = f'LD and PLD must have the same array size. LD size is {len(ld)} and PLD size is {len(pld)}'
            logger.error(error_msg)
            raise ValueError(error_msg)
        else:
            logger.debug(
                f'LD and PLD size validation passed: {len(ld)} elements each'
            )

    def _check_m0_dimension(self):
        if len(self._m0_image.get_as_numpy().shape) > 3:
            warnings.warn(
                'M0 image has more than 3 dimensions. '
                'This may cause issues in processing. '
                'Consider averaging the M0 image across the first dimension.'
            )

__call__(spec)

Object caller to expose the image data.

Examples:

>>> data = ASLData(pcasl='./tests/files/t1-mri.nrrd')
>>> type(data('pcasl'))
<class 'asltk.utils.io.ImageIO'>
>>> type(data('pcasl').get_as_numpy())
<class 'numpy.ndarray'>
>>> np.min(data('pcasl').get_as_numpy())
0

Returns:

Type Description
ndarray

The data placed in the ASLData object

Source code in asltk/asldata.py
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
def __call__(self, spec: str):
    """Object caller to expose the image data.

    Examples:
        >>> data = ASLData(pcasl='./tests/files/t1-mri.nrrd')
        >>> type(data('pcasl'))
        <class 'asltk.utils.io.ImageIO'>
        >>> type(data('pcasl').get_as_numpy())
        <class 'numpy.ndarray'>

        >>> np.min(data('pcasl').get_as_numpy())
        0

    Returns:
        (numpy.ndarray): The data placed in the ASLData object
    """
    if spec == 'pcasl':
        return self._asl_image
    elif spec == 'm0':
        return self._m0_image

__init__(**kwargs)

ASLData constructor

The basic data needed to represent ASL data are: - The full path to load the image file - The Labeling Duration (LD) array - The Post-labeling Delay (PLD) array

If none of these are provided, a null ASLData object is created, which can be further populated using the get/set methods.

The constructor supports classic ASL data, multi-TE, and Diffusion-Weighted (DW) ASL protocols. There are specific get/set methods for TE/DW data. If TE/DW is not provided, those properties are set to None. To provide TE or DW values, use the te_values or dw_values keyword arguments.

Examples:

By default, the LD and PLD arrays are empty lists.

>>> data = ASLData()
>>> data.get_ld()
[]
>>> data.get_pld()
[]
>>> data = ASLData(te_values=[13.0, 20.2, 50.5, 90.5, 125.2])
>>> data.get_te()
[13.0, 20.2, 50.5, 90.5, 125.2]
>>> data = ASLData(dw_values=[13.0, 20.2, 50.5, 90.5, 125.2])
>>> data.get_dw()
[13.0, 20.2, 50.5, 90.5, 125.2]

Other Parameters:

Name Type Description
pcasl str

The ASL data full path with filename. Defaults to ''.

m0 str

The M0 data full path with filename. Defaults to ''.

ld_values list

The LD values. Defaults to [].

pld_values list

The PLD values. Defaults to [].

te_values list

The TE values. Defaults to None.

dw_values list

The DW values. Defaults to None.

average_m0 bool

If True, average the M0 image across the first dimension. This may be helpful for MRI acquisitions that collect an subset sample of M0 volumes and take the average of it. Defaults to False.

Source code in asltk/asldata.py
 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
141
142
143
144
145
146
147
148
149
150
def __init__(
    self,
    **kwargs,
):
    """ASLData constructor

    The basic data needed to represent ASL data are:
    - The full path to load the image file
    - The Labeling Duration (LD) array
    - The Post-labeling Delay (PLD) array

    If none of these are provided, a null ASLData object is created, which can be further populated using the get/set methods.

    The constructor supports classic ASL data, multi-TE, and Diffusion-Weighted (DW) ASL protocols.
    There are specific get/set methods for TE/DW data. If TE/DW is not provided, those properties are set to `None`.
    To provide TE or DW values, use the `te_values` or `dw_values` keyword arguments.

    Examples:
        By default, the LD and PLD arrays are empty lists.

        >>> data = ASLData()
        >>> data.get_ld()
        []
        >>> data.get_pld()
        []

        >>> data = ASLData(te_values=[13.0, 20.2, 50.5, 90.5, 125.2])
        >>> data.get_te()
        [13.0, 20.2, 50.5, 90.5, 125.2]

        >>> data = ASLData(dw_values=[13.0, 20.2, 50.5, 90.5, 125.2])
        >>> data.get_dw()
        [13.0, 20.2, 50.5, 90.5, 125.2]

    Other parameters:
        pcasl (str, optional): The ASL data full path with filename. Defaults to ''.
        m0 (str, optional): The M0 data full path with filename. Defaults to ''.
        ld_values (list, optional): The LD values. Defaults to [].
        pld_values (list, optional): The PLD values. Defaults to [].
        te_values (list, optional): The TE values. Defaults to None.
        dw_values (list, optional): The DW values. Defaults to None.
        average_m0 (bool, optional): If True, average the M0 image across the first dimension. This may be helpful for MRI acquisitions that collect an subset sample of M0 volumes and take the average of it. Defaults to False.
    """
    self._asl_image = None
    self._m0_image = None
    self._parameters = {
        'ld': [],
        'pld': [],
        'te': None,
        'dw': None,
    }

    logger = get_logger('asldata')
    logger.info('Creating ASLData object')

    if kwargs.get('pcasl') is not None:
        if isinstance(kwargs.get('pcasl'), str):
            pcasl_path = kwargs.get('pcasl')
            logger.info(f'Loading ASL image from: {pcasl_path}')
            self._asl_image = ImageIO(image_path=pcasl_path)
            if self._asl_image is not None:
                log_data_info(
                    'ASL image',
                    self._asl_image.get_as_numpy().shape,
                    pcasl_path,
                )
        elif isinstance(kwargs.get('pcasl'), np.ndarray):
            self._asl_image = ImageIO(image_array=kwargs.get('pcasl'))
            logger.info('ASL image loaded')
            log_data_info(
                'ASL image', self._asl_image.get_as_numpy().shape
            )

    if kwargs.get('m0') is not None:
        average_m0 = kwargs.get('average_m0', False)
        if self._asl_image:
            self._asl_image._average_m0 = average_m0

        if isinstance(kwargs.get('m0'), str):
            m0_path = kwargs.get('m0')
            logger.info(f'Loading M0 image from: {m0_path}')
            self._m0_image = ImageIO(
                image_path=m0_path, average_m0=average_m0
            )

            # Check if M0 image is 4D and warn if so
            if (
                self._m0_image is not None
                and len(self._m0_image.get_as_numpy().shape) > 3
            ):
                warnings.warn('M0 image has more than 3 dimensions.')

            if self._m0_image is not None:
                log_data_info(
                    'M0 image',
                    self._m0_image.get_as_numpy().shape,
                    m0_path,
                )
        elif isinstance(kwargs.get('m0'), np.ndarray):
            self._m0_image = ImageIO(
                image_array=kwargs.get('m0'), average_m0=average_m0
            )
            logger.info('M0 image loaded as numpy array')
            log_data_info(
                'M0 image',
                self._m0_image.get_as_numpy().shape,
                'numpy array',
            )

    self._parameters['ld'] = (
        [] if kwargs.get('ld_values') is None else kwargs.get('ld_values')
    )
    self._parameters['pld'] = (
        []
        if kwargs.get('pld_values') is None
        else kwargs.get('pld_values')
    )

    if self._parameters['ld'] or self._parameters['pld']:
        logger.info(
            f"ASL timing parameters - LD: {self._parameters['ld']}, PLD: {self._parameters['pld']}"
        )

    self._check_ld_pld_sizes(
        self._parameters['ld'], self._parameters['pld']
    )
    if kwargs.get('te_values'):
        te_values = kwargs.get('te_values')
        self._parameters['te'] = te_values
        logger.info(f'Multi-TE parameters set: {te_values}')

    if kwargs.get('dw_values'):
        dw_values = kwargs.get('dw_values')
        self._parameters['dw'] = dw_values
        logger.info(f'Diffusion-weighted parameters set: {dw_values}')

    logger.debug('ASLData object created successfully')

__len__()

Return the number of volumes in the ASL data.

This method returns the number of volumes in the ASL data based on the pCASL image format.

Returns:

Name Type Description
int

The number of volumes in the ASL data considering the pcasl data.

Source code in asltk/asldata.py
319
320
321
322
323
324
325
326
327
328
329
330
331
def __len__(self):
    """Return the number of volumes in the ASL data.

    This method returns the number of volumes in the ASL data based on
    the pCASL image format.

    Returns:
        int: The number of volumes in the ASL data considering the `pcasl` data.
    """
    if self._asl_image is not None:
        return len(collect_data_volumes(self._asl_image)[0])
    else:
        return 0

copy()

Make a copy of the ASLData object. This method creates a deep copy of the ASLData object, including all its attributes and data. It is useful when you want to preserve the original object while working with a modified version.

Note

This method uses copy.deepcopy to ensure that all nested objects are also copied, preventing any unintended side effects from modifying the original object.

Examples:

>>> data = ASLData(pcasl='./tests/files/t1-mri.nrrd')
>>> data_copy = data.copy()
>>> type(data_copy)
<class 'asltk.asldata.ASLData'>

Returns:

Name Type Description
ASLData

A new instance of ASLData that is a deep copy of the original object.

Source code in asltk/asldata.py
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
def copy(self):
    """
    Make a copy of the ASLData object.
    This method creates a deep copy of the ASLData object, including all
    its attributes and data. It is useful when you want to preserve the
    original object while working with a modified version.

    Note:
        This method uses `copy.deepcopy` to ensure that all nested objects
        are also copied, preventing any unintended side effects from
        modifying the original object.

    Examples:
        >>> data = ASLData(pcasl='./tests/files/t1-mri.nrrd')
        >>> data_copy = data.copy()
        >>> type(data_copy)
        <class 'asltk.asldata.ASLData'>


    Returns:
        ASLData: A new instance of ASLData that is a deep copy of the original object.
    """
    return copy.deepcopy(self)

get_dw()

Obtain the Diffusion b values array

Source code in asltk/asldata.py
257
258
259
def get_dw(self):
    """Obtain the Diffusion b values array"""
    return self._parameters['dw']

get_ld()

Obtain the LD array values

Source code in asltk/asldata.py
202
203
204
def get_ld(self):
    """Obtain the LD array values"""
    return self._parameters['ld']

get_pld()

Obtain the PLD array values

Source code in asltk/asldata.py
221
222
223
def get_pld(self):
    """Obtain the PLD array values"""
    return self._parameters['pld']

get_te()

Obtain the TE array values

Source code in asltk/asldata.py
240
241
242
def get_te(self):
    """Obtain the TE array values"""
    return self._parameters['te']

set_dw(dw_values)

Set the Diffusion b values.

The proper way to inform the values here is using a list of int or float data. The total quantity of values depends on the image acquisition protocol.

Parameters:

Name Type Description Default
dw_values list

The values to be adjusted for DW array

required
Source code in asltk/asldata.py
261
262
263
264
265
266
267
268
269
270
271
272
def set_dw(self, dw_values: list):
    """Set the Diffusion b values.

    The proper way to inform the values here is using a list of int or
    float data. The total quantity of values depends on the image
    acquisition protocol.

    Args:
        dw_values (list): The values to be adjusted for DW array
    """
    self._check_input_parameter(dw_values, 'DW')
    self._parameters['dw'] = dw_values

set_image(image, spec, **kwargs)

Insert an image necessary to define the ASL data processing.

The spec parameters specifies what is the type of image to be used in ASL processing step. Choose one of the options: m0 for the M0 volume, pcasl for the pCASL data.

Note

The image can be a full path to the image file or a numpy array. In case the image parameter is a path, then the method will load the image file directly and associate it with the spec parameter. However, if the image is a numpy array, then the method will pass it to the ASLData object image data regarding the spec parameter as well.

Examples:

>>> data = ASLData()
>>> path_m0 = './tests/files/m0.nii.gz' # M0 file with shape (5,35,35)
>>> data.set_image(path_m0, spec='m0')
>>> data('m0').get_as_numpy().shape
(5, 35, 35)

Parameters:

Name Type Description Default
image str

The image to be used.

required
spec str

The type of image being used in the ASL processing.

required
Source code in asltk/asldata.py
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
def set_image(self, image: Union[str, np.ndarray], spec: str, **kwargs):
    """Insert an image necessary to define the ASL data processing.

    The `spec` parameters specifies what is the type of image to be used in
    ASL processing step. Choose one of the options: `m0` for the M0 volume,
    `pcasl` for the pCASL data.

    Note:
        The image can be a full path to the image file or a numpy array.
        In case the image parameter is a path, then the method will load
        the image file directly and associate it with the `spec` parameter.
        However, if the image is a numpy array, then the method will
        pass it to the ASLData object image data regarding the `spec`
        parameter as well.

    Examples:
        >>> data = ASLData()
        >>> path_m0 = './tests/files/m0.nii.gz' # M0 file with shape (5,35,35)
        >>> data.set_image(path_m0, spec='m0')
        >>> data('m0').get_as_numpy().shape
        (5, 35, 35)

    Args:
        image (str): The image to be used.
        spec (str): The type of image being used in the ASL processing.
    """
    if isinstance(image, str) and os.path.exists(image):
        if spec == 'm0':
            self._m0_image = ImageIO(image, **kwargs)
        elif spec == 'pcasl':
            self._asl_image = ImageIO(image, **kwargs)
    elif isinstance(image, np.ndarray):
        warnings.warn(
            'Using numpy array as image input does not preserve metadata or image properties.'
        )
        if spec == 'm0':
            self._m0_image = ImageIO(image_array=image, **kwargs)
        elif spec == 'pcasl':
            self._asl_image = ImageIO(image_array=image, **kwargs)
    elif isinstance(image, ImageIO):
        if spec == 'm0':
            self._m0_image = image
        elif spec == 'pcasl':
            self._asl_image = image
    else:
        raise ValueError(
            f'Invalid image type or path: {image}. '
            'Please provide a valid file path or a numpy array.'
        )

set_ld(ld_values)

Set the LD values.

The proper way to inform the values here is using a list of int or float data. The total quantity of values depends on the image acquisition protocol.

The list length for LD must be equal to PLD list length.

Parameters:

Name Type Description Default
ld_values list

The values to be adjusted for LD array

required
Source code in asltk/asldata.py
206
207
208
209
210
211
212
213
214
215
216
217
218
219
def set_ld(self, ld_values: list):
    """Set the LD values.

    The proper way to inform the values here is using a list of int or
    float data. The total quantity of values depends on the image
    acquisition protocol.

    The list length for LD must be equal to PLD list length.

    Args:
        ld_values (list): The values to be adjusted for LD array
    """
    self._check_input_parameter(ld_values, 'LD')
    self._parameters['ld'] = ld_values

set_pld(pld_values)

Set the PLD values.

The proper way to inform the values here is using a list of int or float data. The total quantity of values depends on the image acquisition protocol.

The list length for PLD must be equal to LD list length.

Parameters:

Name Type Description Default
pld_values list

The values to be adjusted for PLD array

required
Source code in asltk/asldata.py
225
226
227
228
229
230
231
232
233
234
235
236
237
238
def set_pld(self, pld_values: list):
    """Set the PLD values.

    The proper way to inform the values here is using a list of int or
    float data. The total quantity of values depends on the image
    acquisition protocol.

    The list length for PLD must be equal to LD list length.

    Args:
        pld_values (list): The values to be adjusted for PLD array
    """
    self._check_input_parameter(pld_values, 'PLD')
    self._parameters['pld'] = pld_values

set_te(te_values)

Set the TE values.

The proper way to inform the values here is using a list of int or float data. The total quantity of values depends on the image acquisition protocol.

Parameters:

Name Type Description Default
te_values list

The values to be adjusted for TE array

required
Source code in asltk/asldata.py
244
245
246
247
248
249
250
251
252
253
254
255
def set_te(self, te_values: list):
    """Set the TE values.

    The proper way to inform the values here is using a list of int or
    float data. The total quantity of values depends on the image
    acquisition protocol.

    Args:
        te_values (list): The values to be adjusted for TE array
    """
    self._check_input_parameter(te_values, 'TE')
    self._parameters['te'] = te_values

Auxiliary Methods API

Logging Configuration

MRI Parameters Class API

The MRI parameters are defined here.

The paper references is listed below, which can be used to get more information about some measures:

[1] Leonie Petitclerc, et al. "Ultra-long-TE arterial spin labeling reveals rapid and brain-wide blood-to-CSF water transport in humans", Neuroimage (2021). DOI: 10.1016/j.neuroimage.2021.118755

[2] R B Buxton, et al. "A general kinetic model for quantitative perfusion imaging with arterial spin labeling". Magn Reson Med (1998). PMID: 9727941 DOI: 10.1002/mrm.1910400308

MRIParameters

Source code in asltk/mri_parameters.py
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
class MRIParameters:
    def __init__(self) -> None:
        """Creates the basic MRIParameters object to define the main MRI
        constants and values for ASL processing

        To see all the parameters listed in the class, one can call print the
        values using the default `print()` function
        """
        self.T1bl = 1650.0   # T1 relaxation for the blood [1]
        self.T1csf = 1400.0   # T1 relaxation for the CSF [1] Paper Ultralong TE: T1csf = 4300!!!

        self.T2bl = 165.0  # T2 relaxation for the blood [1] PAPER CITE 150!!!!
        self.T2gm = 75.0   # T2 relaxation for the GM [1] PAPER CITE 60
        self.T2csf = 1500   # T2 relaxation for the CSF [1]

        # MRI constants
        self.Alpha = 0.85   # RF labeling efficiency
        self.Lambda = 0.98   # Blood-brain partition coefficient [1]

    def set_constant(self, value: float, param: str):
        """Set a different value for a parameter defined in the MRIParameter
        class.

        Args:
            value (float): The value to be assumed in the parameter
            param (str): The parameter that will receive the new value

        Raises:
            AttributeError: The parameter type must be already defined in the
            MRIParameters class.
        """
        if param == 'T1bl':
            self.T1bl = value
        elif param == 'T1csf':
            self.T1csf = value
        elif param == 'T2bl':
            self.T2bl = value
        elif param == 'T2gm':
            self.T2gm = value
        elif param == 'T2csf':
            self.T2csf = value
        elif param == 'Alpha':
            self.Alpha = value
        elif param == 'Lambda':
            self.Lambda = value
        else:
            raise AttributeError(
                f'Constant type {param} is not valid. Choose in the list available in the MRIParameter class.'
            )

    def get_constant(self, param: str) -> float:
        """Collect a parameter value from a defined type

        Args:
            param (str): The specific parameter that should return the storage
            value.

        Raises:
            AttributeError: The parameter type must be already defined in the
            MRIParameters class.

        Returns:
            float: The parameter value storage in the object instance
        """
        if param == 'T1bl':
            return self.T1bl
        elif param == 'T1csf':
            return self.T1csf
        elif param == 'T2bl':
            return self.T2bl
        elif param == 'T2gm':
            return self.T2gm
        elif param == 'T2csf':
            return self.T2csf
        elif param == 'Alpha':
            return self.Alpha
        elif param == 'Lambda':
            return self.Lambda
        else:
            raise AttributeError(
                f'Constant type {param} is not valid. Choose in the list available in the MRIParameter class.'
            )

__init__()

Creates the basic MRIParameters object to define the main MRI constants and values for ASL processing

To see all the parameters listed in the class, one can call print the values using the default print() function

Source code in asltk/mri_parameters.py
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
def __init__(self) -> None:
    """Creates the basic MRIParameters object to define the main MRI
    constants and values for ASL processing

    To see all the parameters listed in the class, one can call print the
    values using the default `print()` function
    """
    self.T1bl = 1650.0   # T1 relaxation for the blood [1]
    self.T1csf = 1400.0   # T1 relaxation for the CSF [1] Paper Ultralong TE: T1csf = 4300!!!

    self.T2bl = 165.0  # T2 relaxation for the blood [1] PAPER CITE 150!!!!
    self.T2gm = 75.0   # T2 relaxation for the GM [1] PAPER CITE 60
    self.T2csf = 1500   # T2 relaxation for the CSF [1]

    # MRI constants
    self.Alpha = 0.85   # RF labeling efficiency
    self.Lambda = 0.98   # Blood-brain partition coefficient [1]

get_constant(param)

Collect a parameter value from a defined type

Parameters:

Name Type Description Default
param str

The specific parameter that should return the storage

required

Raises:

Type Description
AttributeError

The parameter type must be already defined in the

Returns:

Name Type Description
float float

The parameter value storage in the object instance

Source code in asltk/mri_parameters.py
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
def get_constant(self, param: str) -> float:
    """Collect a parameter value from a defined type

    Args:
        param (str): The specific parameter that should return the storage
        value.

    Raises:
        AttributeError: The parameter type must be already defined in the
        MRIParameters class.

    Returns:
        float: The parameter value storage in the object instance
    """
    if param == 'T1bl':
        return self.T1bl
    elif param == 'T1csf':
        return self.T1csf
    elif param == 'T2bl':
        return self.T2bl
    elif param == 'T2gm':
        return self.T2gm
    elif param == 'T2csf':
        return self.T2csf
    elif param == 'Alpha':
        return self.Alpha
    elif param == 'Lambda':
        return self.Lambda
    else:
        raise AttributeError(
            f'Constant type {param} is not valid. Choose in the list available in the MRIParameter class.'
        )

set_constant(value, param)

Set a different value for a parameter defined in the MRIParameter class.

Parameters:

Name Type Description Default
value float

The value to be assumed in the parameter

required
param str

The parameter that will receive the new value

required

Raises:

Type Description
AttributeError

The parameter type must be already defined in the

Source code in asltk/mri_parameters.py
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
def set_constant(self, value: float, param: str):
    """Set a different value for a parameter defined in the MRIParameter
    class.

    Args:
        value (float): The value to be assumed in the parameter
        param (str): The parameter that will receive the new value

    Raises:
        AttributeError: The parameter type must be already defined in the
        MRIParameters class.
    """
    if param == 'T1bl':
        self.T1bl = value
    elif param == 'T1csf':
        self.T1csf = value
    elif param == 'T2bl':
        self.T2bl = value
    elif param == 'T2gm':
        self.T2gm = value
    elif param == 'T2csf':
        self.T2csf = value
    elif param == 'Alpha':
        self.Alpha = value
    elif param == 'Lambda':
        self.Lambda = value
    else:
        raise AttributeError(
            f'Constant type {param} is not valid. Choose in the list available in the MRIParameter class.'
        )