petpal 0.5.7__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.
- petpal/preproc/decay_correction.py +11 -10
- petpal/utils/scan_timing.py +66 -19
- {petpal-0.5.7.dist-info → petpal-0.5.8.dist-info}/METADATA +1 -1
- {petpal-0.5.7.dist-info → petpal-0.5.8.dist-info}/RECORD +7 -7
- {petpal-0.5.7.dist-info → petpal-0.5.8.dist-info}/WHEEL +0 -0
- {petpal-0.5.7.dist-info → petpal-0.5.8.dist-info}/entry_points.txt +0 -0
- {petpal-0.5.7.dist-info → petpal-0.5.8.dist-info}/licenses/LICENSE +0 -0
|
@@ -129,21 +129,22 @@ def decay_correct(input_image_path: str,
|
|
|
129
129
|
return corrected_image
|
|
130
130
|
|
|
131
131
|
|
|
132
|
-
def calculate_frame_decay_factor(frame_reference_time:
|
|
133
|
-
half_life: float) ->
|
|
134
|
-
"""Calculate decay
|
|
132
|
+
def calculate_frame_decay_factor(frame_reference_time: np.ndarray,
|
|
133
|
+
half_life: float) -> np.ndarray:
|
|
134
|
+
"""Calculate decay correction factors for a scan given the frame reference time and half life.
|
|
135
135
|
|
|
136
136
|
Important:
|
|
137
137
|
The frame reference time should be the time at which average activity occurs,
|
|
138
|
-
not simply the midpoint. See
|
|
139
|
-
|
|
138
|
+
not simply the midpoint. See
|
|
139
|
+
:meth:`~petpal.utils.scan_timing.calculate_frame_reference_time` for more info.
|
|
140
|
+
|
|
140
141
|
Args:
|
|
141
|
-
frame_reference_time (
|
|
142
|
+
frame_reference_time (np.ndarray): Time at which the average activity occurs for the frame.
|
|
142
143
|
half_life (float): Radionuclide half life.
|
|
143
144
|
|
|
144
145
|
Returns:
|
|
145
|
-
|
|
146
|
+
np.ndarray: Decay Correction Factors for each frame in the scan.
|
|
146
147
|
"""
|
|
147
|
-
decay_constant =
|
|
148
|
-
frame_decay_factor =
|
|
149
|
-
return frame_decay_factor
|
|
148
|
+
decay_constant = np.log(2)/half_life
|
|
149
|
+
frame_decay_factor = np.exp((decay_constant)*frame_reference_time)
|
|
150
|
+
return frame_decay_factor
|
petpal/utils/scan_timing.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""
|
|
2
2
|
Module to handle timing information of PET scans.
|
|
3
3
|
"""
|
|
4
|
-
import
|
|
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
|
-
|
|
158
|
+
frm_starts = np.asarray(metadata_dict['FrameTimesStart'], float)
|
|
159
159
|
except KeyError:
|
|
160
|
-
|
|
160
|
+
frm_starts = np.cumsum(frm_dur)-frm_dur
|
|
161
161
|
try:
|
|
162
|
-
|
|
162
|
+
frm_ends = np.asarray(metadata_dict['FrameTimesEnd'], float)
|
|
163
163
|
except KeyError:
|
|
164
|
-
|
|
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:
|
|
267
|
-
frame_start:
|
|
268
|
-
half_life: 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
|
|
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
|
|
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 (
|
|
279
|
-
frame_start (
|
|
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
|
-
|
|
328
|
+
np.ndarray: Frame reference time for each frame in the scan in seconds.
|
|
284
329
|
"""
|
|
285
|
-
decay_constant =
|
|
286
|
-
|
|
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
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: petpal
|
|
3
|
-
Version: 0.5.
|
|
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>
|
|
@@ -37,7 +37,7 @@ petpal/pipelines/preproc_steps.py,sha256=VC-KoMwxnfv0BxUEGneDjDy6HUYAub6JztaRHm3
|
|
|
37
37
|
petpal/pipelines/steps_base.py,sha256=W7GVN5-tsXe_7fvhoMRIlOk5ggY8V2wpSSmDONphLnQ,18311
|
|
38
38
|
petpal/pipelines/steps_containers.py,sha256=TV4LkPK48OnAds10vLcsPI3qtWjHsmwr6XGu3hup59Q,33767
|
|
39
39
|
petpal/preproc/__init__.py,sha256=HmTVnCiKMxetDT_w-qU_62UOC39_A83LHXhZm07Q81I,504
|
|
40
|
-
petpal/preproc/decay_correction.py,sha256=
|
|
40
|
+
petpal/preproc/decay_correction.py,sha256=jT8X2lmMrdGf9-lo1ooKul_yomPqm1p24gB9On_GHl0,6872
|
|
41
41
|
petpal/preproc/image_operations_4d.py,sha256=IqzwxaWxoWC1gmK00uuHIwlhx8e_eQ44C6yVFuu73W4,31371
|
|
42
42
|
petpal/preproc/motion_corr.py,sha256=dz10qjXBVTF_RH5RPZ68drUVX2qyj-MnZ674_Ccwz2Y,28670
|
|
43
43
|
petpal/preproc/motion_target.py,sha256=_OJp3NoYcyD3Ke3wl2KbfOhbJ6dp6ZduR9LLz0rIaC0,3945
|
|
@@ -55,7 +55,7 @@ petpal/utils/decorators.py,sha256=9CVT4rXnSUqryNL83jmhQHiI6IGDr2E8jBqPD-KhYGA,49
|
|
|
55
55
|
petpal/utils/image_io.py,sha256=2Dj2U-OaGL15lwt8KVyl_RZZZdRYdvzUahQWegO_JrA,17995
|
|
56
56
|
petpal/utils/math_lib.py,sha256=DYt80lB1je-wFqHGuzOwfTOM1tPugomB889xBUdr99U,4725
|
|
57
57
|
petpal/utils/metadata.py,sha256=O9exRDlqAmPAEcO9v7dsqzkYcSVLgRA207owEvNXXJ8,6129
|
|
58
|
-
petpal/utils/scan_timing.py,sha256=
|
|
58
|
+
petpal/utils/scan_timing.py,sha256=CYtYuFquAnOQ2QfjXdeLjWrBDPM_k4vBI9oHQdpmVZ0,13908
|
|
59
59
|
petpal/utils/stats.py,sha256=paFdwVPIjlAi0wh5xU4x5WeydjKsEHuwzMLcDG_WzPc,6449
|
|
60
60
|
petpal/utils/testing_utils.py,sha256=eMt1kklxK3rl8tm74I3yVNDotKh1CnYWLINDT7rzboM,9557
|
|
61
61
|
petpal/utils/time_activity_curve.py,sha256=gX3PDYbeWblycvtvyiuFtnv1mBml_-93sIXKh2EmglM,39137
|
|
@@ -65,8 +65,8 @@ petpal/visualizations/graphical_plots.py,sha256=ZCKUeLX2TAQscuHjA4bzlFm1bACHIyCw
|
|
|
65
65
|
petpal/visualizations/image_visualization.py,sha256=Ob6TD4Q0pIrxi0m9SznK1TRWbX1Ea9Pt4wNMdRrTfTs,9124
|
|
66
66
|
petpal/visualizations/qc_plots.py,sha256=iaCPe-LWWyM3OZzDPZodHZhP-z5fRdpUgaH7QS9VxPM,1243
|
|
67
67
|
petpal/visualizations/tac_plots.py,sha256=zSGdptL-EnqhfDViAX8LFunln5a1b-NJ5ft7ZDcxQ38,15116
|
|
68
|
-
petpal-0.5.
|
|
69
|
-
petpal-0.5.
|
|
70
|
-
petpal-0.5.
|
|
71
|
-
petpal-0.5.
|
|
72
|
-
petpal-0.5.
|
|
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
|
|
File without changes
|
|
File without changes
|