napari-tmidas 0.2.0__py3-none-any.whl → 0.2.2__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.
@@ -1,6 +1,7 @@
1
1
  # processing_functions/cellpose_env_manager.py
2
2
  """
3
3
  This module manages a dedicated virtual environment for Cellpose.
4
+ Updated to support Cellpose 4 (Cellpose-SAM) installation.
4
5
  """
5
6
 
6
7
  import os
@@ -59,18 +60,47 @@ def create_cellpose_env():
59
60
  # Path to the Python executable in the new environment
60
61
  env_python = get_env_python_path()
61
62
 
62
- # Install numpy first to ensure correct version
63
- print("Installing NumPy...")
64
- subprocess.check_call(
65
- [env_python, "-m", "pip", "install", "numpy>=1.24,<1.25"]
63
+ # # Install numpy first to ensure correct version
64
+ # print("Installing NumPy...")
65
+ # subprocess.check_call(
66
+ # [env_python, "-m", "pip", "install", "--upgrade", "pip"]
67
+ # )
68
+ # subprocess.check_call(
69
+ # [env_python, "-m", "pip", "install", "numpy>=1.24,<1.25"]
70
+ # )
71
+
72
+ # Install cellpose 4 and other dependencies
73
+ print(
74
+ "Installing Cellpose 4 (Cellpose-SAM) in the dedicated environment..."
66
75
  )
67
-
68
- # Install cellpose and other dependencies
69
- print("Installing Cellpose in the dedicated environment...")
70
76
  subprocess.check_call([env_python, "-m", "pip", "install", "cellpose"])
71
77
 
72
- # Install tifffile for image handling
73
- subprocess.check_call([env_python, "-m", "pip", "install", "tifffile"])
78
+ # # Install PyTorch - needed for GPU acceleration
79
+ # print("Installing PyTorch for GPU acceleration...")
80
+ # subprocess.check_call([
81
+ # env_python, "-m", "pip", "install",
82
+ # "torch", "torchvision"
83
+ # ])
84
+
85
+ # # Install tifffile for image handling
86
+ # subprocess.check_call([env_python, "-m", "pip", "install", "tifffile"])
87
+
88
+ # Check if installation was successful
89
+ try:
90
+ # Run a command to check if cellpose can be imported and GPU is available
91
+ result = subprocess.run(
92
+ [
93
+ env_python,
94
+ "-c",
95
+ "from cellpose import core; print(f'GPU available: {core.use_gpu()}')",
96
+ ],
97
+ capture_output=True,
98
+ text=True,
99
+ check=True,
100
+ )
101
+ print(f"Cellpose environment check: {result.stdout.strip()}")
102
+ except subprocess.CalledProcessError as e:
103
+ print(f"Warning: Cellpose installation check failed: {e.stderr}")
74
104
 
75
105
  print("Cellpose environment created successfully.")
76
106
  return env_python
@@ -109,26 +139,32 @@ def run_cellpose_in_env(func_name, args_dict):
109
139
  tifffile.imwrite(input_file.name, args_dict["image"])
110
140
 
111
141
  # Prepare a temporary script to run Cellpose
142
+ # Updated to use Cellpose 4 parameters
112
143
  script = f"""
113
144
  import numpy as np
114
- from cellpose import models
145
+ from cellpose import models, core
115
146
  import tifffile
116
147
 
148
+
149
+
117
150
  # Load image
118
151
  image = tifffile.imread('{input_file.name}')
119
152
 
120
153
  # Create and run model
121
- model = models.Cellpose(
122
- gpu={args_dict.get('use_gpu', True)},
123
- model_type='{args_dict.get('model_type', 'cyto3')}'
124
- )
154
+ model = models.CellposeModel(
155
+ gpu={args_dict.get('use_gpu', True)})
156
+
157
+ # Prepare normalization parameters (Cellpose 4)
158
+ normalize = {args_dict.get('normalize', {'tile_norm_blocksize': 128})}
125
159
 
126
- # Perform segmentation
127
- masks, *_ = model.eval(
160
+ # Perform segmentation with Cellpose 4 parameters
161
+ masks, flows, styles = model.eval(
128
162
  image,
129
- diameter={args_dict.get('diameter', 30.0)},
130
- flow_threshold={args_dict.get('flow_threshold', 0.4)},
131
163
  channels={args_dict.get('channels', [0, 0])},
164
+ flow_threshold={args_dict.get('flow_threshold', 0.4)},
165
+ cellprob_threshold={args_dict.get('cellprob_threshold', 0.0)},
166
+ batch_size={args_dict.get('batch_size', 32)},
167
+ normalize=normalize,
132
168
  do_3D={args_dict.get('do_3D', False)},
133
169
  z_axis={args_dict.get('z_axis', 0)} if {args_dict.get('do_3D', False)} else None
134
170
  )
@@ -147,10 +183,9 @@ tifffile.imwrite('{output_file.name}', masks)
147
183
  result = subprocess.run(
148
184
  [env_python, script_file.name], capture_output=True, text=True
149
185
  )
150
-
186
+ print("Stdout:", result.stdout)
151
187
  # Check for errors
152
188
  if result.returncode != 0:
153
- print("Stdout:", result.stdout)
154
189
  print("Stderr:", result.stderr)
155
190
  raise RuntimeError(
156
191
  f"Cellpose segmentation failed: {result.stderr}"
@@ -6,10 +6,11 @@ This module provides functionality to automatically segment cells or nuclei in i
6
6
  using the Cellpose deep learning-based segmentation toolkit. It supports both 2D and 3D images,
7
7
  various dimension orders, and handles time series data.
8
8
 
9
+ Updated to support Cellpose 4 (Cellpose-SAM) which offers improved generalization
10
+ for cellular segmentation without requiring diameter parameter.
11
+
9
12
  Note: This requires the cellpose library to be installed.
10
13
  """
11
- import os
12
- import sys
13
14
 
14
15
  import numpy as np
15
16
 
@@ -91,13 +92,15 @@ def run_cellpose(
91
92
  img,
92
93
  model,
93
94
  channels,
94
- diameter,
95
95
  flow_threshold=0.4,
96
+ cellprob_threshold=0.0,
96
97
  dim_order="ZYX",
97
98
  max_pixels=4000000,
99
+ tile_norm_blocksize=128,
100
+ batch_size=32,
98
101
  ):
99
102
  """
100
- Run Cellpose segmentation on an image.
103
+ Run Cellpose segmentation on an image using Cellpose 4 (Cellpose-SAM).
101
104
 
102
105
  Parameters:
103
106
  -----------
@@ -107,14 +110,18 @@ def run_cellpose(
107
110
  Cellpose model to use
108
111
  channels : list
109
112
  Channels to use for segmentation [0,0] = grayscale, [1,0] = green channel, [2,0] = red channel
110
- diameter : float
111
- Diameter of objects to segment
112
113
  flow_threshold : float
113
114
  Flow threshold for Cellpose
115
+ cellprob_threshold : float
116
+ Cell probability threshold
114
117
  dim_order : str
115
118
  Dimension order of the input image
116
119
  max_pixels : int
117
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
118
125
 
119
126
  Returns:
120
127
  --------
@@ -138,6 +145,9 @@ def run_cellpose(
138
145
  # Check if we have a time series
139
146
  has_time = "T" in new_dim_order
140
147
 
148
+ # Set up normalization with tile_norm_blocksize (Cellpose 4 parameter)
149
+ normalize = {"tile_norm_blocksize": tile_norm_blocksize}
150
+
141
151
  if has_time:
142
152
  # Handle time series - process each time point
143
153
  n_timepoints = img_transposed.shape[0]
@@ -146,67 +156,58 @@ def run_cellpose(
146
156
  # Process each time point
147
157
  for t in range(n_timepoints):
148
158
  img_t = img_transposed[t]
149
- mask, _, _, _ = model.eval(
159
+ masks, _, _ = model.eval(
150
160
  img_t,
151
- diameter=diameter,
152
- flow_threshold=flow_threshold,
153
161
  channels=channels,
162
+ flow_threshold=flow_threshold,
163
+ cellprob_threshold=cellprob_threshold,
164
+ normalize=normalize,
154
165
  z_axis=0 if is_3d else None,
155
166
  do_3D=is_3d,
156
- niter=2000, # Maximum iterations
167
+ batch_size=batch_size,
157
168
  )
158
- result[t] = mask
169
+ result[t] = masks
159
170
  else:
160
171
  # Process single time point
161
- result, _, _, _ = model.eval(
172
+ masks, _, _ = model.eval(
162
173
  img_transposed,
163
- diameter=diameter,
164
- flow_threshold=flow_threshold,
165
174
  channels=channels,
175
+ flow_threshold=flow_threshold,
176
+ cellprob_threshold=cellprob_threshold,
177
+ normalize=normalize,
166
178
  z_axis=0 if is_3d else None,
167
179
  do_3D=is_3d,
168
- niter=2000, # Maximum iterations
180
+ batch_size=batch_size,
169
181
  )
182
+ result = masks
170
183
 
171
184
  return result.astype(np.uint32)
172
185
 
173
186
 
174
187
  @BatchProcessingRegistry.register(
175
- name="Segment cells or nuclei (Cellpose)",
188
+ name="Cellpose-SAM Segmentation",
176
189
  suffix="_labels",
177
- description="Automatic instance segmentation using Cellpose 3.0 (dedicated environment)",
190
+ description="Automatic instance segmentation using Cellpose 4 (Cellpose-SAM) with improved generalization.",
178
191
  parameters={
179
- "model_type": {
180
- "type": str,
181
- "default": "cyto3",
182
- "description": "Cellpose model type: 'cyto'/'cyto2'/'cyto3' for cells, 'nuclei' for nuclei",
183
- },
184
- "diameter": {
185
- "type": float,
186
- "default": 40.0,
187
- "min": 5.0,
188
- "max": 1000.0,
189
- "description": "Approximate diameter of objects to segment (pixels)",
190
- },
191
192
  "dim_order": {
192
193
  "type": str,
193
194
  "default": "YX",
194
195
  "description": "Dimension order of the input (e.g., 'YX', 'ZYX', 'TZYX')",
195
196
  },
196
- "channel_1": {
197
- "type": int,
198
- "default": 0,
199
- "min": 0,
200
- "max": 3,
201
- "description": "First channel: 0=grayscale, 1=green, 2=red, 3=blue",
202
- },
203
- "channel_2": {
204
- "type": int,
205
- "default": 0,
206
- "min": 0,
207
- "max": 3,
208
- "description": "Second channel: 0=none, 1=green, 2=red, 3=blue",
209
- },
197
+ # "channel_1": {
198
+ # "type": int,
199
+ # "default": 0,
200
+ # "min": 0,
201
+ # "max": 3,
202
+ # "description": "First channel: 0=grayscale, 1=green, 2=red, 3=blue",
203
+ # },
204
+ # "channel_2": {
205
+ # "type": int,
206
+ # "default": 0,
207
+ # "min": 0,
208
+ # "max": 3,
209
+ # "description": "Second channel: 0=none, 1=green, 2=red, 3=blue",
210
+ # },
210
211
  "flow_threshold": {
211
212
  "type": float,
212
213
  "default": 0.4,
@@ -214,6 +215,27 @@ def run_cellpose(
214
215
  "max": 0.9,
215
216
  "description": "Flow threshold for Cellpose segmentation",
216
217
  },
218
+ "cellprob_threshold": {
219
+ "type": float,
220
+ "default": 0.0,
221
+ "min": -6.0,
222
+ "max": 6.0,
223
+ "description": "Cell probability threshold (Cellpose 4 parameter)",
224
+ },
225
+ "tile_norm_blocksize": {
226
+ "type": int,
227
+ "default": 128,
228
+ "min": 32,
229
+ "max": 512,
230
+ "description": "Block size for tile normalization (Cellpose 4 parameter)",
231
+ },
232
+ "batch_size": {
233
+ "type": int,
234
+ "default": 32,
235
+ "min": 1,
236
+ "max": 128,
237
+ "description": "Batch size for processing multiple images/slices at once",
238
+ },
217
239
  "force_dedicated_env": {
218
240
  "type": bool,
219
241
  "default": False,
@@ -223,20 +245,21 @@ def run_cellpose(
223
245
  )
224
246
  def cellpose_segmentation(
225
247
  image: np.ndarray,
226
- model_type: str = "cyto3",
227
- diameter: float = 40.0,
228
248
  dim_order: str = "YX",
229
249
  channel_1: int = 0,
230
250
  channel_2: int = 0,
231
251
  flow_threshold: float = 0.4,
252
+ cellprob_threshold: float = 0.0,
253
+ tile_norm_blocksize: int = 128,
254
+ batch_size: int = 32,
232
255
  force_dedicated_env: bool = False,
233
256
  ) -> np.ndarray:
234
257
  """
235
- Run Cellpose segmentation on an image.
258
+ Run Cellpose 4 (Cellpose-SAM) segmentation on an image.
236
259
 
237
260
  This function takes an image and performs automatic instance segmentation using
238
- Cellpose. It supports both 2D and 3D images, various dimension orders, and handles
239
- time series data.
261
+ Cellpose 4 with improved generalization for cellular segmentation. It supports
262
+ both 2D and 3D images, various dimension orders, and handles time series data.
240
263
 
241
264
  If Cellpose is not available in the current environment, a dedicated virtual
242
265
  environment will be created to run Cellpose.
@@ -245,10 +268,6 @@ def cellpose_segmentation(
245
268
  -----------
246
269
  image : numpy.ndarray
247
270
  Input image
248
- model_type : str
249
- Cellpose model type: 'cyto'/'cyto2'/'cyto3' for cells, 'nuclei' for nuclei (default: "cyto3")
250
- diameter : float
251
- Approximate diameter of objects to segment in pixels (default: 40.0)
252
271
  dim_order : str
253
272
  Dimension order of the input (e.g., 'YX', 'ZYX', 'TZYX') (default: "YX")
254
273
  channel_1 : int
@@ -257,6 +276,12 @@ def cellpose_segmentation(
257
276
  Second channel: 0=none, 1=green, 2=red, 3=blue (default: 0)
258
277
  flow_threshold : float
259
278
  Flow threshold for Cellpose segmentation (default: 0.4)
279
+ cellprob_threshold : float
280
+ Cell probability threshold (Cellpose 4 parameter) (default: 0.0)
281
+ tile_norm_blocksize : int
282
+ Block size for tile normalization (Cellpose 4 parameter) (default: 128)
283
+ batch_size : int
284
+ Batch size for processing multiple images/slices at once (default: 32)
260
285
  force_dedicated_env : bool
261
286
  Force using dedicated environment even if Cellpose is available (default: False)
262
287
 
@@ -266,16 +291,8 @@ def cellpose_segmentation(
266
291
  Segmented image with instance labels
267
292
  """
268
293
  # Convert channel parameters to Cellpose channels list
269
- channels = [channel_1, channel_2]
270
-
271
- # Validate parameters
272
- valid_models = ["cyto", "cyto2", "cyto3", "nuclei"]
273
- if model_type not in valid_models:
274
- raise ValueError(
275
- f"Invalid model_type: {model_type}. "
276
- f"Must be one of: {', '.join(valid_models)}"
277
- )
278
-
294
+ # channels = [channel_1, channel_2]
295
+ channels = [0, 0] # limit script to single channel
279
296
  # Determine whether to use dedicated environment
280
297
  use_env = force_dedicated_env or USE_DEDICATED_ENV
281
298
 
@@ -293,29 +310,30 @@ def cellpose_segmentation(
293
310
  # Prepare arguments for the Cellpose function
294
311
  args = {
295
312
  "image": image,
296
- "model_type": model_type,
297
- "diameter": diameter,
298
313
  "channels": channels,
299
314
  "flow_threshold": flow_threshold,
315
+ "cellprob_threshold": cellprob_threshold,
316
+ "normalize": {"tile_norm_blocksize": tile_norm_blocksize},
317
+ "batch_size": batch_size,
300
318
  "use_gpu": USE_GPU,
301
319
  "do_3D": "Z" in dim_order,
302
320
  "z_axis": 0 if "Z" in dim_order else None,
303
321
  }
304
322
 
305
323
  # Run Cellpose in the dedicated environment
306
- print(f"Running Cellpose ({model_type}) in dedicated environment...")
324
+ print("Running Cellpose model in dedicated environment...")
307
325
  result = run_cellpose_in_env("eval", args)
308
326
  print(f"Segmentation complete. Found {np.max(result)} objects.")
309
327
  return result
310
328
 
311
329
  else:
312
- print(f"Running Cellpose ({model_type}) in current environment...")
330
+ print("Running Cellpose model in current environment...")
313
331
  # Initialize Cellpose model in current environment
314
- model = models.Cellpose(gpu=USE_GPU, model_type=model_type)
332
+ model = models.CellposeModel(gpu=USE_GPU)
315
333
 
316
334
  # Print status information
317
335
  gpu_status = "GPU" if USE_GPU else "CPU"
318
- print(f"Using Cellpose {model_type} model on {gpu_status}")
336
+ print(f"Using Cellpose on {gpu_status}")
319
337
  print(
320
338
  f"Processing image with shape {image.shape}, dimension order: {dim_order}"
321
339
  )
@@ -323,7 +341,14 @@ def cellpose_segmentation(
323
341
  # Run segmentation
324
342
  try:
325
343
  result = run_cellpose(
326
- image, model, channels, diameter, flow_threshold, dim_order
344
+ image,
345
+ model,
346
+ channels,
347
+ flow_threshold,
348
+ cellprob_threshold,
349
+ dim_order,
350
+ tile_norm_blocksize=tile_norm_blocksize,
351
+ batch_size=batch_size,
327
352
  )
328
353
 
329
354
  print(f"Segmentation complete. Found {np.max(result)} objects.")
@@ -338,10 +363,11 @@ def cellpose_segmentation(
338
363
  try:
339
364
  args = {
340
365
  "image": image,
341
- "model_type": model_type,
342
- "diameter": diameter,
343
366
  "channels": channels,
344
367
  "flow_threshold": flow_threshold,
368
+ "cellprob_threshold": cellprob_threshold,
369
+ "normalize": {"tile_norm_blocksize": tile_norm_blocksize},
370
+ "batch_size": batch_size,
345
371
  "use_gpu": USE_GPU,
346
372
  "do_3D": "Z" in dim_order,
347
373
  "z_axis": 0 if "Z" in dim_order else None,
@@ -362,150 +388,11 @@ def cellpose_segmentation(
362
388
  raise
363
389
 
364
390
 
365
- # Add a command-line function to run cellpose segmentation
366
- def run_cellpose_segmentation():
367
- """Run Cellpose segmentation from the command line."""
368
- import argparse
369
-
370
- from skimage.io import imread
371
- from tifffile import imwrite
372
- from tqdm import tqdm
373
-
374
- # Parse arguments
375
- parser = argparse.ArgumentParser(
376
- description="Runs automatic mask generation on images using Cellpose."
377
- )
378
- parser.add_argument(
379
- "--input", type=str, required=True, help="Path to input images."
380
- )
381
- parser.add_argument(
382
- "--diameter", type=float, default=40.0, help="Diameter of objects."
383
- )
384
- parser.add_argument(
385
- "--channels",
386
- type=int,
387
- nargs="+",
388
- default=[0, 0],
389
- help="Channels to use.",
390
- )
391
- parser.add_argument(
392
- "--dim_order",
393
- type=str,
394
- default="ZYX",
395
- help="Dimension order of the input images.",
396
- )
397
- parser.add_argument(
398
- "--model_type",
399
- type=str,
400
- default="cyto3",
401
- choices=["cyto", "cyto2", "cyto3", "nuclei"],
402
- help="Model type: 'cyto'/'cyto2'/'cyto3' for cells, 'nuclei' for nuclei",
403
- )
404
- parser.add_argument(
405
- "--flow_threshold",
406
- type=float,
407
- default=0.4,
408
- help="Flow threshold for Cellpose (default: 0.4)",
409
- )
410
- parser.add_argument(
411
- "--max_pixels",
412
- type=int,
413
- default=4000000,
414
- help="Maximum number of pixels to process for 2D images (default: 4000000)",
415
- )
416
-
417
- args = parser.parse_args()
418
-
419
- # Validate input folder
420
- input_folder = args.input
421
- if not os.path.isdir(input_folder):
422
- print(
423
- f"Error: The input folder '{input_folder}' does not exist or is not accessible."
424
- )
425
- return 1
426
-
427
- # Find input files
428
- input_files = [
429
- f
430
- for f in os.listdir(input_folder)
431
- if f.endswith(".tif") and not f.endswith("_labels.tif")
432
- ]
433
-
434
- if not input_files:
435
- print(f"No .tif files found in {input_folder}")
436
- return 1
437
-
438
- print(f"Found {len(input_files)} files to process")
439
-
440
- # Check if Cellpose is available
441
- if not CELLPOSE_AVAILABLE:
442
- print(
443
- "Error: Cellpose is not installed. Please install it with: pip install cellpose"
444
- )
445
- return 1
446
-
447
- # Initialize model
448
- model = models.Cellpose(gpu=USE_GPU, model_type=args.model_type)
449
-
450
- # Print status
451
- gpu_status = "GPU" if USE_GPU else "CPU"
452
- print(f"Using Cellpose {args.model_type} model on {gpu_status}")
453
-
454
- # Process each file
455
- for input_file in tqdm(input_files, desc="Processing images"):
456
- try:
457
- # Check image size
458
- img = imread(os.path.join(input_folder, input_file))
459
-
460
- if len(img.shape) == 2 or (
461
- len(img.shape) == 3 and "C" in args.dim_order
462
- ):
463
- # For 2D images (potentially with channels)
464
- height, width = img.shape[:2]
465
- total_pixels = height * width
466
- if total_pixels > args.max_pixels:
467
- print(
468
- f"Skipping {input_file} as it exceeds the maximum size of {args.max_pixels} pixels."
469
- )
470
- continue
471
-
472
- print(
473
- "\nCheck if image shape corresponds to the dim order that you have given:"
474
- )
475
- print(
476
- f"Image shape: {img.shape}, dimension order: {args.dim_order}\n"
477
- )
478
-
479
- # Run segmentation
480
- result = run_cellpose(
481
- img,
482
- model,
483
- args.channels,
484
- args.diameter,
485
- args.flow_threshold,
486
- args.dim_order,
487
- args.max_pixels,
488
- )
489
-
490
- # Save result
491
- output_file = os.path.join(
492
- input_folder, input_file.replace(".tif", "_labels.tif")
493
- )
494
- imwrite(output_file, result, compression="zlib")
495
-
496
- print(
497
- f"Saved segmentation with {np.max(result)} objects to {output_file}"
498
- )
499
-
500
- except (Exception, MemoryError) as e:
501
- print(f"Error processing {input_file}: {str(e)}")
502
-
503
- print("\nProcessing complete.")
504
- return 0
505
-
506
-
507
- # Run the command-line function if this script is run directly
508
- if __name__ == "__main__":
509
- import sys
510
-
511
- sys.exit(run_cellpose_segmentation())
391
+ # Update cellpose_env_manager.py to install Cellpose 4
392
+ def update_cellpose_env_manager():
393
+ """
394
+ Update the cellpose_env_manager to install Cellpose 4
395
+ """
396
+ # This function can be called to update the environment manager code
397
+ # For example, by modifying the pip install command to install the latest version
398
+ # or specify Cellpose 4 explicitly