Skip to content

Commit fefde86

Browse files
committed
Reapply GS-specific modifications
1 parent 5d96dc5 commit fefde86

File tree

13 files changed

+452
-16
lines changed

13 files changed

+452
-16
lines changed

cellprofiler_core/analysis/_runner.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -672,7 +672,8 @@ def start_workers(cls, num=None):
672672
# closed, the subprocess exits.
673673
if hasattr(sys, "frozen"):
674674
if sys.platform == "darwin":
675-
executable = os.path.join(os.path.dirname(sys.executable), "cp")
675+
executable = os.path.join(os.path.dirname(sys.executable),
676+
"cellprofilerapp")
676677
args = [executable] + aw_args
677678
elif sys.platform.startswith("linux"):
678679
aw_path = os.path.join(os.path.dirname(__file__), "__init__.py")

cellprofiler_core/constants/image.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,4 +103,4 @@
103103
SUB_ALL = "All"
104104
SUB_SOME = "Some"
105105
FILE_SCHEME = "file:"
106-
PASSTHROUGH_SCHEMES = ("http", "https", "ftp", "omero", "s3")
106+
PASSTHROUGH_SCHEMES = ("http", "https", "ftp", "omero", "s3", "omero-3d")

cellprofiler_core/image/abstract_image/file/_file_image.py

Lines changed: 78 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,23 @@
99
import numpy
1010
import skimage.io
1111

12+
import requests
13+
from PIL import Image as PilImage
14+
from io import BytesIO
15+
from posixpath import join as urljoin
16+
1217
import cellprofiler_core.preferences
1318
from .._abstract_image import AbstractImage
1419
from ..._image import Image
1520
from ....utilities.image import is_numpy_file
1621
from ....utilities.image import is_matlab_file
22+
from ....utilities.image import is_omero3d_path
1723
from ....utilities.image import loadmat
1824
from ....utilities.image import load_data_file
1925
from ....utilities.image import generate_presigned_url
2026
from ....constants.image import FILE_SCHEME, PASSTHROUGH_SCHEMES
2127
from ....utilities.pathname import pathname2url, url2pathname
28+
from ....utilities.zarr import get_zarr_reader
2229

2330

2431
class FileImage(AbstractImage):
@@ -35,6 +42,8 @@ def __init__(
3542
channel=None,
3643
volume=False,
3744
spacing=None,
45+
z=None,
46+
t=None,
3847
):
3948
"""
4049
:param name: Name of image to be provided
@@ -84,6 +93,8 @@ def __init__(
8493
self.__index = index
8594
self.__volume = volume
8695
self.__spacing = spacing
96+
self.z_index = z if z is not None else 0
97+
self.t_index = t if t is not None else 0
8798
self.scale = None
8899

89100
@property
@@ -176,6 +187,8 @@ def cache_file(self):
176187
)
177188
finally:
178189
os.close(tempfd)
190+
elif url.lower().endswith('.zarr'):
191+
self.__cached_file = url
179192
else:
180193
from bioformats.formatreader import get_image_reader
181194

@@ -185,6 +198,8 @@ def cache_file(self):
185198
return True
186199

187200
def get_full_name(self):
201+
if is_omero3d_path(self.__url):
202+
return self.get_url()
188203
self.cache_file()
189204
if self.__is_cached:
190205
return self.__cached_file
@@ -203,8 +218,12 @@ def get_md5_hash(self, measurements):
203218
#
204219
# Cache the MD5 hash on the image reader
205220
#
206-
if is_matlab_file(self.__filename) or is_numpy_file(self.__filename):
221+
if (is_matlab_file(self.__filename) or
222+
is_numpy_file(self.__filename) or
223+
is_omero3d_path(self.get_url())):
207224
rdr = None
225+
elif self.get_url().endswith('.zarr'):
226+
rdr = get_zarr_reader(None, url=self.get_url())
208227
else:
209228
from bioformats.formatreader import get_image_reader
210229

@@ -273,6 +292,8 @@ def __set_image(self):
273292
url = self.get_url()
274293
if url.lower().startswith("omero:"):
275294
rdr = get_image_reader(self.get_name(), url=url)
295+
elif url.lower().endswith('.zarr'):
296+
rdr = get_zarr_reader(self.get_name(), url=url)
276297
else:
277298
rdr = get_image_reader(self.get_name(), url=self.get_url())
278299
if numpy.isscalar(self.index) or self.index is None:
@@ -283,6 +304,8 @@ def __set_image(self):
283304
rescale=self.rescale if isinstance(self.rescale, bool) else False,
284305
wants_max_intensity=True,
285306
channel_names=channel_names,
307+
z=self.z_index,
308+
t=self.t_index,
286309
)
287310
else:
288311
# It's a stack
@@ -305,6 +328,8 @@ def __set_image(self):
305328
rescale=self.rescale if isinstance(self.rescale, bool) else False,
306329
wants_max_intensity=True,
307330
channel_names=channel_names,
331+
z=self.z_index,
332+
t=self.t_index,
308333
)
309334
stack.append(img)
310335
img = numpy.dstack(stack)
@@ -330,10 +355,61 @@ def provide_image(self, image_set):
330355

331356
def __set_image_volume(self):
332357
pathname = url2pathname(self.get_url())
333-
358+
print("Using pathname: {} for url {}".format(pathname, self.get_url()))
334359
# Volume loading is currently limited to tiffs/numpy files only
335360
if is_numpy_file(self.__filename):
336361
data = numpy.load(pathname)
362+
elif is_omero3d_path(self.__url):
363+
scheme = 'omero-3d:'
364+
url = self.__url.split(scheme)[1]
365+
parsed_url = urllib.parse.urlparse(url)
366+
query_params = urllib.parse.parse_qs(parsed_url.query)
367+
zmin = int(query_params['zmin'][0])
368+
zmax = int(query_params['zmax'][0])
369+
width = int(query_params['width'][0])
370+
height = int(query_params['height'][0])
371+
image_id = query_params['imageid'][0]
372+
channel = query_params['c'][0]
373+
stack = numpy.ndarray((zmax - zmin + 1, height, width))
374+
for i in range(zmin, zmax + 1):
375+
path = urljoin('/tile', image_id, str(i), channel, '0')
376+
url = urllib.parse.urlunparse((
377+
parsed_url.scheme,
378+
parsed_url.netloc,
379+
path,
380+
'',
381+
parsed_url.query,
382+
''
383+
))
384+
print("Requesting URL: {}".format(url))
385+
timeout = 2
386+
response = None
387+
while timeout < 500:
388+
try:
389+
response = requests.get(url, timeout=timeout)
390+
except Exception:
391+
print('Get %s with timeout %s sec failed' % (
392+
url, timeout))
393+
timeout = timeout**2
394+
else:
395+
break
396+
if response is None:
397+
raise Exception('Failed to retrieve data from URL')
398+
image_bytes = BytesIO(response.content)
399+
image = PilImage.open(image_bytes)
400+
stack[i - zmin, :, :] = image
401+
data = stack
402+
elif pathname.endswith('.zarr'):
403+
rdr = get_zarr_reader(self.get_name(), url=self.get_url())
404+
data = rdr.read(
405+
c=self.channel,
406+
series=self.series,
407+
index=None,
408+
rescale=False,
409+
wants_max_intensity=False,
410+
z=None,
411+
t=self.t_index,
412+
)
337413
else:
338414
data = imageio.volread(pathname)
339415

cellprofiler_core/image/abstract_image/file/url/_color_image.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ class ColorImage(URLImage):
77
"""Provide a color image, tripling a monochrome plane if needed"""
88

99
def __init__(
10-
self, name, url, series, index, rescale=True, volume=False, spacing=None
10+
self, name, url, series, index, rescale=True, volume=False, spacing=None, z=None, t=None,
1111
):
1212
URLImage.__init__(
1313
self,
@@ -18,6 +18,8 @@ def __init__(
1818
index=index,
1919
volume=volume,
2020
spacing=spacing,
21+
z=z,
22+
t=t,
2123
)
2224

2325
def provide_image(self, image_set):

cellprofiler_core/image/abstract_image/file/url/_mask_image.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
class MaskImage(MonochromeImage):
55
"""Provide a boolean image, converting nonzero to True, zero to False if needed"""
66

7-
def __init__(self, name, url, series, index, channel, volume=False, spacing=None):
7+
def __init__(self, name, url, series, index, channel, volume=False, spacing=None, z=None, t=None):
88
MonochromeImage.__init__(
99
self,
1010
name,
@@ -15,6 +15,8 @@ def __init__(self, name, url, series, index, channel, volume=False, spacing=None
1515
channel=channel,
1616
volume=volume,
1717
spacing=spacing,
18+
z=z,
19+
t=t,
1820
)
1921

2022
def provide_image(self, image_set):

cellprofiler_core/image/abstract_image/file/url/_monochrome_image.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ def __init__(
1616
rescale=True,
1717
volume=False,
1818
spacing=None,
19+
z=None,
20+
t=None,
1921
):
2022
URLImage.__init__(
2123
self,
@@ -27,6 +29,8 @@ def __init__(
2729
channel=channel,
2830
volume=volume,
2931
spacing=spacing,
32+
z=z,
33+
t=t,
3034
)
3135

3236
def provide_image(self, image_set):

cellprofiler_core/image/abstract_image/file/url/_url_image.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import os
22
from .....utilities.pathname import url2pathname
33

4+
from .....utilities.image import is_omero3d_path
5+
46
from .._file_image import FileImage
57

68

@@ -17,6 +19,8 @@ def __init__(
1719
channel=None,
1820
volume=False,
1921
spacing=None,
22+
z=None,
23+
t=None,
2024
):
2125
if url.lower().startswith("file:"):
2226
path = url2pathname(url)
@@ -25,11 +29,17 @@ def __init__(
2529
pathname = ""
2630
filename = url
2731
super(URLImage, self).__init__(
28-
name, pathname, filename, rescale, series, index, channel, volume, spacing
32+
name, pathname, filename, rescale, series, index, channel, volume, spacing, z=z, t=t,
2933
)
3034
self.url = url
3135

3236
def get_url(self):
37+
if is_omero3d_path(self.url):
38+
print("OMERO-3D URL: {}".format(self.url))
39+
url = self.url.split("omero-3d:")[1]
40+
if url is not None:
41+
return url
42+
return self.url
3343
if self.cache_file():
3444
return super(URLImage, self).get_url()
3545
return self.url

cellprofiler_core/modules/loaddata.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1060,6 +1060,33 @@ def fetch_provider(self, name, measurements, is_image_name=True):
10601060
frame = measurements["Image", frame_feature]
10611061
else:
10621062
frame = None
1063+
if url.endswith('.zarr'):
1064+
# Zarrs need czt indexing rather than just index.
1065+
c, z, t = None, None, None
1066+
1067+
if measurements.has_feature("Image", f"Channel_{name}"):
1068+
c = measurements["Image", f"Channel_{name}"]
1069+
elif measurements.has_feature("Image", "Metadata_C"):
1070+
c = measurements["Image", "Metadata_C"]
1071+
if measurements.has_feature("Image", f"Z_{name}"):
1072+
z = measurements["Image", f"Z_{name}"]
1073+
elif measurements.has_feature("Image", "Metadata_Z"):
1074+
z = measurements["Image", "Metadata_Z"]
1075+
if measurements.has_feature("Image", f"T_{name}"):
1076+
t = measurements["Image", f"T_{name}"]
1077+
elif measurements.has_feature("Image", "Metadata_T"):
1078+
t = measurements["Image", "Metadata_T"]
1079+
return FileImage(
1080+
name,
1081+
path,
1082+
filename,
1083+
rescale=self.rescale.value and is_image_name,
1084+
series=series,
1085+
index=frame,
1086+
z=z,
1087+
channel=c,
1088+
t=t,
1089+
)
10631090
return FileImage(
10641091
name,
10651092
path,

cellprofiler_core/modules/metadata.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1133,6 +1133,7 @@ def msg(url):
11331133
from bioformats.formatreader import get_omexml_metadata
11341134
from typing import Optional, Any, Callable
11351135
from dataclasses import dataclass
1136+
from cellprofiler_core.utilities.zarr import get_zarr_metadata
11361137

11371138
@dataclass
11381139
class ui_context:
@@ -1173,6 +1174,7 @@ def update_all_urls():
11731174
for i, url in enumerate(urls):
11741175
try:
11751176
if not pbar_context.update_callback(pbar_context.dlg, i, url):
1177+
11761178
break
11771179
if group.filter_choice == F_FILTERED_IMAGES:
11781180
match = group.filter.evaluate(
@@ -1186,7 +1188,10 @@ def update_all_urls():
11861188
continue
11871189
metadata = filelist.get_metadata(url)
11881190
if metadata is None:
1189-
metadata = get_omexml_metadata(url=url)
1191+
if url.lower().endswith('.zarr'):
1192+
metadata = get_zarr_metadata(url=url)
1193+
else:
1194+
metadata = get_omexml_metadata(url=url)
11901195
filelist.add_metadata(url, metadata)
11911196
except Exception as e:
11921197
import logging
@@ -1199,7 +1204,6 @@ def update_all_urls():
11991204
pbar_context.err_callback(errmsg)
12001205

12011206
update_all_urls()
1202-
12031207
group.metadata_autoextracted.value = True
12041208

12051209
def on_activated(self, workspace):

0 commit comments

Comments
 (0)