Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions examples/servers/serverkit-cellposev4_gpu/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Doc: https://github.com/conda-forge/miniforge-images
FROM pytorch/pytorch:2.8.0-cuda12.9-cudnn9-runtime

RUN python3 -m pip install --upgrade pip
RUN pip install imaging-server-kit cellpose opencv-python-headless

WORKDIR /app

COPY . .

EXPOSE 8000

CMD ["python3", "main.py"]
19 changes: 19 additions & 0 deletions examples/servers/serverkit-cellposev4_gpu/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
![EPFL Center for Imaging logo](https://imaging.epfl.ch/resources/logo-for-gitlab.svg)
# serverkit-cellposev4

Implementation of a web server for [CellPosev4](https://github.com/MouseLand/cellpose) with GPU in WSL2 support.


## Using `docker-compose`

To build the docker image and run a container for the algorithm server in a single command, use:

```
docker compose up
```

The server will be running on http://localhost:8000.

## Sample images provenance

- `nuclei_2d.tif`: Fluorescence microscopy image and mask from the 2018 kaggle DSB challenge (Caicedo et al. "Nucleus segmentation across imaging experiments: the 2018 Data Science Bowl." Nature methods 16.12).
17 changes: 17 additions & 0 deletions examples/servers/serverkit-cellposev4_gpu/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
services:
cellpose_single:
container_name: cellpose_single
build:
context: .
dockerfile: Dockerfile
image: serverkit_cellpose:gpu-latest
ports:
- "8000:8000"
volumes:
- E:\models\cellposev4:/models
- .cache:/root/.cellpose/models
deploy:
resources:
reservations:
devices:
- capabilities: [gpu]
122 changes: 122 additions & 0 deletions examples/servers/serverkit-cellposev4_gpu/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
from pathlib import Path
from typing import List
import os

import numpy as np
import uvicorn
from cellpose import models

from imaging_server_kit import (
DropDownUI,
FloatUI,
ImageUI,
IntUI,
algorithm_server,
)

custom_model_path = "/models" # Use relative path for portability
if os.path.exists(custom_model_path):
custom_models = [f.name for f in os.scandir(custom_model_path) if f.is_file()]
else:
custom_models = []
base_models = ["cpsam"] # Add all built-in models you want to support
models_list = base_models + custom_models
print(f"Available models: {models_list}")

# Global cache variables for performance
last_model = None
cached_model = None
last_custom_path = None
cached_custom_model = None

@algorithm_server(
algorithm_name="cellpose",
parameters={
"image": ImageUI(
title="Image",
description="Input image (2D).",
dimensionality=[2],
),
"model_name": DropDownUI(
default="cpsam",
title="Model",
description="The model used for instance segmentation",
items=models_list, # Use dynamic list
),
"flow_threshold": FloatUI(
default=0.3,
title="Flow threshold",
description="The flow threshold",
min=0.0,
max=1.0,
step=0.05,
),
"cellprob_threshold": FloatUI(
default=0.5,
title="Probability threshold",
description="The detection probability threshold",
min=0.0,
max=1.0,
step=0.01,
),
},
title="CellPose",
description="A generalist algorithm for cellular segmentation.",
used_for=["Segmentation"],
tags=[
"Deep learning",
"Fluorescence microscopy",
"Digital pathology",
"Cell biology",
],
project_url="https://github.com/MouseLand/cellpose",
sample_images=[
str(Path(__file__).parent / "sample_images" / "nuclei_2d.tif"),
],
)
def cellpose_server(
image: np.ndarray,
model_name: str,
flow_threshold: float,
cellprob_threshold: float,
) -> List[tuple]:
"""Runs the algorithm."""
global last_model, cached_model, last_custom_path, cached_custom_model
if len(image.shape) != 2:
if image.shape[0] == 1:
image = image[0]
else:
raise ValueError("Input image must be 2D")
if model_name in custom_models:
model_path = os.path.join(custom_model_path, model_name)
if model_name != last_custom_path:
print(f"Loading custom model from {model_path}")
cached_custom_model = models.CellposeModel(gpu=True, pretrained_model=model_path)
last_custom_path = model_name
else:
print(f"Using cached custom model from {model_path}")
model = cached_custom_model
else:
if model_name != last_model:
print("Loading built-in model")
cached_model = models.CellposeModel(gpu=True, pretrained_model=model_name)
last_model = model_name
else:
print("Using cached built-in model")
model = cached_model

segmentation, flows, styles = model.eval(
image,
flow_threshold=flow_threshold,
cellprob_threshold=cellprob_threshold,
)

segmentation_params = {"name": "Cellpose result"}

return [
(segmentation, segmentation_params, "instance_mask"),
]


if __name__ == "__main__":
uvicorn.run(cellpose_server.app, host="0.0.0.0", port=8000)
5 changes: 5 additions & 0 deletions examples/servers/serverkit-cellposev4_gpu/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
imaging-server-kit
cellpose
torch
torchvision
opencv-contrib-python-headless
Binary file not shown.