petpal 0.5.6__py3-none-any.whl → 0.5.8__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,159 @@
1
+ """
2
+ Module for functions calculating standard uptake value (SUV) and related measures, such as standard
3
+ uptake value ratio (SUVR).
4
+ """
5
+ import ants
6
+
7
+ from ..utils.stats import mean_value_in_region
8
+ from ..utils.math_lib import weighted_sum_computation
9
+ from ..utils.useful_functions import gen_3d_img_from_timeseries, nearest_frame_to_timepoint
10
+ from ..utils.image_io import (get_half_life_from_nifti,
11
+ load_metadata_for_nifti_with_same_filename,
12
+ safe_copy_meta)
13
+
14
+
15
+ def weighted_sum_for_suv(input_image_path: str,
16
+ output_image_path: str | None,
17
+ start_time: float=0,
18
+ end_time: float=-1) -> ants.ANTsImage:
19
+ """Function that calculates the weighted series sum for a PET image specifically for
20
+ calculating the standard uptake value (SUV) of the image.
21
+
22
+ Args:
23
+ input_image_path (str): Path to a 4D PET image which we calculate the sum on.
24
+ output_image_path (str): Path to which output image is saved. If None, returns
25
+ calculated image without saving.
26
+ start_time: Time in seconds from the start of the scan from which to begin sum calculation.
27
+ Only frames after selected time will be included in the sum. Default 0.
28
+ end_time: Time in seconds from the start of the scan from which to end sum calculation.
29
+ Only frames before selected time will be included in the sum. If -1, use all frames
30
+ after `start_time` in the calculation. Default -1.
31
+
32
+ Returns:
33
+ weighted_sum_img (ants.ANTsImage): 3D image resulting from the sum calculation.
34
+ """
35
+ half_life = get_half_life_from_nifti(image_path=input_image_path)
36
+ if half_life <= 0:
37
+ raise ValueError('(ImageOps4d): Radioisotope half life is zero or negative.')
38
+ pet_meta = load_metadata_for_nifti_with_same_filename(input_image_path)
39
+ pet_img = ants.image_read(input_image_path)
40
+ frame_start = pet_meta['FrameTimesStart']
41
+ frame_duration = pet_meta['FrameDuration']
42
+
43
+ if 'DecayCorrectionFactor' in pet_meta.keys():
44
+ decay_correction = pet_meta['DecayCorrectionFactor']
45
+ elif 'DecayFactor' in pet_meta.keys():
46
+ decay_correction = pet_meta['DecayFactor']
47
+ else:
48
+ raise ValueError("Neither 'DecayCorrectionFactor' nor 'DecayFactor' exist in meta-data "
49
+ "file")
50
+
51
+ last_frame_time = frame_start[-1]
52
+ if end_time!=-1:
53
+ last_frame_time = end_time
54
+ scan_start = frame_start[0]
55
+ nearest_frame = nearest_frame_to_timepoint(frame_times=frame_start)
56
+ calc_first_frame = int(nearest_frame(start_time+scan_start))
57
+ calc_last_frame = int(nearest_frame(last_frame_time+scan_start))
58
+ if calc_first_frame==calc_last_frame:
59
+ calc_last_frame += 1
60
+ pet_series_adjusted = pet_img[:,:,:,calc_first_frame:calc_last_frame]
61
+ frame_start_adjusted = frame_start[calc_first_frame:calc_last_frame]
62
+ frame_duration_adjusted = frame_duration[calc_first_frame:calc_last_frame]
63
+ decay_correction_adjusted = decay_correction[calc_first_frame:calc_last_frame]
64
+
65
+ weighted_sum_arr = weighted_sum_computation(frame_duration=frame_duration_adjusted,
66
+ half_life=half_life,
67
+ pet_series=pet_series_adjusted,
68
+ frame_start=frame_start_adjusted,
69
+ decay_correction=decay_correction_adjusted)
70
+ weighted_sum_img = ants.from_numpy_like(weighted_sum_arr,gen_3d_img_from_timeseries(pet_img))
71
+
72
+ if output_image_path is not None:
73
+ ants.image_write(weighted_sum_img, output_image_path)
74
+ safe_copy_meta(input_image_path=input_image_path,
75
+ out_image_path=output_image_path)
76
+
77
+ return weighted_sum_img
78
+
79
+
80
+ def suv(input_image_path: str,
81
+ output_image_path: str | None,
82
+ weight: float,
83
+ dose: float,
84
+ start_time: float,
85
+ end_time: float) -> ants.ANTsImage:
86
+ """Compute standard uptake value (SUV) over a pet image. Calculate the weighted image sum
87
+ then divide by the dose and multiplying by the weight of the participant.
88
+
89
+ Args:
90
+ input_image_path: Path to input PET image.
91
+ output_image_path: Path to which SUV image is saved.
92
+ weight: Weight of the participant in kg.
93
+ dose: Dose injected during the scan in MBq.
94
+ start_time: Start time for the SUV calculation in seconds.
95
+ end_time: End time for the SUV calculation in seconds.
96
+
97
+ Returns:
98
+ suv_img (ants.ANTsImage): The standard uptake value calculated on the input image."""
99
+ wss_img = weighted_sum_for_suv(input_image_path=input_image_path,
100
+ output_image_path=None,
101
+ start_time=start_time,
102
+ end_time=end_time)
103
+ suv_img = wss_img / (dose*1000) * weight
104
+
105
+ if output_image_path is not None:
106
+ ants.image_write(suv_img, output_image_path)
107
+ safe_copy_meta(input_image_path=input_image_path,
108
+ out_image_path=output_image_path)
109
+
110
+ return suv_img
111
+
112
+
113
+ def suvr(input_image_path: str,
114
+ output_image_path: str | None,
115
+ segmentation_image_path: str,
116
+ ref_region: int | list[int],
117
+ start_time: float,
118
+ end_time: float) -> ants.ANTsImage:
119
+ """
120
+ Computes an ``SUVR`` (Standard Uptake Value Ratio) by taking the average of
121
+ an input image within a reference region, and dividing the input image by
122
+ said average value.
123
+
124
+ Args:
125
+ input_image_path (str): Path to 4D PET image.
126
+ output_image_path (str): Path to output image file which is written to. If None, no output
127
+ is written.
128
+ segmentation_image_path (str): Path to segmentation image, which we use
129
+ to compute average uptake value in the reference region.
130
+ ref_region (int): Region or list of region mappings over which to compute average SUV. If a
131
+ list is provided, combines all regions in the list as one reference region.
132
+ start_time: Time in seconds from the start of the scan from which to begin sum calculation.
133
+ Only frames after selected time will be included in the sum. Default 0.
134
+ end_time: Time in seconds from the start of the scan from which to end sum calculation.
135
+ Only frames before selected time will be included in the sum. If -1, use all frames
136
+ after `start_time` in the calculation. Default -1.
137
+
138
+ Returns:
139
+ ants.ANTsImage: SUVR parametric image
140
+ """
141
+ sum_img = weighted_sum_for_suv(input_image_path=input_image_path,
142
+ output_image_path=None,
143
+ start_time=start_time,
144
+ end_time=end_time)
145
+ segmentation_img = ants.image_read(filename=segmentation_image_path)
146
+
147
+ ref_region_avg = mean_value_in_region(input_img=sum_img,
148
+ seg_img=segmentation_img,
149
+ mappings=ref_region)
150
+
151
+ suvr_img = sum_img / ref_region_avg
152
+
153
+ if output_image_path is not None:
154
+ ants.image_write(image=suvr_img,
155
+ filename=output_image_path)
156
+ safe_copy_meta(input_image_path=input_image_path,
157
+ out_image_path=output_image_path)
158
+
159
+ return suvr_img
@@ -1,7 +1,7 @@
1
1
  """
2
2
  Module to handle timing information of PET scans.
3
3
  """
4
- import math
4
+ from typing import Self
5
5
  from dataclasses import dataclass
6
6
  import numpy as np
7
7
 
@@ -82,8 +82,8 @@ class ScanTimingInfo:
82
82
 
83
83
  """
84
84
  duration: np.ndarray[float]
85
- end: np.ndarray[float]
86
85
  start: np.ndarray[float]
86
+ end: np.ndarray[float]
87
87
  center: np.ndarray[float]
88
88
  decay: np.ndarray[float]
89
89
 
@@ -130,7 +130,7 @@ class ScanTimingInfo:
130
130
 
131
131
 
132
132
  @classmethod
133
- def from_metadata(cls, metadata_dict: dict):
133
+ def from_metadata(cls, metadata_dict: dict) -> Self:
134
134
  r"""
135
135
  Extracts frame timing information and decay factors from a json metadata.
136
136
  Expects that the JSON metadata has ``FrameDuration`` and ``DecayFactor`` or
@@ -155,13 +155,13 @@ class ScanTimingInfo:
155
155
  """
156
156
  frm_dur = np.asarray(metadata_dict['FrameDuration'], float)
157
157
  try:
158
- frm_ends = np.asarray(metadata_dict['FrameTimesEnd'], float)
158
+ frm_starts = np.asarray(metadata_dict['FrameTimesStart'], float)
159
159
  except KeyError:
160
- frm_ends = np.cumsum(frm_dur)
160
+ frm_starts = np.cumsum(frm_dur)-frm_dur
161
161
  try:
162
- frm_starts = np.asarray(metadata_dict['FrameTimesStart'], float)
162
+ frm_ends = np.asarray(metadata_dict['FrameTimesEnd'], float)
163
163
  except KeyError:
164
- frm_starts = np.diff(frm_ends)
164
+ frm_ends = frm_starts+frm_dur
165
165
  try:
166
166
  decay = np.asarray(metadata_dict['DecayCorrectionFactor'], float)
167
167
  except KeyError:
@@ -178,7 +178,7 @@ class ScanTimingInfo:
178
178
  decay=decay)
179
179
 
180
180
  @classmethod
181
- def from_nifti(cls, image_path: str):
181
+ def from_nifti(cls, image_path: str) -> Self:
182
182
  r"""
183
183
  Extracts frame timing information and decay factors from a NIfTI image metadata.
184
184
  Expects that the JSON metadata file has ``FrameDuration`` and ``DecayFactor`` or
@@ -204,6 +204,49 @@ class ScanTimingInfo:
204
204
  _meta_data = load_metadata_for_nifti_with_same_filename(image_path=image_path)
205
205
  return cls.from_metadata(metadata_dict=_meta_data)
206
206
 
207
+ @classmethod
208
+ def from_start_end(cls,
209
+ frame_starts: np.ndarray,
210
+ frame_ends: np.ndarray,
211
+ decay_correction_factor: np.ndarray | None=None) -> Self:
212
+ """Infer timing properties based on start and end time.
213
+
214
+ Args:
215
+ frame_starts (np.ndarray): Start time of each frame.
216
+ frame_ends (np.ndarray): End time of each frame.
217
+ decay_correction_factor (np.ndarray | None): Decay correction factor, which can be
218
+ optionally provided based on the type of analysis being done. If None, frame decay
219
+ will be set to ones. Default None.
220
+
221
+ Returns:
222
+ scan_timing_info (ScanTimingInfo): ScanTimingInfo object with the correct start, end,
223
+ duration, midpoint, and (optionally) decay correction for each frame.
224
+
225
+ Raises:
226
+ ValueError: If frame_starts, frame_ends, and decay_correction_factor (if provided) are
227
+ not of identical shape.
228
+
229
+ """
230
+ if frame_starts.shape != frame_ends.shape:
231
+ raise ValueError("frame_ends must have the same shape as frame_starts")
232
+
233
+ frame_duration = frame_ends - frame_starts
234
+ frame_midpoint = frame_starts + frame_duration / 2
235
+ frame_decay = np.ones_like(frame_starts)
236
+
237
+ if decay_correction_factor is None:
238
+ frame_decay = np.ones_like(frame_starts, dtype=float)
239
+ else:
240
+ frame_decay = np.asarray(decay_correction_factor, dtype=float)
241
+ if frame_decay.shape != frame_starts.shape:
242
+ raise ValueError("decay_correction_factor must have the same shape as frame_starts")
243
+
244
+ return cls(duration=frame_duration,
245
+ start=frame_starts,
246
+ end=frame_ends,
247
+ center=frame_midpoint,
248
+ decay=frame_decay)
249
+
207
250
 
208
251
  def get_window_index_pairs_from_durations(frame_durations: np.ndarray, w_size: float):
209
252
  r"""
@@ -263,25 +306,29 @@ def get_window_index_pairs_for_image(image_path: str, w_size: float):
263
306
  w_size=w_size)
264
307
 
265
308
 
266
- def calculate_frame_reference_time(frame_duration: float,
267
- frame_start: float,
268
- half_life: float) -> float:
309
+ def calculate_frame_reference_time(frame_duration: np.ndarray,
310
+ frame_start: np.ndarray,
311
+ half_life: float) -> np.ndarray:
269
312
  r"""Compute frame reference time as the time at which the average activity occurs.
270
313
 
271
- Equation comes from the `DICOM standard documentation <https://dicom.innolitics.com/ciods/positron-emission-tomography-image/pet-image/00541300>`_
314
+ Equation comes from the `DICOM standard documentation
315
+ <https://dicom.innolitics.com/ciods/positron-emission-tomography-image/pet-image/00541300>`_
272
316
 
273
317
  :math:`T_{ave}=\frac{1}{\lambda}ln\frac{\lambda T}{1-e^{-\lambda T}}`
274
318
 
275
- where lambda is the decay constant, :math:`\frac{ln2}{T_{1/2}}`, :math:`T_{1/2}` is the half life, and :math:`T` is the frame duration.
319
+ where lambda is the decay constant, :math:`\frac{ln2}{T_{1/2}}`, :math:`T_{1/2}` is the half
320
+ life, and :math:`T` is the frame duration.
276
321
 
277
322
  Args:
278
- frame_duration (float): Frame Duration in seconds
279
- frame_start (float): Start time of frame relative to scan start, in seconds
280
- half_life (float): Radionuclide half life
323
+ frame_duration (np.ndarray): Duration of each frame in seconds.
324
+ frame_start (np.ndarray): Start time of each frame relative to scan start, in seconds.
325
+ half_life (float): Radionuclide half life in seconds.
281
326
 
282
327
  Returns:
283
- float: Frame reference time
328
+ np.ndarray: Frame reference time for each frame in the scan in seconds.
284
329
  """
285
- decay_constant = math.log(2)/half_life
286
- frame_reference_time = frame_start + math.log((decay_constant*frame_duration)/(1-math.exp(-decay_constant*frame_duration)))/decay_constant
330
+ decay_constant = np.log(2)/half_life
331
+ decay_over_frame = decay_constant*frame_duration
332
+ reference_time_delay = np.log((decay_over_frame)/(1-np.exp(-decay_over_frame)))/decay_constant
333
+ frame_reference_time = frame_start + reference_time_delay
287
334
  return frame_reference_time
petpal/utils/stats.py CHANGED
@@ -6,6 +6,27 @@ import ants
6
6
  from ..meta.label_maps import LabelMapLoader
7
7
  from .useful_functions import check_physical_space_for_ants_image_pair
8
8
 
9
+ def mean_value_in_region(input_img: ants.ANTsImage,
10
+ seg_img: ants.ANTsImage,
11
+ mappings: int | list[int]) -> float:
12
+ """Calculate the mean value in a 3D PET image over a region based on one or more integer
13
+ mappings corresponding to regions in a segmentation image.
14
+
15
+ Args:
16
+ input_img (ants.ANTsImage): 3D PET image over which to calculate the mean.
17
+ seg_img (ants.ANTsImage): Segmentation image in same space as `input_img`.
18
+ mappings (int | list[int]): One or more mappings to mask input_image over.
19
+
20
+ Returns:
21
+ region_mean (float): Mean PET value over voxels in the regions corresponding to
22
+ `mappings`."""
23
+ region_mask = ants.mask_image(input_img, seg_img, level=mappings)
24
+ region_arr = region_mask.numpy().flatten()
25
+ region_arr_nonzero = region_arr.nonzero()
26
+ voxel_arr = region_arr[region_arr_nonzero]
27
+ return voxel_arr.mean()
28
+
29
+
9
30
  class RegionalStats:
10
31
  """Run statistics on each region in a parametric 3D PET kinetic model or other image.
11
32
 
@@ -1,6 +1,7 @@
1
1
  """
2
2
  Module to handle abstracted functionalities
3
3
  """
4
+ from collections.abc import Callable
4
5
  import os
5
6
  import nibabel
6
7
  import numpy as np
@@ -88,7 +89,7 @@ def build_label_map(region_names: list[str]):
88
89
  return abbreviated_names
89
90
 
90
91
 
91
- def weighted_series_sum(input_image_4d_path: str,
92
+ def weighted_series_sum(input_image_path: str,
92
93
  out_image_path: str,
93
94
  half_life: float,
94
95
  verbose: bool=False,
@@ -124,7 +125,7 @@ def weighted_series_sum(input_image_4d_path: str,
124
125
  # TODO: Determine half_life from .json rather than passing as argument.
125
126
 
126
127
  Args:
127
- input_image_4d_path (str): Path to a .nii or .nii.gz file containing a 4D
128
+ input_image_path (str): Path to a .nii or .nii.gz file containing a 4D
128
129
  PET image on which the weighted sum is calculated. Assume a metadata
129
130
  file exists with the same path and file name, but with extension .json,
130
131
  and follows BIDS standard.
@@ -147,8 +148,8 @@ def weighted_series_sum(input_image_4d_path: str,
147
148
  """
148
149
  if half_life <= 0:
149
150
  raise ValueError('(ImageOps4d): Radioisotope half life is zero or negative.')
150
- pet_meta = image_io.load_metadata_for_nifti_with_same_filename(input_image_4d_path)
151
- pet_image = nibabel.load(input_image_4d_path)
151
+ pet_meta = image_io.load_metadata_for_nifti_with_same_filename(input_image_path)
152
+ pet_image = nibabel.load(input_image_path)
152
153
  pet_series = pet_image.get_fdata()
153
154
  frame_start = pet_meta['FrameTimesStart']
154
155
  frame_duration = pet_meta['FrameDuration']
@@ -202,7 +203,7 @@ def weighted_series_sum(input_image_4d_path: str,
202
203
  nibabel.save(pet_sum_image, out_image_path)
203
204
  if verbose:
204
205
  print(f"(ImageOps4d): weighted sum image saved to {out_image_path}")
205
- image_io.safe_copy_meta(input_image_path=input_image_4d_path,
206
+ image_io.safe_copy_meta(input_image_path=input_image_path,
206
207
  out_image_path=out_image_path)
207
208
 
208
209
  return image_weighted_sum
@@ -431,3 +432,103 @@ def get_frame_from_timeseries(input_img: ants.ANTsImage, frame: int) -> ants.ANT
431
432
  ants.set_direction( img_3d, subdirection )
432
433
 
433
434
  return img_3d
435
+
436
+
437
+ def nearest_frame_to_timepoint(frame_times: np.ndarray) -> Callable[[float],float]:
438
+ """Returns a step function that gets the index of the frame closest to a provided timepoint
439
+ based on an array of frame times, such as the frame starts or reference times.
440
+
441
+ Args:
442
+ frame_times (np.ndarray): The frame times on which to generate the step function.
443
+
444
+ Returns:
445
+ nearest_frame_func (Callable[[float],float]): A function that returns the time closest to
446
+ the provided timepoint.
447
+ """
448
+ nearest_frame_func = interp1d(x=frame_times,
449
+ y=range(len(frame_times)),
450
+ kind='nearest',
451
+ bounds_error=False,
452
+ fill_value='extrapolate')
453
+ return nearest_frame_func
454
+
455
+
456
+ def get_average_of_timeseries(input_image: ants.ANTsImage) -> ants.ANTsImage:
457
+ """
458
+ Get average of a 4D ANTsImage and return as a 3D ANTsImage.
459
+
460
+ Args:
461
+ input_image (ants.ANTsImage): 4D PET image over which to compute timeseries average.
462
+
463
+ Returns:
464
+ mean_image (ants.ANTsImage): 3D mean over time in the PET image.
465
+ """
466
+ assert len(input_image.shape) == 4, "Input image must be 4D"
467
+ mean_array = input_image.mean(axis=-1)
468
+ mean_image = ants.from_numpy(data=mean_array,
469
+ origin=input_image.origin[:-1],
470
+ spacing=input_image.spacing[:-1],
471
+ direction=input_image.direction[:-1,:-1])
472
+ return mean_image
473
+
474
+
475
+ def gen_nd_image_based_on_image_list(image_list: list[ants.ANTsImage]) -> ants.ANTsImage:
476
+ r"""
477
+ Generate a 4D ANTsImage based on a list of 3D ANTsImages.
478
+
479
+ This function takes a list of 3D ANTsImages and constructs a new 4D ANTsImage,
480
+ where the additional dimension represents the number of frames (3D images) in the list.
481
+ The 4D image retains the spacing, origin, direction, and shape properties of the 3D images,
482
+ with appropriate modifications for the additional dimension.
483
+
484
+ Args:
485
+ image_list (list[ants.core.ants_image.ANTsImage]):
486
+ List of 3D ANTsImage objects to be combined into a 4D image.
487
+ The list must contain at least one image, and all images must have the same
488
+ dimensions and properties.
489
+
490
+ Returns:
491
+ ants.ANTsImage:
492
+ A 4D ANTsImage constructed from the input list of 3D images. The additional
493
+ dimension corresponds to the number of frames (length of the image list).
494
+
495
+ Raises:
496
+ AssertionError: If the `image_list` is empty or if the images in the list are not 3D.
497
+
498
+ See Also
499
+ * :func:`petpal.preproc.motion_corr.motion_corr_frame_list_to_t1`
500
+
501
+ Example:
502
+
503
+ .. code-block:: python
504
+
505
+
506
+ import ants
507
+ image1 = ants.image_read('frame1.nii.gz')
508
+ image2 = ants.image_read('frame2.nii.gz')
509
+ image_list = [image1, image2]
510
+ result = _gen_nd_image_based_on_image_list(image_list)
511
+ print(result.dimension) # 4
512
+ image4d = ants.list_to_ndimage(result, image_list)
513
+
514
+ """
515
+ assert len(image_list) > 0
516
+ assert image_list[0].dimension == 3
517
+
518
+ num_frames = len(image_list)
519
+ spacing_3d = image_list[0].spacing
520
+ origin_3d = image_list[0].origin
521
+ shape_3d = image_list[0].shape
522
+ direction_3d = image_list[0].direction
523
+
524
+ direction_4d = np.eye(4)
525
+ direction_4d[:3, :3] = direction_3d
526
+ spacing_4d = (*spacing_3d, 1.0)
527
+ origin_4d = (*origin_3d, 0.0)
528
+ shape_4d = (*shape_3d, num_frames)
529
+
530
+ tmp_image = ants.make_image(imagesize=shape_4d,
531
+ spacing=spacing_4d,
532
+ origin=origin_4d,
533
+ direction=direction_4d)
534
+ return tmp_image
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: petpal
3
- Version: 0.5.6
3
+ Version: 0.5.8
4
4
  Summary: PET-PAL (Positron Emission Tomography Processing and Analysis Library)
5
5
  Project-URL: Repository, https://github.com/PETPAL-WUSM/PETPAL.git
6
6
  Author-email: Noah Goldman <noahg@wustl.edu>, Bradley Judge <bjudge@wustl.edu>, Furqan Dar <dar@wustl.edu>, Kenan Oestreich <kenan.oestreich@wustl.edu>
@@ -4,15 +4,15 @@ petpal/cli/cli_graphical_analysis.py,sha256=nGb0afMAigJgvbyEj5EXOCt6WNU35LNo3h3K
4
4
  petpal/cli/cli_graphical_plots.py,sha256=_2tlGtZ0hIVyEYtGviEzGZMNhFymUPg4ZvSVyMtT_dA,3211
5
5
  petpal/cli/cli_idif.py,sha256=6lh_kJHcGjlHDXZOvbiuHrNqpk5FovVV5_j7_dPHTHU,5145
6
6
  petpal/cli/cli_parametric_images.py,sha256=JBFb8QlxZoGOzqvCJPFuZ7czzGWntJP5ZcfeM5-QF4Y,7385
7
- petpal/cli/cli_pib_processing.py,sha256=6EjoY0wSJZ7PImgjV9PxlGPgcZkcZISvFh9ctsZW3Gw,6935
7
+ petpal/cli/cli_pib_processing.py,sha256=ye_yw0ZQ4cSrMNemGR7cU9v6epD7Wbq1xaNAJwLzV_8,6889
8
8
  petpal/cli/cli_plot_tacs.py,sha256=XycaYQQl9Jp5jqDp3QXOlVT2sXHYYpYSraEArxsfJec,6479
9
- petpal/cli/cli_preproc.py,sha256=_l4OoOnKUTgu0T5lT9ctZK1h5qj7yBZgtf0m0PK_HS0,20355
9
+ petpal/cli/cli_preproc.py,sha256=y5YvRliXC3zNY8oBJgTkzwPH9YNwWnEUWgiltUAv7AU,21850
10
10
  petpal/cli/cli_pvc.py,sha256=DC0JZ6p1pkc5BDgQ006bi9y0Mz32ENrjUaOtSvFobP4,3967
11
11
  petpal/cli/cli_reference_tissue_models.py,sha256=18BlKN4rMehyFbdq_yr88oztqR99_gBtWKImhwf7CQY,13283
12
12
  petpal/cli/cli_stats.py,sha256=Mqbzc9yYo9SVAfxzaYbAbk7EheW472l1PY_ptlD1DOI,2050
13
13
  petpal/cli/cli_tac_fitting.py,sha256=bCYwFAbxIKwnYBteAKnot5vOsk9F4Z1EJw2Xk0tZ9oo,14989
14
14
  petpal/cli/cli_tac_interpolation.py,sha256=Nwf0CAfyEATLeiwuPSirS0DWDeerrIH2P-U0lpXpKWk,5734
15
- petpal/cli/cli_vat_processing.py,sha256=Zr76hISMVCCwjGKp8zk0CiPdewzSOeUO2zaFZJ3yGl0,12346
15
+ petpal/cli/cli_vat_processing.py,sha256=XrWcjZqgc5JAtp4fZ94ZLJ7h6fvdMhZvR30nh7GCD4w,12404
16
16
  petpal/input_function/__init__.py,sha256=mWdwuVdMSgaHE0wviNE7TGGoOI9Y3sEKfKpBqLS-Ph4,151
17
17
  petpal/input_function/blood_input.py,sha256=TNx3hL7M8Z_ZaZoTpt8LgLQhXnNyW0BOhgVZompwgxA,9206
18
18
  petpal/input_function/idif_necktangle.py,sha256=o5kyAqyT4C6o7zELY4EjyHrkJyX1BWcxvBqYiMjNyn4,7863
@@ -32,18 +32,20 @@ petpal/meta/label_maps.py,sha256=cifp_KXQAgIbdWoinMpOQstEK4-pasSXlgML6xoEjHM,227
32
32
  petpal/pipelines/__init__.py,sha256=Qt9VwqAvVjadHR6Lsja05XIVQONHTCs30NFxiBvf_2k,266
33
33
  petpal/pipelines/kinetic_modeling_steps.py,sha256=G6FyfhR0MJ83b4pnww_FhZcAY8PwAIXSYglyoj1mPoQ,32717
34
34
  petpal/pipelines/pca_guided_idif_steps.py,sha256=tuL3stKDlUQsHBTTzlYx_WgBKwaS8eHpieUjzB90Mq4,20550
35
- petpal/pipelines/pipelines.py,sha256=lyvXp7qGP859D9e-F9FUuRKvEKEMj1dVxMH-NiyUHJc,38633
36
- petpal/pipelines/preproc_steps.py,sha256=bKrBTsPuQlpr76UPlbbBlAS8tohTD45QUIabTn1eNmY,38119
35
+ petpal/pipelines/pipelines.py,sha256=2KgeOvrXmjNrecTQMqIKMPv4tzvaRjr1FhvntVyvHX0,38391
36
+ petpal/pipelines/preproc_steps.py,sha256=VC-KoMwxnfv0BxUEGneDjDy6HUYAub6JztaRHm3gm4M,37987
37
37
  petpal/pipelines/steps_base.py,sha256=W7GVN5-tsXe_7fvhoMRIlOk5ggY8V2wpSSmDONphLnQ,18311
38
38
  petpal/pipelines/steps_containers.py,sha256=TV4LkPK48OnAds10vLcsPI3qtWjHsmwr6XGu3hup59Q,33767
39
- petpal/preproc/__init__.py,sha256=OCYUXxPiQOCENQuzUSrtJaRZKj8dAnOQcq4kOn6N2i4,440
40
- petpal/preproc/decay_correction.py,sha256=QCA_QcB6pqAD_wYSqtRKSvO6qWCaEzgL_qrAcSczRtw,6829
41
- petpal/preproc/image_operations_4d.py,sha256=qYCndoBO4eJwlgqzvMkN12ftlEc4NNayLhtqSNZC29I,38714
42
- petpal/preproc/motion_corr.py,sha256=UVNFII1-Z8cYEHc27xFl4tqEjo5c6Q3pLDksPoP-RM0,32301
39
+ petpal/preproc/__init__.py,sha256=HmTVnCiKMxetDT_w-qU_62UOC39_A83LHXhZm07Q81I,504
40
+ petpal/preproc/decay_correction.py,sha256=jT8X2lmMrdGf9-lo1ooKul_yomPqm1p24gB9On_GHl0,6872
41
+ petpal/preproc/image_operations_4d.py,sha256=IqzwxaWxoWC1gmK00uuHIwlhx8e_eQ44C6yVFuu73W4,31371
42
+ petpal/preproc/motion_corr.py,sha256=dz10qjXBVTF_RH5RPZ68drUVX2qyj-MnZ674_Ccwz2Y,28670
43
+ petpal/preproc/motion_target.py,sha256=_OJp3NoYcyD3Ke3wl2KbfOhbJ6dp6ZduR9LLz0rIaC0,3945
43
44
  petpal/preproc/partial_volume_corrections.py,sha256=J06j_Y_lhj3b3b9M5FbB2r2EPWQvoymG3GRUffSlYdE,6799
44
- petpal/preproc/regional_tac_extraction.py,sha256=9B7LrVmVFfMCC5cl3ACamvJEsCU49iu_3Z8lugS_eUc,19713
45
- petpal/preproc/register.py,sha256=K_hvcV47ZRBfJF8QC6EM3bQXzkPdpN3xXYer_lqyZuE,14500
46
- petpal/preproc/segmentation_tools.py,sha256=Z2tZxDXRQkQhWtRkoWRs2VOwwLMDXnP5xJ_Z_52CN5c,25680
45
+ petpal/preproc/regional_tac_extraction.py,sha256=qQDD9Z9p21DVUKokh_en2chOGP7F01wnDN156_74X8Q,19704
46
+ petpal/preproc/register.py,sha256=NKg8mt_XMGa5HBdxYZh3sMu_KMJ0W41VHlX4Zl8wlyE,14171
47
+ petpal/preproc/segmentation_tools.py,sha256=BUy8ij45mmetenvWzODVwNIThDkYiEtY6gTAqI8sIak,25703
48
+ petpal/preproc/standard_uptake_value.py,sha256=YJIt0fl3fwMLl0tRYHpPPprMTaN4Q5JjQ5dx_CQX1nI,7494
47
49
  petpal/preproc/symmetric_geometric_transfer_matrix.py,sha256=ELkr7Mo233to1Rwml5YJ-aBvmTSk3LHNSdRhnX0WBDw,17575
48
50
  petpal/utils/__init__.py,sha256=PlxBIKUtNvtSFnNZqz8myszOysaYzS8nSILMK4haVGg,412
49
51
  petpal/utils/bids_utils.py,sha256=3eZAzwGpOBUQ5ShVBUJJpmUBUhr3VcOikR-KpGCsdE0,7664
@@ -53,18 +55,18 @@ petpal/utils/decorators.py,sha256=9CVT4rXnSUqryNL83jmhQHiI6IGDr2E8jBqPD-KhYGA,49
53
55
  petpal/utils/image_io.py,sha256=2Dj2U-OaGL15lwt8KVyl_RZZZdRYdvzUahQWegO_JrA,17995
54
56
  petpal/utils/math_lib.py,sha256=DYt80lB1je-wFqHGuzOwfTOM1tPugomB889xBUdr99U,4725
55
57
  petpal/utils/metadata.py,sha256=O9exRDlqAmPAEcO9v7dsqzkYcSVLgRA207owEvNXXJ8,6129
56
- petpal/utils/scan_timing.py,sha256=j7i66Nt0Qs3fnQLUaycLHQTfVsNOqS7YS-xUJKm7nYk,11795
57
- petpal/utils/stats.py,sha256=W-6sMnZoKbp9zEp7CWl3iWLyly4948gmLbK7P3Q2YW4,5496
58
+ petpal/utils/scan_timing.py,sha256=CYtYuFquAnOQ2QfjXdeLjWrBDPM_k4vBI9oHQdpmVZ0,13908
59
+ petpal/utils/stats.py,sha256=paFdwVPIjlAi0wh5xU4x5WeydjKsEHuwzMLcDG_WzPc,6449
58
60
  petpal/utils/testing_utils.py,sha256=eMt1kklxK3rl8tm74I3yVNDotKh1CnYWLINDT7rzboM,9557
59
61
  petpal/utils/time_activity_curve.py,sha256=gX3PDYbeWblycvtvyiuFtnv1mBml_-93sIXKh2EmglM,39137
60
- petpal/utils/useful_functions.py,sha256=IziQ6DnB5CcxRlk9_14QWXdDzDACw7WKIAsKQ2rBbQg,17526
62
+ petpal/utils/useful_functions.py,sha256=md2kTLbs45MhrjdMhvDYcbflPTRNPspRSIHiOeIxEqY,21361
61
63
  petpal/visualizations/__init__.py,sha256=bd0NHDVl6Z2BDhisEcob2iIcqfxUfgKJ4DEmlrXJRP4,205
62
64
  petpal/visualizations/graphical_plots.py,sha256=ZCKUeLX2TAQscuHjA4bzlFm1bACHIyCwDuNnjCakVWU,47297
63
65
  petpal/visualizations/image_visualization.py,sha256=Ob6TD4Q0pIrxi0m9SznK1TRWbX1Ea9Pt4wNMdRrTfTs,9124
64
66
  petpal/visualizations/qc_plots.py,sha256=iaCPe-LWWyM3OZzDPZodHZhP-z5fRdpUgaH7QS9VxPM,1243
65
67
  petpal/visualizations/tac_plots.py,sha256=zSGdptL-EnqhfDViAX8LFunln5a1b-NJ5ft7ZDcxQ38,15116
66
- petpal-0.5.6.dist-info/METADATA,sha256=W0Fo_jDNeBMUBbXybn9HymGcieOEqygaZDqETObBvrw,2617
67
- petpal-0.5.6.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
68
- petpal-0.5.6.dist-info/entry_points.txt,sha256=0SZmyXqBxKzQg2eerDA16n2BdUEXyixEm0_AUo2dFns,653
69
- petpal-0.5.6.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
70
- petpal-0.5.6.dist-info/RECORD,,
68
+ petpal-0.5.8.dist-info/METADATA,sha256=p2q6Rl726zTvyMW39Uw3j4jw0dXYKFhIDvkGG9nXqKk,2617
69
+ petpal-0.5.8.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
70
+ petpal-0.5.8.dist-info/entry_points.txt,sha256=0SZmyXqBxKzQg2eerDA16n2BdUEXyixEm0_AUo2dFns,653
71
+ petpal-0.5.8.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
72
+ petpal-0.5.8.dist-info/RECORD,,
File without changes