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.
@@ -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: float,
133
- half_life: float) -> float:
134
- """Calculate decay factor for a single frame, given the frame reference time and half life.
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 preproc.scan_timing.calculate_frame_reference_time for more info.
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 (float): Time at which the average activity occurs for the frame.
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
- float: Decay Correction Factor for the frame.
146
+ np.ndarray: Decay Correction Factors for each frame in the scan.
146
147
  """
147
- decay_constant = math.log(2)/half_life
148
- frame_decay_factor = math.exp((decay_constant)*frame_reference_time)
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
@@ -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
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: petpal
3
- Version: 0.5.7
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=QCA_QcB6pqAD_wYSqtRKSvO6qWCaEzgL_qrAcSczRtw,6829
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=j7i66Nt0Qs3fnQLUaycLHQTfVsNOqS7YS-xUJKm7nYk,11795
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.7.dist-info/METADATA,sha256=9fNNCPhSznboKgTX9xPVDIDTJXquMiPoh66Bq-PN9lg,2617
69
- petpal-0.5.7.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
70
- petpal-0.5.7.dist-info/entry_points.txt,sha256=0SZmyXqBxKzQg2eerDA16n2BdUEXyixEm0_AUo2dFns,653
71
- petpal-0.5.7.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
72
- petpal-0.5.7.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