11import logging
22from dataclasses import dataclass
3- from datetime import datetime
3+ from datetime import datetime , timedelta
44from typing import Optional , Sequence
55
66from ome_types import OME
7+ from ome_types .model import UnitsTime
78
89log = logging .getLogger (__name__ )
910
@@ -66,11 +67,10 @@ class StandardMetadata:
6667 timelapse: Optional[bool]
6768 Is the data a timelapse?
6869
69- timelapse_interval: Optional[float]
70- Time interval between frames, measured from the beginning of the first
71- time point to the beginning of the second timepoint.
70+ timelapse_interval: Optional[timedelta]
71+ Average time interval between timepoints.
7272
73- total_time_duration: Optional[str ]
73+ total_time_duration: Optional[timedelta ]
7474 Total time duration of imaging, measured from the beginning of the first
7575 time point to the beginning of the final time point.
7676
@@ -95,8 +95,8 @@ class StandardMetadata:
9595 position_index : Optional [int ] = None
9696 row : Optional [str ] = None
9797 timelapse : Optional [bool ] = None
98- timelapse_interval : Optional [float ] = None
99- total_time_duration : Optional [str ] = None
98+ timelapse_interval : Optional [timedelta ] = None
99+ total_time_duration : Optional [timedelta ] = None
100100
101101 FIELD_LABELS = {
102102 "binning" : "Binning" ,
@@ -232,3 +232,71 @@ def objective(ome: OME) -> Optional[str]:
232232 except Exception as exc :
233233 log .warning ("Failed to extract Objective: %s" , exc , exc_info = True )
234234 return None
235+
236+
237+ def _convert_to_timedelta (delta_t : float , unit : Optional [UnitsTime ]) -> timedelta :
238+ """
239+ Converts delta_t to a timedelta object based on the provided unit.
240+ """
241+ if unit is None :
242+ # Assume seconds if unit is None
243+ return timedelta (seconds = delta_t )
244+
245+ unit_value = unit .value # Access the string representation of the enum
246+
247+ if unit_value == "ms" :
248+ return timedelta (milliseconds = delta_t )
249+ elif unit_value == "µs" :
250+ return timedelta (microseconds = delta_t )
251+ elif unit_value == "ns" :
252+ return timedelta (microseconds = delta_t / 1000.0 )
253+ else :
254+ # Default to seconds for unrecognized units
255+ log .warning ("No units found for timedelta, defaulting to seconds." )
256+ return timedelta (seconds = delta_t )
257+
258+
259+ def total_time_duration (ome : OME , scene_index : int ) -> Optional [timedelta ]:
260+ """
261+ Computes the total time duration from the beginning of the first
262+ timepoint to the beginning of the final timepoint.
263+ """
264+ try :
265+ image = ome .images [scene_index ]
266+ planes = image .pixels .planes
267+
268+ # Initialize variables to track the maximum the_t and corresponding plane
269+ max_t = - 1
270+ target_plane = None
271+
272+ for p in planes :
273+ if p .the_z == 0 and p .the_c == 0 and p .the_t is not None :
274+ if p .the_t > max_t :
275+ max_t = p .the_t
276+ target_plane = p
277+
278+ if target_plane is None or target_plane .delta_t is None :
279+ return None
280+
281+ return _convert_to_timedelta (target_plane .delta_t , target_plane .delta_t_unit )
282+ except Exception :
283+ return None
284+
285+
286+ def timelapse_interval (ome : OME , scene_index : int ) -> Optional [timedelta ]:
287+ """
288+ Computes the average time interval between consecutive timepoints.
289+ """
290+ try :
291+ image = ome .images [scene_index ]
292+ size_t = image .pixels .size_t
293+ if size_t is None or size_t < 2 :
294+ return None
295+
296+ total_duration = total_time_duration (ome , scene_index )
297+ if total_duration is None :
298+ return None
299+
300+ return total_duration / (size_t - 1 )
301+ except Exception :
302+ return None
0 commit comments