Run Cellpose with appose#

Now let’s do something more exciting - run Cellpose segmentation using Appose! This shows how to send real data (an image) to another environment and get meaningful results back.

Important: Set your notebook kernel to ‘Python (appose_napari_ai)’ - this environment doesn’t have Cellpose installed, which perfectly demonstrates calling Cellpose from a different environment!

Load Libraries and Check Local Environment#

First, let’s import what we need. Notice we check if cellpose is available locally - it probably isn’t, and that’s okay! We’ll run it in another environment.

from skimage.io import imread
from matplotlib import pyplot as plt
import appose

try:
    import cellpose
except ImportError:
    print("Cellpose is not installed.")
Cellpose is not installed.

Load Our Test Image#

Let’s load the same cell image we’ve been using. This will be sent to the Cellpose environment for segmentation.

image_path = r"..\..\data\SOTA_segmentation\cell_00068.bmp"
img = imread(image_path)
plt.imshow(img)
<matplotlib.image.AxesImage at 0x1d06f8a6810>
../_images/094e822ce28b43bd1559a34e1e141c281602bd8848c218eb87df31b3b8c53f72.png

Write the Cellpose Code#

We write Cellpose code as a string that will run in the other environment. Note how we get the result back through task.outputs.

# Create the execution string
execution_string = f'''
import numpy as np
from cellpose import models
import appose

model = models.CellposeModel(gpu=True)
    
masks, flows, styles = model.eval(
        image.ndarray(),
        #diameter=30,
        flow_threshold=0.5,
        niter=200
)

# Convert result to appose format for output

ndarr_mask = appose.NDArray(dtype=str(masks.dtype), shape=masks.shape)
ndarr_mask.ndarray()[:] = masks

task.outputs["mask"] = ndarr_mask
'''

Prepare the Image for Sending#

We need to convert our image into Appose’s format so it can be sent to the other environment.

cellpose_env_path = r"..\..\pixi\microsam_cellposesam\.pixi\envs\default"

env = appose.base(cellpose_env_path).build()
ndarr_img = appose.NDArray(dtype=str(img.dtype), shape=img.shape)
ndarr_img.ndarray()[:] = img

# Always include image, optionally add additional inputs
inputs = {"image": ndarr_img}

Run Cellpose in the Other Environment#

Now we send our image and code to the Cellpose environment, wait for it to finish, and get our segmentation mask back.

with env.python() as python:
    task = python.task(execution_string, inputs=inputs, queue="main")
    task.wait_for()

    if task.error:
        print(f"⚠️  Task error: {task.error}")

    print(task.outputs.keys())

    result = task.outputs.get("mask", None)
⚠️  Task error: Traceback (most recent call last):
  File "c:\Users\bnort\work\ImageJ2022\tnia\notebooks-and-napari-widgets-for-dl\pixi\microsam_cellposesam\.pixi\envs\default\Lib\site-packages\appose\python_worker.py", line 145, in _run
    exec(compile(block, "<string>", mode="exec"), _globals, binding)
  File "<string>", line 8, in <module>
  File "c:\Users\bnort\work\ImageJ2022\tnia\notebooks-and-napari-widgets-for-dl\pixi\microsam_cellposesam\.pixi\envs\default\Lib\site-packages\cellpose\models.py", line 338, in eval
    masks = self._compute_masks(x.shape, dP, cellprob, flow_threshold=flow_threshold,
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "c:\Users\bnort\work\ImageJ2022\tnia\notebooks-and-napari-widgets-for-dl\pixi\microsam_cellposesam\.pixi\envs\default\Lib\site-packages\cellpose\models.py", line 524, in _compute_masks
    outputs = dynamics.resize_and_compute_masks(
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "c:\Users\bnort\work\ImageJ2022\tnia\notebooks-and-napari-widgets-for-dl\pixi\microsam_cellposesam\.pixi\envs\default\Lib\site-packages\cellpose\dynamics.py", line 610, in resize_and_compute_masks
    mask = compute_masks(dP, cellprob, niter=niter,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "c:\Users\bnort\work\ImageJ2022\tnia\notebooks-and-napari-widgets-for-dl\pixi\microsam_cellposesam\.pixi\envs\default\Lib\site-packages\cellpose\dynamics.py", line 672, in compute_masks
    mask = remove_bad_flow_masks(mask, dP, threshold=flow_threshold,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "c:\Users\bnort\work\ImageJ2022\tnia\notebooks-and-napari-widgets-for-dl\pixi\microsam_cellposesam\.pixi\envs\default\Lib\site-packages\cellpose\dynamics.py", line 443, in remove_bad_flow_masks
    merrors, _ = flow_error(masks, flows, device0)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "c:\Users\bnort\work\ImageJ2022\tnia\notebooks-and-napari-widgets-for-dl\pixi\microsam_cellposesam\.pixi\envs\default\Lib\site-packages\cellpose\dynamics.py", line 300, in flow_error
    dP_masks = masks_to_flows_gpu(maski, device=device)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "c:\Users\bnort\work\ImageJ2022\tnia\notebooks-and-napari-widgets-for-dl\pixi\microsam_cellposesam\.pixi\envs\default\Lib\site-packages\cellpose\dynamics.py", line 139, in masks_to_flows_gpu
    mu = _extend_centers_gpu(neighbors, meds_p, isneighbor, shape, n_iter=n_iter,
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "c:\Users\bnort\work\ImageJ2022\tnia\notebooks-and-napari-widgets-for-dl\pixi\microsam_cellposesam\.pixi\envs\default\Lib\site-packages\cellpose\dynamics.py", line 45, in _extend_centers_gpu
    Tneigh *= isneighbor
RuntimeError: CUDA error: an illegal memory access was encountered
CUDA kernel errors might be asynchronously reported at some other API call, so the stacktrace below might be incorrect.
For debugging consider passing CUDA_LAUNCH_BLOCKING=1
Compile with `TORCH_USE_CUDA_DSA` to enable device-side assertions.


dict_keys([])

Compare Results#

Let’s see how well our Appose-powered Cellpose did! We’ll compare it side-by-side with the ground truth.

# Load ground truth for comparison
label_path = r"..\..\data\SOTA_segmentation\cell_00068_label.tiff"
ground_truth = imread(label_path)

# Import visualization helper
from tnia.plotting.plt_helper import mask_overlay

# Create overlays
ground_truth_overlay = mask_overlay(img, ground_truth)
result_overlay = mask_overlay(img, result.ndarray())

# Create comparison plot
fig, axes = plt.subplots(1, 2, figsize=(12, 6))

axes[0].imshow(ground_truth_overlay)
axes[0].set_title('Ground Truth')
axes[0].axis('off')

axes[1].imshow(result_overlay)
axes[1].set_title('Appose Cellpose Result')
axes[1].axis('off')

plt.tight_layout()
plt.show()
../_images/5e2f3d507a121426d938327d504437e5e5472f7ac3c37d7c1c4e567aee786a0f.png