Skip to content

Commit daa23c3

Browse files
Replace dict return with StageMetadata class
1 parent a13dc5c commit daa23c3

1 file changed

Lines changed: 86 additions & 134 deletions

File tree

src/imcflibs/imagej/bioformats.py

Lines changed: 86 additions & 134 deletions
Original file line numberDiff line numberDiff line change
@@ -486,169 +486,121 @@ def get_stage_coords(source, filenames):
486486
source : str
487487
Path to the images.
488488
filenames : list of str
489-
List of images filenames.
489+
List of image filenames.
490490
491491
Returns
492492
-------
493-
dict
494-
495-
{
496-
dimensions : int, # number of dimensions (2D or 3D)
497-
stage_coordinates_x : list, # absolute stage x-coordinated
498-
stage_coordinates_y : list, # absolute stage y-coordinated
499-
stage_coordinates_z : list, # absolute stage z-coordinated
500-
relative_coordinates_x : list, # relative stage x-coordinates in px
501-
relative_coordinates_y : list, # relative stage y-coordinates in px
502-
relative_coordinates_z : list, # relative stage z-coordinates in px
503-
image_calibration : list, # x,y,z image calibration in unit/px
504-
calibration_unit : str, # image calibration unit
505-
image_dimensions_czt : list, # number of images in dimensions c,z,t
506-
series_names : list of str, # names of all series in the files
507-
max_size : list of int, # max size (x/y/z) across all files
508-
}
493+
StageMetadata
494+
An object containing extracted stage metadata.
509495
"""
510-
511-
# open an array to store the abosolute stage coordinates from metadata
496+
# Initialize lists to store stage coordinates and series names
512497
stage_coordinates_x = []
513498
stage_coordinates_y = []
514499
stage_coordinates_z = []
515500
series_names = []
516501

502+
# Intiialize default values
503+
dimensions = 2
504+
image_calibration = []
505+
calibration_unit = "unknown"
506+
image_dimensions_czt = []
507+
max_size = []
508+
509+
# Initialize max_size variables to track the maximums
510+
max_phys_size_x = 0.0
511+
max_phys_size_y = 0.0
512+
max_phys_size_z = 0.0
513+
517514
for counter, image in enumerate(filenames):
518-
# parse metadata
519515
reader = ImageReader()
520516
reader.setFlattenedResolutions(False)
521-
omeMeta = MetadataTools.createOMEXMLMetadata()
522-
reader.setMetadataStore(omeMeta)
517+
ome_meta = MetadataTools.createOMEXMLMetadata()
518+
reader.setMetadataStore(ome_meta)
523519
reader.setId(source + str(image))
524520
series_count = reader.getSeriesCount()
525521

526-
# get hyperstack dimensions from the first image
522+
# Process only the first image to get values not dependent on series
527523
if counter == 0:
528524
frame_size_x = reader.getSizeX()
529525
frame_size_y = reader.getSizeY()
530526
frame_size_z = reader.getSizeZ()
531527
frame_size_c = reader.getSizeC()
532528
frame_size_t = reader.getSizeT()
533529

534-
# note the dimensions
535-
if frame_size_z == 1:
536-
dimensions = 2
537-
if frame_size_z > 1:
538-
dimensions = 3
539-
540-
# get the physical calibration for the first image series
541-
physSizeX = omeMeta.getPixelsPhysicalSizeX(0)
542-
physSizeY = omeMeta.getPixelsPhysicalSizeY(0)
543-
physSizeZ = omeMeta.getPixelsPhysicalSizeZ(0)
544-
545-
# workaround to get the z-interval if physSizeZ.value() returns None.
546-
z_interval = 1
547-
if physSizeZ is not None:
548-
z_interval = physSizeZ.value()
549-
550-
if frame_size_z > 1 and physSizeZ is None:
551-
log.debug("no z calibration found, trying to recover")
552-
first_plane = omeMeta.getPlanePositionZ(0, 0)
553-
next_plane_imagenumber = frame_size_c + frame_size_t - 1
554-
second_plane = omeMeta.getPlanePositionZ(0, next_plane_imagenumber)
555-
z_interval = abs(abs(first_plane.value()) - abs(second_plane.value()))
556-
log.debug("z-interval seems to be: " + str(z_interval))
557-
558-
# create an image calibration
559-
image_calibration = [
560-
physSizeX.value(),
561-
physSizeY.value(),
562-
z_interval,
563-
]
564-
calibration_unit = physSizeX.unit().getSymbol()
565-
image_dimensions_czt = [
566-
frame_size_c,
567-
frame_size_z,
568-
frame_size_t,
569-
]
530+
dimensions = 2 if frame_size_z == 1 else 3
531+
532+
# Retrieve physical size coordinates safely
533+
phys_size_x = getattr(ome_meta.getPixelsPhysicalSizeX(0), "value", lambda: 1.0)()
534+
phys_size_y = getattr(ome_meta.getPixelsPhysicalSizeY(0), "value", lambda: 1.0)()
535+
phys_size_z = getattr(ome_meta.getPixelsPhysicalSizeZ(0), "value", lambda: None)()
536+
537+
z_interval = phys_size_z if phys_size_z is not None else 1.0
538+
539+
# Handle missing Z calibration
540+
if phys_size_z is None and frame_size_z > 1:
541+
first_plane = getattr(ome_meta.getPlanePositionZ(0, 0), "value", lambda: 0)()
542+
next_plane_index = frame_size_c + frame_size_t - 1
543+
second_plane = getattr(ome_meta.getPlanePositionZ(0, next_plane_index), "value", lambda: 0)()
544+
z_interval = abs(first_plane - second_plane)
545+
546+
image_calibration = [phys_size_x, phys_size_y, z_interval]
547+
calibration_unit = (
548+
getattr(ome_meta.getPixelsPhysicalSizeX(0).unit(), "getSymbol", lambda: "unknown")()
549+
if phys_size_x
550+
else "unknown"
551+
)
552+
image_dimensions_czt = [frame_size_c, frame_size_z, frame_size_t]
570553

571554
reader.close()
572555

573556
for series in range(series_count):
574-
if omeMeta.getImageName(series) == "macro image":
557+
if ome_meta.getImageName(series) == "macro image":
575558
continue
576559

577560
if series_count > 1 and not str(image).endswith(".vsi"):
578-
series_names.append(omeMeta.getImageName(series))
561+
series_names.append(ome_meta.getImageName(series))
579562
else:
580563
series_names.append(str(image))
581-
# get the plane position in calibrated units
582-
current_position_x = omeMeta.getPlanePositionX(series, 0)
583-
current_position_y = omeMeta.getPlanePositionY(series, 0)
584-
current_position_z = omeMeta.getPlanePositionZ(series, 0)
585-
586-
physSizeX_max = (
587-
physSizeX.value()
588-
if physSizeX.value() >= omeMeta.getPixelsPhysicalSizeX(series).value()
589-
else omeMeta.getPixelsPhysicalSizeX(series).value()
590-
)
591-
physSizeY_max = (
592-
physSizeY.value()
593-
if physSizeY.value() >= omeMeta.getPixelsPhysicalSizeY(series).value()
594-
else omeMeta.getPixelsPhysicalSizeY(series).value()
595-
)
596-
if omeMeta.getPixelsPhysicalSizeZ(series):
597-
physSizeZ_max = (
598-
physSizeZ.value()
599-
if physSizeZ.value()
600-
>= omeMeta.getPixelsPhysicalSizeZ(series).value()
601-
else omeMeta.getPixelsPhysicalSizeZ(series).value()
602-
)
603-
604-
else:
605-
physSizeZ_max = 1.0
606564

607-
# get the absolute stage positions and store them
608-
pos_x = current_position_x.value()
609-
pos_y = current_position_y.value()
610-
611-
if current_position_z is None:
612-
log.debug("the z-position is missing in the ome-xml metadata.")
613-
pos_z = 1.0
614-
else:
615-
pos_z = current_position_z.value()
616-
617-
stage_coordinates_x.append(pos_x)
618-
stage_coordinates_y.append(pos_y)
619-
stage_coordinates_z.append(pos_z)
620-
621-
max_size = [physSizeX_max, physSizeY_max, physSizeZ_max]
622-
623-
# calculate the store the relative stage movements in px (for the grid/collection stitcher)
624-
relative_coordinates_x_px = []
625-
relative_coordinates_y_px = []
626-
relative_coordinates_z_px = []
627-
628-
for i in range(len(stage_coordinates_x)):
629-
rel_pos_x = (
630-
stage_coordinates_x[i] - stage_coordinates_x[0]
631-
) / physSizeX.value()
632-
rel_pos_y = (
633-
stage_coordinates_y[i] - stage_coordinates_y[0]
634-
) / physSizeY.value()
635-
rel_pos_z = (stage_coordinates_z[i] - stage_coordinates_z[0]) / z_interval
636-
637-
relative_coordinates_x_px.append(rel_pos_x)
638-
relative_coordinates_y_px.append(rel_pos_y)
639-
relative_coordinates_z_px.append(rel_pos_z)
640-
641-
return {
642-
"dimensions": dimensions,
643-
"stage_coordinates_x": stage_coordinates_x,
644-
"stage_coordinates_y": stage_coordinates_y,
645-
"stage_coordinates_z": stage_coordinates_z,
646-
"relative_coordinates_x": relative_coordinates_x_px,
647-
"relative_coordinates_y": relative_coordinates_y_px,
648-
"relative_coordinates_z": relative_coordinates_z_px,
649-
"image_calibration": image_calibration,
650-
"calibration_unit": calibration_unit,
651-
"image_dimensions_czt": image_dimensions_czt,
652-
"series_names": series_names,
653-
"max_size": max_size,
654-
}
565+
current_position_x = getattr(ome_meta.getPlanePositionX(series, 0), "value", lambda: 0)()
566+
current_position_y = getattr(ome_meta.getPlanePositionY(series, 0), "value", lambda: 0)()
567+
current_position_z = getattr(ome_meta.getPlanePositionZ(series, 0), "value", lambda: 1.0)()
568+
569+
max_phys_size_x = max(max_phys_size_x, ome_meta.getPixelsPhysicalSizeX(series).value())
570+
max_phys_size_y = max(max_phys_size_y, ome_meta.getPixelsPhysicalSizeY(series).value())
571+
max_phys_size_z = max(max_phys_size_z, ome_meta.getPixelsPhysicalSizeZ(series).value()
572+
if phys_size_z else z_interval)
573+
574+
stage_coordinates_x.append(current_position_x)
575+
stage_coordinates_y.append(current_position_y)
576+
stage_coordinates_z.append(current_position_z)
577+
578+
max_size = [max_phys_size_x, max_phys_size_y, max_phys_size_z]
579+
580+
relative_coordinates_x_px = [
581+
(stage_coordinates_x[i] - stage_coordinates_x[0]) / (phys_size_x or 1.0)
582+
for i in range(len(stage_coordinates_x))
583+
]
584+
relative_coordinates_y_px = [
585+
(stage_coordinates_y[i] - stage_coordinates_y[0]) / (phys_size_y or 1.0)
586+
for i in range(len(stage_coordinates_y))
587+
]
588+
relative_coordinates_z_px = [
589+
(stage_coordinates_z[i] - stage_coordinates_z[0]) / (z_interval or 1.0)
590+
for i in range(len(stage_coordinates_z))
591+
]
592+
593+
return StageMetadata(
594+
dimensions=dimensions,
595+
stage_coordinates_x=stage_coordinates_x,
596+
stage_coordinates_y=stage_coordinates_y,
597+
stage_coordinates_z=stage_coordinates_z,
598+
relative_coordinates_x=relative_coordinates_x_px,
599+
relative_coordinates_y=relative_coordinates_y_px,
600+
relative_coordinates_z=relative_coordinates_z_px,
601+
image_calibration=image_calibration,
602+
calibration_unit=calibration_unit,
603+
image_dimensions_czt=image_dimensions_czt,
604+
series_names=series_names,
605+
max_size=max_size,
606+
)

0 commit comments

Comments
 (0)