napari-tmidas 0.2.1__py3-none-any.whl → 0.2.4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- napari_tmidas/__init__.py +35 -5
- napari_tmidas/_crop_anything.py +1458 -499
- napari_tmidas/_env_manager.py +76 -0
- napari_tmidas/_file_conversion.py +1646 -1131
- napari_tmidas/_file_selector.py +1464 -223
- napari_tmidas/_label_inspection.py +83 -8
- napari_tmidas/_processing_worker.py +309 -0
- napari_tmidas/_reader.py +6 -10
- napari_tmidas/_registry.py +15 -14
- napari_tmidas/_roi_colocalization.py +1221 -84
- napari_tmidas/_tests/test_crop_anything.py +123 -0
- napari_tmidas/_tests/test_env_manager.py +89 -0
- napari_tmidas/_tests/test_file_selector.py +90 -0
- napari_tmidas/_tests/test_grid_view_overlay.py +193 -0
- napari_tmidas/_tests/test_init.py +98 -0
- napari_tmidas/_tests/test_intensity_label_filter.py +222 -0
- napari_tmidas/_tests/test_label_inspection.py +86 -0
- napari_tmidas/_tests/test_processing_basic.py +500 -0
- napari_tmidas/_tests/test_processing_worker.py +142 -0
- napari_tmidas/_tests/test_regionprops_analysis.py +547 -0
- napari_tmidas/_tests/test_registry.py +135 -0
- napari_tmidas/_tests/test_scipy_filters.py +168 -0
- napari_tmidas/_tests/test_skimage_filters.py +259 -0
- napari_tmidas/_tests/test_split_channels.py +217 -0
- napari_tmidas/_tests/test_spotiflow.py +87 -0
- napari_tmidas/_tests/test_tyx_display_fix.py +142 -0
- napari_tmidas/_tests/test_ui_utils.py +68 -0
- napari_tmidas/_tests/test_widget.py +30 -0
- napari_tmidas/_tests/test_windows_basic.py +66 -0
- napari_tmidas/_ui_utils.py +57 -0
- napari_tmidas/_version.py +16 -3
- napari_tmidas/_widget.py +41 -4
- napari_tmidas/processing_functions/basic.py +557 -20
- napari_tmidas/processing_functions/careamics_env_manager.py +72 -99
- napari_tmidas/processing_functions/cellpose_env_manager.py +415 -112
- napari_tmidas/processing_functions/cellpose_segmentation.py +132 -191
- napari_tmidas/processing_functions/colocalization.py +513 -56
- napari_tmidas/processing_functions/grid_view_overlay.py +703 -0
- napari_tmidas/processing_functions/intensity_label_filter.py +422 -0
- napari_tmidas/processing_functions/regionprops_analysis.py +1280 -0
- napari_tmidas/processing_functions/sam2_env_manager.py +53 -69
- napari_tmidas/processing_functions/sam2_mp4.py +274 -195
- napari_tmidas/processing_functions/scipy_filters.py +403 -8
- napari_tmidas/processing_functions/skimage_filters.py +424 -212
- napari_tmidas/processing_functions/spotiflow_detection.py +949 -0
- napari_tmidas/processing_functions/spotiflow_env_manager.py +591 -0
- napari_tmidas/processing_functions/timepoint_merger.py +334 -86
- napari_tmidas/processing_functions/trackastra_tracking.py +24 -5
- {napari_tmidas-0.2.1.dist-info → napari_tmidas-0.2.4.dist-info}/METADATA +92 -39
- napari_tmidas-0.2.4.dist-info/RECORD +63 -0
- napari_tmidas/_tests/__init__.py +0 -0
- napari_tmidas-0.2.1.dist-info/RECORD +0 -38
- {napari_tmidas-0.2.1.dist-info → napari_tmidas-0.2.4.dist-info}/WHEEL +0 -0
- {napari_tmidas-0.2.1.dist-info → napari_tmidas-0.2.4.dist-info}/entry_points.txt +0 -0
- {napari_tmidas-0.2.1.dist-info → napari_tmidas-0.2.4.dist-info}/licenses/LICENSE +0 -0
- {napari_tmidas-0.2.1.dist-info → napari_tmidas-0.2.4.dist-info}/top_level.txt +0 -0
|
@@ -11,6 +11,7 @@ for cellular segmentation without requiring diameter parameter.
|
|
|
11
11
|
|
|
12
12
|
Note: This requires the cellpose library to be installed.
|
|
13
13
|
"""
|
|
14
|
+
from typing import Union
|
|
14
15
|
|
|
15
16
|
import numpy as np
|
|
16
17
|
|
|
@@ -23,16 +24,15 @@ from napari_tmidas.processing_functions.cellpose_env_manager import (
|
|
|
23
24
|
|
|
24
25
|
# Check if cellpose is directly available in this environment
|
|
25
26
|
try:
|
|
26
|
-
|
|
27
|
+
import cellpose # noqa: F401
|
|
27
28
|
|
|
28
29
|
CELLPOSE_AVAILABLE = True
|
|
29
|
-
USE_GPU
|
|
30
|
-
|
|
30
|
+
# Don't evaluate USE_GPU here - it should be evaluated in the cellpose environment
|
|
31
|
+
|
|
31
32
|
print("Cellpose found in current environment. Using native import.")
|
|
32
33
|
except ImportError:
|
|
33
34
|
CELLPOSE_AVAILABLE = False
|
|
34
|
-
|
|
35
|
-
USE_DEDICATED_ENV = True
|
|
35
|
+
|
|
36
36
|
print(
|
|
37
37
|
"Cellpose not found in current environment. Will use dedicated environment."
|
|
38
38
|
)
|
|
@@ -88,102 +88,6 @@ def transpose_dimensions(img, dim_order):
|
|
|
88
88
|
return img_transposed, new_dim_order, is_3d
|
|
89
89
|
|
|
90
90
|
|
|
91
|
-
def run_cellpose(
|
|
92
|
-
img,
|
|
93
|
-
model,
|
|
94
|
-
channels,
|
|
95
|
-
flow_threshold=0.4,
|
|
96
|
-
cellprob_threshold=0.0,
|
|
97
|
-
dim_order="ZYX",
|
|
98
|
-
max_pixels=4000000,
|
|
99
|
-
tile_norm_blocksize=128,
|
|
100
|
-
batch_size=32,
|
|
101
|
-
):
|
|
102
|
-
"""
|
|
103
|
-
Run Cellpose segmentation on an image using Cellpose 4 (Cellpose-SAM).
|
|
104
|
-
|
|
105
|
-
Parameters:
|
|
106
|
-
-----------
|
|
107
|
-
img : numpy.ndarray
|
|
108
|
-
Input image
|
|
109
|
-
model : cellpose.models.Cellpose
|
|
110
|
-
Cellpose model to use
|
|
111
|
-
channels : list
|
|
112
|
-
Channels to use for segmentation [0,0] = grayscale, [1,0] = green channel, [2,0] = red channel
|
|
113
|
-
flow_threshold : float
|
|
114
|
-
Flow threshold for Cellpose
|
|
115
|
-
cellprob_threshold : float
|
|
116
|
-
Cell probability threshold
|
|
117
|
-
dim_order : str
|
|
118
|
-
Dimension order of the input image
|
|
119
|
-
max_pixels : int
|
|
120
|
-
Maximum number of pixels to process (for 2D images)
|
|
121
|
-
tile_norm_blocksize : int
|
|
122
|
-
Block size for tile normalization (new parameter in Cellpose 4)
|
|
123
|
-
batch_size : int
|
|
124
|
-
Batch size for processing multiple images or 3D slices at once
|
|
125
|
-
|
|
126
|
-
Returns:
|
|
127
|
-
--------
|
|
128
|
-
numpy.ndarray
|
|
129
|
-
Segmented image with labels
|
|
130
|
-
"""
|
|
131
|
-
# First check if the image is too large (for 2D images)
|
|
132
|
-
if len(img.shape) == 2 or (len(img.shape) == 3 and "C" in dim_order):
|
|
133
|
-
# For 2D images (potentially with channels)
|
|
134
|
-
height, width = img.shape[:2]
|
|
135
|
-
total_pixels = height * width
|
|
136
|
-
if total_pixels > max_pixels:
|
|
137
|
-
raise ValueError(
|
|
138
|
-
f"Image size ({height}x{width}={total_pixels} pixels) exceeds the "
|
|
139
|
-
f"maximum size of {max_pixels} pixels. Consider downsampling."
|
|
140
|
-
)
|
|
141
|
-
|
|
142
|
-
# Transpose to expected dimension order
|
|
143
|
-
img_transposed, new_dim_order, is_3d = transpose_dimensions(img, dim_order)
|
|
144
|
-
|
|
145
|
-
# Check if we have a time series
|
|
146
|
-
has_time = "T" in new_dim_order
|
|
147
|
-
|
|
148
|
-
# Set up normalization with tile_norm_blocksize (Cellpose 4 parameter)
|
|
149
|
-
normalize = {"tile_norm_blocksize": tile_norm_blocksize}
|
|
150
|
-
|
|
151
|
-
if has_time:
|
|
152
|
-
# Handle time series - process each time point
|
|
153
|
-
n_timepoints = img_transposed.shape[0]
|
|
154
|
-
result = np.zeros(img_transposed.shape, dtype=np.uint32)
|
|
155
|
-
|
|
156
|
-
# Process each time point
|
|
157
|
-
for t in range(n_timepoints):
|
|
158
|
-
img_t = img_transposed[t]
|
|
159
|
-
masks, _, _ = model.eval(
|
|
160
|
-
img_t,
|
|
161
|
-
channels=channels,
|
|
162
|
-
flow_threshold=flow_threshold,
|
|
163
|
-
cellprob_threshold=cellprob_threshold,
|
|
164
|
-
normalize=normalize,
|
|
165
|
-
z_axis=0 if is_3d else None,
|
|
166
|
-
do_3D=is_3d,
|
|
167
|
-
batch_size=batch_size,
|
|
168
|
-
)
|
|
169
|
-
result[t] = masks
|
|
170
|
-
else:
|
|
171
|
-
# Process single time point
|
|
172
|
-
masks, _, _ = model.eval(
|
|
173
|
-
img_transposed,
|
|
174
|
-
channels=channels,
|
|
175
|
-
flow_threshold=flow_threshold,
|
|
176
|
-
cellprob_threshold=cellprob_threshold,
|
|
177
|
-
normalize=normalize,
|
|
178
|
-
z_axis=0 if is_3d else None,
|
|
179
|
-
do_3D=is_3d,
|
|
180
|
-
batch_size=batch_size,
|
|
181
|
-
)
|
|
182
|
-
result = masks
|
|
183
|
-
|
|
184
|
-
return result.astype(np.uint32)
|
|
185
|
-
|
|
186
|
-
|
|
187
91
|
@BatchProcessingRegistry.register(
|
|
188
92
|
name="Cellpose-SAM Segmentation",
|
|
189
93
|
suffix="_labels",
|
|
@@ -208,19 +112,40 @@ def run_cellpose(
|
|
|
208
112
|
# "max": 3,
|
|
209
113
|
# "description": "Second channel: 0=none, 1=green, 2=red, 3=blue",
|
|
210
114
|
# },
|
|
115
|
+
"diameter": {
|
|
116
|
+
"type": float,
|
|
117
|
+
"default": 0.0,
|
|
118
|
+
"min": 0.0,
|
|
119
|
+
"max": 200.0,
|
|
120
|
+
"description": "Optional. Only required if your ROI diameter is outside the range 7.5–120. Set to 0 to leave unset (recommended for most users). Cellpose-SAM is trained for diameters in this range.",
|
|
121
|
+
},
|
|
211
122
|
"flow_threshold": {
|
|
212
123
|
"type": float,
|
|
213
124
|
"default": 0.4,
|
|
214
125
|
"min": 0.1,
|
|
215
126
|
"max": 0.9,
|
|
216
|
-
"description": "Flow threshold
|
|
127
|
+
"description": "Flow threshold (cell detection sensitivity)",
|
|
217
128
|
},
|
|
218
129
|
"cellprob_threshold": {
|
|
219
130
|
"type": float,
|
|
220
131
|
"default": 0.0,
|
|
221
132
|
"min": -6.0,
|
|
222
133
|
"max": 6.0,
|
|
223
|
-
"description": "Cell probability threshold (
|
|
134
|
+
"description": "Cell probability threshold (increase to reduce splits)",
|
|
135
|
+
},
|
|
136
|
+
"anisotropy": {
|
|
137
|
+
"type": float,
|
|
138
|
+
"default": 1.0,
|
|
139
|
+
"min": 0.1,
|
|
140
|
+
"max": 10.0,
|
|
141
|
+
"description": "Optional rescaling factor (3D; Z step[um] / X pixel res [um])",
|
|
142
|
+
},
|
|
143
|
+
"flow3D_smooth": {
|
|
144
|
+
"type": int,
|
|
145
|
+
"default": 0,
|
|
146
|
+
"min": 0,
|
|
147
|
+
"max": 10,
|
|
148
|
+
"description": "Smooth flow with gaussian filter (stdev)",
|
|
224
149
|
},
|
|
225
150
|
"tile_norm_blocksize": {
|
|
226
151
|
"type": int,
|
|
@@ -236,11 +161,6 @@ def run_cellpose(
|
|
|
236
161
|
"max": 128,
|
|
237
162
|
"description": "Batch size for processing multiple images/slices at once",
|
|
238
163
|
},
|
|
239
|
-
"force_dedicated_env": {
|
|
240
|
-
"type": bool,
|
|
241
|
-
"default": False,
|
|
242
|
-
"description": "Force using dedicated environment even if Cellpose is available",
|
|
243
|
-
},
|
|
244
164
|
},
|
|
245
165
|
)
|
|
246
166
|
def cellpose_segmentation(
|
|
@@ -250,9 +170,12 @@ def cellpose_segmentation(
|
|
|
250
170
|
channel_2: int = 0,
|
|
251
171
|
flow_threshold: float = 0.4,
|
|
252
172
|
cellprob_threshold: float = 0.0,
|
|
173
|
+
anisotropy: Union[float, None] = None,
|
|
174
|
+
flow3D_smooth: int = 0,
|
|
253
175
|
tile_norm_blocksize: int = 128,
|
|
254
176
|
batch_size: int = 32,
|
|
255
|
-
|
|
177
|
+
diameter: float = 0.0,
|
|
178
|
+
_source_filepath: str = None, # Hidden parameter for zarr optimization
|
|
256
179
|
) -> np.ndarray:
|
|
257
180
|
"""
|
|
258
181
|
Run Cellpose 4 (Cellpose-SAM) segmentation on an image.
|
|
@@ -282,110 +205,128 @@ def cellpose_segmentation(
|
|
|
282
205
|
Block size for tile normalization (Cellpose 4 parameter) (default: 128)
|
|
283
206
|
batch_size : int
|
|
284
207
|
Batch size for processing multiple images/slices at once (default: 32)
|
|
285
|
-
force_dedicated_env : bool
|
|
286
|
-
Force using dedicated environment even if Cellpose is available (default: False)
|
|
287
208
|
|
|
288
209
|
Returns:
|
|
289
210
|
--------
|
|
290
211
|
numpy.ndarray
|
|
291
212
|
Segmented image with instance labels
|
|
292
213
|
"""
|
|
214
|
+
# Diameter parameter guidance:
|
|
215
|
+
# Cellpose-SAM is trained for ROI diameters 7.5–120. Only set diameter if your images have objects outside this range (e.g., diameter <7.5 or >120). Otherwise, leave as None.
|
|
216
|
+
# Cellpose 4 handles normalization internally via percentile-based normalization
|
|
217
|
+
# It accepts uint8, uint16, float32, float64 - no pre-conversion needed!
|
|
218
|
+
# The normalize=True parameter (default) will convert to float and normalize
|
|
219
|
+
# to 1st-99th percentile range internally
|
|
220
|
+
|
|
221
|
+
# Handle TZYX data by processing each timepoint separately
|
|
222
|
+
if "T" in dim_order and image.ndim == 4:
|
|
223
|
+
print(
|
|
224
|
+
f"Detected TZYX data with shape {image.shape}. Processing each timepoint separately..."
|
|
225
|
+
)
|
|
226
|
+
t_axis = dim_order.index("T")
|
|
227
|
+
num_timepoints = image.shape[t_axis]
|
|
228
|
+
|
|
229
|
+
# Move T axis to front if not already there
|
|
230
|
+
if t_axis != 0:
|
|
231
|
+
axes_order = list(range(image.ndim))
|
|
232
|
+
axes_order.insert(0, axes_order.pop(t_axis))
|
|
233
|
+
image = np.transpose(image, axes_order)
|
|
234
|
+
|
|
235
|
+
# Process each timepoint
|
|
236
|
+
results = []
|
|
237
|
+
for t in range(num_timepoints):
|
|
238
|
+
print(f"Processing timepoint {t+1}/{num_timepoints}...")
|
|
239
|
+
timepoint_image = image[t]
|
|
240
|
+
# Remove 'T' from dim_order for single timepoint
|
|
241
|
+
timepoint_dim_order = dim_order.replace("T", "")
|
|
242
|
+
|
|
243
|
+
# Recursively call this function for the single timepoint
|
|
244
|
+
timepoint_result = cellpose_segmentation(
|
|
245
|
+
timepoint_image,
|
|
246
|
+
dim_order=timepoint_dim_order,
|
|
247
|
+
channel_1=channel_1,
|
|
248
|
+
channel_2=channel_2,
|
|
249
|
+
flow_threshold=flow_threshold,
|
|
250
|
+
cellprob_threshold=cellprob_threshold,
|
|
251
|
+
anisotropy=anisotropy,
|
|
252
|
+
flow3D_smooth=flow3D_smooth,
|
|
253
|
+
tile_norm_blocksize=tile_norm_blocksize,
|
|
254
|
+
batch_size=batch_size,
|
|
255
|
+
_source_filepath=None, # Don't use zarr optimization for timepoints
|
|
256
|
+
)
|
|
257
|
+
results.append(timepoint_result)
|
|
258
|
+
|
|
259
|
+
# Stack results back together
|
|
260
|
+
result = np.stack(results, axis=0)
|
|
261
|
+
print(f"Completed processing all {num_timepoints} timepoints.")
|
|
262
|
+
return result
|
|
263
|
+
|
|
293
264
|
# Convert channel parameters to Cellpose channels list
|
|
294
265
|
# channels = [channel_1, channel_2]
|
|
295
266
|
channels = [0, 0] # limit script to single channel
|
|
296
|
-
# Determine whether to use dedicated environment
|
|
297
|
-
use_env = force_dedicated_env or USE_DEDICATED_ENV
|
|
298
267
|
|
|
299
|
-
if
|
|
300
|
-
|
|
268
|
+
# First check if the environment exists, create if not
|
|
269
|
+
if not is_env_created():
|
|
270
|
+
print(
|
|
271
|
+
"Creating dedicated Cellpose environment (this may take a few minutes)..."
|
|
272
|
+
)
|
|
273
|
+
create_cellpose_env()
|
|
274
|
+
print("Environment created successfully.")
|
|
301
275
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
)
|
|
307
|
-
create_cellpose_env()
|
|
308
|
-
print("Environment created successfully.")
|
|
276
|
+
# Check if we can use zarr optimization
|
|
277
|
+
use_zarr_direct = _source_filepath and _source_filepath.lower().endswith(
|
|
278
|
+
".zarr"
|
|
279
|
+
)
|
|
309
280
|
|
|
310
|
-
|
|
281
|
+
if use_zarr_direct:
|
|
282
|
+
print(f"Using optimized zarr processing for: {_source_filepath}")
|
|
283
|
+
# Prepare arguments for direct zarr processing
|
|
284
|
+
is_3d = "Z" in dim_order
|
|
311
285
|
args = {
|
|
312
|
-
"
|
|
286
|
+
"zarr_path": _source_filepath,
|
|
287
|
+
"zarr_key": None, # Could be enhanced to support specific keys
|
|
313
288
|
"channels": channels,
|
|
314
289
|
"flow_threshold": flow_threshold,
|
|
315
290
|
"cellprob_threshold": cellprob_threshold,
|
|
291
|
+
"flow3D_smooth": flow3D_smooth,
|
|
292
|
+
"anisotropy": anisotropy,
|
|
316
293
|
"normalize": {"tile_norm_blocksize": tile_norm_blocksize},
|
|
317
294
|
"batch_size": batch_size,
|
|
318
|
-
"
|
|
319
|
-
"
|
|
320
|
-
"
|
|
295
|
+
"diameter": diameter,
|
|
296
|
+
"use_gpu": True, # Let cellpose environment detect GPU
|
|
297
|
+
"do_3D": is_3d,
|
|
298
|
+
"z_axis": 0 if is_3d else None,
|
|
299
|
+
"channel_axis": None, # No channel axis for single-channel grayscale images
|
|
321
300
|
}
|
|
322
|
-
|
|
323
|
-
# Run Cellpose in the dedicated environment
|
|
324
|
-
print("Running Cellpose model in dedicated environment...")
|
|
325
|
-
result = run_cellpose_in_env("eval", args)
|
|
326
|
-
print(f"Segmentation complete. Found {np.max(result)} objects.")
|
|
327
|
-
return result
|
|
328
|
-
|
|
329
301
|
else:
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
batch_size=batch_size,
|
|
352
|
-
)
|
|
302
|
+
# Prepare arguments for the Cellpose function (legacy numpy array mode)
|
|
303
|
+
is_3d = "Z" in dim_order
|
|
304
|
+
args = {
|
|
305
|
+
"image": image,
|
|
306
|
+
"channels": channels,
|
|
307
|
+
"flow_threshold": flow_threshold,
|
|
308
|
+
"cellprob_threshold": cellprob_threshold,
|
|
309
|
+
"flow3D_smooth": flow3D_smooth,
|
|
310
|
+
"anisotropy": anisotropy,
|
|
311
|
+
"normalize": {"tile_norm_blocksize": tile_norm_blocksize},
|
|
312
|
+
"batch_size": batch_size,
|
|
313
|
+
"diameter": diameter,
|
|
314
|
+
"use_gpu": True, # Let cellpose environment detect GPU
|
|
315
|
+
"do_3D": is_3d,
|
|
316
|
+
"z_axis": 0 if is_3d else None,
|
|
317
|
+
"channel_axis": None, # No channel axis for single-channel grayscale images
|
|
318
|
+
}
|
|
319
|
+
# Run Cellpose in the dedicated environment
|
|
320
|
+
print("Running Cellpose model in dedicated environment...")
|
|
321
|
+
result = run_cellpose_in_env("eval", args)
|
|
322
|
+
print(f"Segmentation complete. Found {np.max(result)} objects.")
|
|
353
323
|
|
|
354
|
-
|
|
355
|
-
|
|
324
|
+
# Ensure result is uint32 for proper label detection in napari
|
|
325
|
+
# Cellpose typically returns int32, but uint32 is preferred for labels
|
|
326
|
+
if result.dtype != np.uint32:
|
|
327
|
+
result = result.astype(np.uint32)
|
|
356
328
|
|
|
357
|
-
|
|
358
|
-
print(f"Error during segmentation in current environment: {str(e)}")
|
|
359
|
-
|
|
360
|
-
# If we haven't already tried using the dedicated environment, try that as a fallback
|
|
361
|
-
if not USE_DEDICATED_ENV and not force_dedicated_env:
|
|
362
|
-
print("Attempting fallback to dedicated Cellpose environment...")
|
|
363
|
-
try:
|
|
364
|
-
args = {
|
|
365
|
-
"image": image,
|
|
366
|
-
"channels": channels,
|
|
367
|
-
"flow_threshold": flow_threshold,
|
|
368
|
-
"cellprob_threshold": cellprob_threshold,
|
|
369
|
-
"normalize": {"tile_norm_blocksize": tile_norm_blocksize},
|
|
370
|
-
"batch_size": batch_size,
|
|
371
|
-
"use_gpu": USE_GPU,
|
|
372
|
-
"do_3D": "Z" in dim_order,
|
|
373
|
-
"z_axis": 0 if "Z" in dim_order else None,
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
if not is_env_created():
|
|
377
|
-
create_cellpose_env()
|
|
378
|
-
|
|
379
|
-
result = run_cellpose_in_env("eval", args)
|
|
380
|
-
print(f"Fallback successful. Found {np.max(result)} objects.")
|
|
381
|
-
return result
|
|
382
|
-
except (Exception, MemoryError) as fallback_e:
|
|
383
|
-
print(f"Fallback also failed: {str(fallback_e)}")
|
|
384
|
-
raise Exception(
|
|
385
|
-
f"Both direct and dedicated environment approaches failed: {str(e)} | {str(fallback_e)}"
|
|
386
|
-
) from fallback_e
|
|
387
|
-
else:
|
|
388
|
-
raise
|
|
329
|
+
return result
|
|
389
330
|
|
|
390
331
|
|
|
391
332
|
# Update cellpose_env_manager.py to install Cellpose 4
|