88from omero .model import Screen
99from omero .model import Dataset
1010from omero .model import Project
11+ import re
1112
1213
13- def get_path (conn : BlitzGateway , image_id : int ) -> str :
14+ # Regex to match well positions (eg. A1)
15+ WELL_POS_RE = re .compile (r"(?P<row>\D+)(?P<col>\d+)" )
16+
17+
18+ def _get_path (conn : BlitzGateway , image_id : int ) -> str :
19+ """
20+ Retrieve the (first) original file path for a given OMERO image.
21+
22+ Args:
23+ conn (BlitzGateway): Active OMERO gateway connection
24+ image_id (int): ID of the OMERO image
25+
26+ Returns:
27+ str: path of the image file
28+
29+ Raises:
30+ Exception: If the query fails or the path cannot be retrieved
31+ """
1432 params = ParametersI ()
1533 params .addId (image_id )
1634 query = """
@@ -25,24 +43,49 @@ def get_path(conn: BlitzGateway, image_id: int) -> str:
2543 return res
2644
2745
28- def set_external_info (img : ImageI , path : str ) -> ImageI :
29- info = ExternalInfoI ()
30- info .entityType = rstring ("com.glencoesoftware.ngff:multiscales" )
31- info .entityId = rlong (3 )
32- info .lsid = rstring (path )
33- img .details .externalInfo = info
34- return img
46+ def _lookup (conn : BlitzGateway , type : str , oid : int ) -> BlitzObjectWrapper :
47+ """
48+ Look up an OMERO object by its type and ID.
3549
50+ Args:
51+ conn (BlitzGateway): Active OMERO gateway connection
52+ type (str): Type of OMERO object (e.g., "Screen", "Plate", "Image")
53+ oid (int): Object ID to look up
3654
37- def _lookup (conn : BlitzGateway , type : str , oid : int ) -> BlitzObjectWrapper :
55+ Returns:
56+ BlitzObjectWrapper: Wrapped OMERO object
57+
58+ Raises:
59+ ValueError: If the object doesn't exist
60+ """
3861 conn .SERVICE_OPTS .setOmeroGroup ("-1" )
3962 obj = conn .getObject (type , oid )
4063 if not obj :
4164 raise ValueError (f"No such { type } : { oid } " )
4265 return obj
4366
4467
45- def get_images (conn : BlitzGateway , object ):
68+ def get_images (conn : BlitzGateway , object ) -> tuple [BlitzObjectWrapper , str | None , int | None ]:
69+ """
70+ Generator that yields images from any OMERO container object.
71+
72+ Recursively traverses OMERO container hierarchies (Screen/Plate/Project/Dataset)
73+ to find all contained images.
74+
75+ Args:
76+ conn (BlitzGateway): Active OMERO gateway connection
77+ object: OMERO container object (Screen, Plate, Project, Dataset, Image)
78+ or a list of such objects
79+
80+ Yields:
81+ tuple: Contains:
82+ - BlitzObjectWrapper: Image object
83+ - str | None: Well position (eg. A1) if from plate, None otherwise
84+ - int | None: Well sample index if from plate, None otherwise
85+
86+ Raises:
87+ ValueError: If given an unsupported object type
88+ """
4689 if isinstance (object , list ):
4790 for x in object :
4891 yield from get_images (conn , x )
@@ -55,17 +98,73 @@ def get_images(conn: BlitzGateway, object):
5598 for well in plt .listChildren ():
5699 for idx in range (0 , well .countWellSample ()):
57100 img = well .getImage (idx )
58- yield img
101+ yield img , well . getWellPos (), idx
59102 elif isinstance (object , Project ):
60103 prj = _lookup (conn , "Project" , object .id )
61104 for ds in prj .listChildren ():
62105 yield from get_images (conn , ds ._obj )
63106 elif isinstance (object , Dataset ):
64107 ds = _lookup (conn , "Dataset" , object .id )
65108 for img in ds .listChildren ():
66- yield img
109+ yield img , None , None
67110 elif isinstance (object , Image ):
68111 img = _lookup (conn , "Image" , object .id )
69- yield img
112+ yield img , None , None
70113 else :
71114 raise ValueError (f"Unsupported type: { object .__class__ .__name__ } " )
115+
116+
117+ def set_external_info (conn : BlitzGateway , img : ImageI , well : str , idx : int ) -> ImageI :
118+ """
119+ Set external info for an image to enable omero zarr pixel buffer handling.
120+
121+ This function configures an image for use with the omero-zarr-pixel-buffer by:
122+ 1. Retrieving the original file path
123+ 2. Converting it to point to the 5d multiscale image directory
124+ 3. Setting up the external info with the path and metadata
125+
126+ For plate-based images (with wells), the path structure follows:
127+ /<base_path>/<row>/<column>/<field index>
128+
129+ For regular images:
130+ /<base_path>/0
131+
132+ Args:
133+ conn (BlitzGateway): Active OMERO gateway connection
134+ img (ImageI): OMERO image object to modify
135+ well (str): Well position (e.g., 'A1', 'B2') for plate-based images, or None
136+ idx (int): Well sample / field index for plate-based images, or None
137+
138+ Returns:
139+ ImageI: Modified image object with updated external info
140+
141+ Raises:
142+ ValueError: If the image path is not an OME-Zarr format or if well position is invalid
143+
144+ Note:
145+ The external info is configured with entity type 'com.glencoesoftware.ngff:multiscales'
146+ and entity ID 3, which are required by the omero-zarr-pixel-buffer.
147+ """
148+ path = _get_path (conn , img .id )
149+ if path .endswith ("OME/METADATA.ome.xml" ):
150+ if well :
151+ match = WELL_POS_RE .match (well )
152+ if match :
153+ col = match .group ("col" )
154+ row = match .group ("row" )
155+ path = path .replace ("OME/METADATA.ome.xml" , f"{ row } " )
156+ path = f"/{ path } /{ col } /{ idx } "
157+ else :
158+ raise ValueError (f"Couldn't parse well position: { well } " )
159+ else :
160+ path = path .replace ("OME/METADATA.ome.xml" , "0" )
161+ path = f"/{ path } "
162+ else :
163+ raise ValueError (f"Doesn't seem to be an ome.zarr: { path } " )
164+
165+ info = ExternalInfoI ()
166+ info .entityType = rstring ("com.glencoesoftware.ngff:multiscales" )
167+ info .entityId = rlong (3 )
168+ info .lsid = rstring (path )
169+ img .details .externalInfo = info
170+ return img
0 commit comments