[docs]@dataclassclassStandardMetadata:""" A simple container for embedded metadata fields. Attributes ---------- binning: Optional[str] Binning configuration. column: Optional[str] Column information. dimensions_present: Optional[Sequence[str]] List or sequence of dimension names. image_size_c: Optional[int] Channel dimension size. image_size_t: Optional[int] Time dimension size. image_size_x: Optional[int] Spatial X dimension size. image_size_y: Optional[int] Spatial Y dimension size. image_size_z: Optional[int] Spatial Z dimension size. imaged_by: Optional[str] The experimentalist who produced this data. imaging_date: Optional[str] Date this file was imaged. objective: Optional[str] Objective. pixel_size_x: Optional[float] Physical pixel size along X. pixel_size_y: Optional[float] Physical pixel size along Y. pixel_size_z: Optional[float] Physical pixel size along Z. position_index: Optional[int] Position index, if applicable. row: Optional[str] Row information. timelapse: Optional[bool] Is the data a timelapse? timelapse_interval: Optional[timedelta] Average time interval between timepoints. total_time_duration: Optional[timedelta] Total time duration of imaging, measured from the beginning of the first time point to the beginning of the final time point. FIELD_LABELS: dict[str, str] Mapping of the above attribute names to readable labels. """binning:Optional[str]=Nonecolumn:Optional[str]=Nonedimensions_present:Optional[Sequence[str]]=Noneimage_size_c:Optional[int]=Noneimage_size_t:Optional[int]=Noneimage_size_x:Optional[int]=Noneimage_size_y:Optional[int]=Noneimage_size_z:Optional[int]=Noneimaged_by:Optional[str]=Noneimaging_datetime:Optional[datetime]=Noneobjective:Optional[str]=Nonepixel_size_x:Optional[float]=Nonepixel_size_y:Optional[float]=Nonepixel_size_z:Optional[float]=Noneposition_index:Optional[int]=Nonerow:Optional[str]=Nonetimelapse:Optional[bool]=Nonetimelapse_interval:Optional[timedelta]=Nonetotal_time_duration:Optional[timedelta]=NoneFIELD_LABELS={"binning":"Binning","column":"Column","dimensions_present":"Dimensions Present","image_size_c":"Image Size C","image_size_t":"Image Size T","image_size_x":"Image Size X","image_size_y":"Image Size Y","image_size_z":"Image Size Z","imaged_by":"Imaged By","imaging_datetime":"Imaging Datetime","objective":"Objective","pixel_size_x":"Pixel Size X","pixel_size_y":"Pixel Size Y","pixel_size_z":"Pixel Size Z","position_index":"Position Index","row":"Row","timelapse":"Timelapse","timelapse_interval":"Timelapse Interval","total_time_duration":"Total Time Duration",}
[docs]defto_dict(self)->dict:""" Convert the metadata into a dictionary using readable labels. Returns: dict: A mapping where keys are the readable labels defined in FIELD_LABELS, and values are the corresponding metadata values. """return{self.FIELD_LABELS[field]:getattr(self,field)forfieldinself.FIELD_LABELS}
[docs]defbinning(ome:OME)->Optional[str]:""" Extracts the binning setting from the OME metadata. Returns ------- Optional[str] The binning setting as a string. Returns None if not found. """try:# DetectorSettings under each Channel holds the binning infochannels=ome.images[0].pixels.channelsor[]forchannelinchannels:ds=channel.detector_settingsifdsandds.binning:returnstr(ds.binning.value)exceptExceptionasexc:log.warning("Failed to extract Binning setting: %s",exc,exc_info=True)returnNone
[docs]defimaged_by(ome:OME)->Optional[str]:""" Extracts the name of the experimenter (user who imaged the sample). Returns ------- Optional[str] The username of the experimenter. Returns None if not found. """try:img=ome.images[0]# Prefer explicit ExperimenterRef if presentifimg.experimenter_refandome.experimenters:exp=next((eforeinome.experimentersife.id==img.experimenter_ref.id),None)ifexpandexp.user_name:returnexp.user_name# Fallback to first Experimenterifome.experimenters:returnome.experimenters[0].user_nameexceptExceptionasexc:log.warning("Failed to extract Imaged By: %s",exc,exc_info=True)returnNone
[docs]defimaging_datetime(ome:OME)->Optional[datetime]:""" Extracts the acquisition datetime from the OME metadata. Returns ------- Optional[datetime] The acquisition datetime as provided in the metadata, including its original timezone. None: if the acquisition datetime is not found or cannot be parsed. """try:img=ome.images[0]acq=img.acquisition_datereturnacqexceptExceptionasexc:log.warning("Failed to extract Acquisition Datetime: %s",exc,exc_info=True)returnNone
[docs]defobjective(ome:OME)->Optional[str]:""" Extracts the microscope objective details. Returns ------- Optional[str] The formatted objective magnification and numerical aperture. Returns the raw string (e.g. "40x/1.2W"). """try:img=ome.images[0]instrs=ome.instrumentsor[]instr=None# Prefer explicit InstrumentRefifimg.instrument_ref:instr=next((iforiininstrsifi.id==img.instrument_ref.id),None)# Fallback to first Instrumentifnotinstrandinstrs:instr=instrs[0]ifinstrandinstr.objectives:obj=instr.objectives[0]mag=round(float(obj.nominal_magnification))na=obj.lens_naimm=obj.immersion.valueifobj.immersionelse""raw_obj=f"{mag}x/{na}{imm}"returnraw_objexceptExceptionasexc:log.warning("Failed to extract Objective: %s",exc,exc_info=True)returnNone
def_convert_to_timedelta(delta_t:float,unit:Optional[UnitsTime])->timedelta:""" Converts delta_t to a timedelta object based on the provided unit. """ifunitisNone:# Assume seconds if unit is Nonereturntimedelta(seconds=delta_t)unit_value=unit.value# Access the string representation of the enumifunit_value=="ms":returntimedelta(milliseconds=delta_t)elifunit_value=="µs":returntimedelta(microseconds=delta_t)elifunit_value=="ns":returntimedelta(microseconds=delta_t/1000.0)else:# Default to seconds for unrecognized unitslog.warning("No units found for timedelta, defaulting to seconds.")returntimedelta(seconds=delta_t)
[docs]deftotal_time_duration(ome:OME,scene_index:int)->Optional[timedelta]:""" Computes the total time duration from the beginning of the first timepoint to the beginning of the final timepoint. """try:image=ome.images[scene_index]planes=image.pixels.planes# Initialize variables to track the maximum the_t and corresponding planemax_t=-1target_plane=Noneforpinplanes:ifp.the_z==0andp.the_c==0andp.the_tisnotNone:ifp.the_t>max_t:max_t=p.the_ttarget_plane=piftarget_planeisNoneortarget_plane.delta_tisNone:returnNonereturn_convert_to_timedelta(target_plane.delta_t,target_plane.delta_t_unit)exceptException:returnNone
[docs]deftimelapse_interval(ome:OME,scene_index:int)->Optional[timedelta]:""" Computes the average time interval between consecutive timepoints. """try:image=ome.images[scene_index]size_t=image.pixels.size_tifsize_tisNoneorsize_t<2:returnNonetotal_duration=total_time_duration(ome,scene_index)iftotal_durationisNone:returnNonereturntotal_duration/(size_t-1)exceptException:returnNone