{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "colab_type": "text",
        "id": "view-in-github"
      },
      "source": [
        "<a href=\"https://colab.research.google.com/github/MouseLand/cellpose/blob/main/notebooks/test_Cellpose-SAM.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Nb90LCrotIx4"
      },
      "source": [
        "# Cellpose-SAM: superhuman generalization for cellular segmentation\n",
        "\n",
        "Marius Pachitariu, Michael Rariden, Carsen Stringer\n",
        "\n",
        "[paper](https://www.biorxiv.org/content/10.1101/2025.04.28.651001v1) | [code](https://github.com/MouseLand/cellpose)\n",
        "\n",
        "This notebook explains processing example 2D and 3D images using the Cellpose package on Google Colab using the GPU."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Z0s2fz5hUk75"
      },
      "source": [
        "### Make sure you have GPU access enabled by going to Runtime -> Change Runtime Type -> Hardware accelerator and selecting GPU\n",
        "\n",
        "![image.png](data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAV4AAAD5CAYAAABvRV34AAAgAElEQVR4Ae2de7QU1Zm3+XNumWQuK7MyMyvKmjEhMRkdJ2GUGDFE+CReCYqIV8RRTBQ0igYviAIiioIKGi8oES8gEZWIokaQKBdFQCIGFSQCKooKHOAc7rzfevbhbXbX6e7TTXcd+pzzq7Wqq7tq1778du2n3nr3rt1tzj//fPO1T58+lms977zzrNDau3dvy7Wee+65plUa6BrQNdASroFcjGNfITZyLBdT2+SDbmORJTPREoRVGQQIXQO6Bkq5BpIcbIybDuEAXv/BttCJyURKyeA555xjWqWBrgFdA83tGiiWc0k+FmJpG4duoUDJCAtlpLmJqvwKBLoGdA2Ueg0UYmCSl/xO8jWAN7nTf3NC//79bdGiRbZ7927TIgWkgBSQAsUpADNhJwx1GDtbc4LXA7HlRC1SQApIASmwbwrA0JipwLeNE9i3cQDMaVm6+ya2zpICUkAKoAAMhaUxW7PA6wdi/4WkkwJSQApIgfIUiJkKZzPgzQVdAmuRAlJACkiB8hSg8y6GbwBvLuh6L195yelsKSAFpIAUcJ46fNskoesB2J599tlSTApIASkgBcpUAJbGbA3gdQqz9YMEFHjLVFunSwEpIAXMAktj+GaBNwndM888U6JJASkgBaRAmQrAUjdm4Wyb2Nr1A2wJKPCWqbZOlwJSQAqYZXjqjM2AFwr7zrPOOisEPOOMMySaFJACUkAKlKkALMWQha1wNoA3F3QJ1KtXrzKT0+lSQApIASkAS92LAHzzgpeAp59+uhSTAlJACkiBMhWApQ7fAN64Qy12MRCoZ8+eZSan06WAFJACUgCWwlR3ObTJ5WZwa1fg1QUjBaSAFChfAVgaW70Z8Lq1675dAp122mnlp6gYpIAUkAKtXAFYmgXeXCMZ3M3Qo0ePVi6Xii8FpIAUKF8BWBq7G9oAXqxdt3hjN4PAW77gikEKSAEp4OB1qzcDXh/q4ODFND711FOlmBSQAlJACpSpACyN3Q05wYtJLPCWqbROlwJSQArsUcDB6+6GLPAy1CH2755yyikSTgpIASkgBcpUAJa6uwHGNgAvPgioTCCBt0y1dboUkAJSwCywNAu8cccaFq/Aq+tECkgBKVBZBWKLF8a28dEM7maIwdu9e/fKpq7YpIAUkAKtUAFY6hZvXvDSsUYggbcVXiEqshSQAhVXwMHrIxtyWrwCb8V1V4RSQAq0YgUE3kYqf926ddatWzc78sgjbdmyZY2EruzhefPmWdu2bW3EiBGVjTjF2Hbt2mXr16+37du3p5iKopYCzVuBRsHrY3jTdjU4ZADce++910BVP96/f3+rq6trcDytHQJvacpOmTIl3CwGDhwo+JYmnUK3IgVi8MLYjKuBsWU+htdfniBwWouDFQtvwIABDeDqx/cFvOXAs5xzy9XKy7w/Ld585c+3nzwfccQRNmbMGNu5c2e5Euh8KdAiFYCl8UsUVQHegw46yKZNm5YluENI4M2SJfUf+QCbb3/qGVICUqAFKFASeH/+85+nVmQH63e/+10DvMcff7x98sknmfT8eBK8K1euNB5rDz300HAek/wsXrzYdu/eHc594oknwqMvlrSvcRxbtmyxcePGWadOncJxtpMnT7Zt27aF82PATJ06Nfw/Evnr0KGDPfnkkw2susby4wWqra0tmC7hvMyxxTt79uxQVvK5dOlSj67B9qOPPsrShYqeOXOm4YONl3feeccuuugia9euXVj79etnlIEln3aPPPJIRsukpn6O59n169ixo5H3Sy+9NKRDfd1zzz2G/r5QZ7NmzbITTjghxH/sscfa9OnTjTzFPnYsaerCw7Vv396GDh1qn3/+uUelrRSoagVgadEWb1OAt2/fvjZo0KDQ8O64444M2BxCMTTff//9AExASCMF1g6Qp556Kgg/f/58u+mmm+zwww+3733ve3bdddcFsNL5g68YtwbwOOqoo+zkk082GjG/gQIgcHA4YI455phMOuwbP358BvLF5IdMAd3LL788Z7q//vWvM24WL7NDzOMHWkAs3wI4u3TpErRArxtuuCGUC524WfhC/MSFZmiHhoThXOLIp93cuXPzapoPvMTLTTWp34QJEzw7oUzkB10JR344h9XBS51QN4ThONpws+U3rrEvvvgiE5++SIFqVaDqwAsoPvjggwACGuHChQuDdg4hBy8W6ZVXXhlAgYXqFq5bhCeeeKJ9+umn4VyHpzder4xXXnklnA8EgSELVjYQ6ty5s61atSoLvI8++mjGYkymU0p+sNYARZzuZ599Fl7NBlDki8XLDFzi43F5Q8DEh3dw4Wd1XRYsWBBuPBdccIFt3rw5lJebXAxxwnIjIW9jx44N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)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "_lRDGixTm1Px"
      },
      "source": [
        "### Install Cellpose-SAM"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "cellView": "form",
        "id": "hG3LSmJmLylT"
      },
      "outputs": [],
      "source": [
        "!uv pip install git+https://www.github.com/mouseland/cellpose.git\n",
        "!uv pip install git+https://github.com/facebookresearch/dinov3.git"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "JRalUQBTm1Py"
      },
      "source": [
        "Check GPU and instantiate model - will download weights."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "cellView": "form",
        "id": "5ydQ-fggSiUm"
      },
      "outputs": [],
      "source": [
        "import numpy as np\n",
        "from cellpose import models, core, io, plot\n",
        "from pathlib import Path\n",
        "from tqdm import trange\n",
        "import matplotlib.pyplot as plt\n",
        "\n",
        "io.logger_setup() # run this to get printing of progress\n",
        "\n",
        "#Check if colab notebook instance has GPU access\n",
        "if core.use_gpu()==False:\n",
        "  raise ImportError(\"No GPU access, change your runtime\")\n",
        "\n",
        "model = models.CellposeModel(gpu=True)\n",
        "\n",
        "### You can also use other pretrained models, like the DINO models \n",
        "# model = models.CellposeModel(gpu=True, pretrained_model=\"cpdino\")\n",
        "# model = models.CellposeModel(gpu=True, pretrained_model=\"cpdino-vitb\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "fY6Vv5I3m1Py"
      },
      "source": [
        "### Download example images"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "cellView": "form",
        "id": "-lZP6alpUAfY"
      },
      "outputs": [],
      "source": [
        "import numpy as np\n",
        "import matplotlib.pyplot as plt\n",
        "from cellpose import utils, io\n",
        "\n",
        "# download example 2D images from website\n",
        "url = \"http://www.cellpose.org/static/data/imgs_cyto3.npz\"\n",
        "filename = \"imgs_cyto3.npz\"\n",
        "utils.download_url_to_file(url, filename)\n",
        "\n",
        "# download 3D tiff\n",
        "url = \"http://www.cellpose.org/static/data/rgb_3D.tif\"\n",
        "utils.download_url_to_file(url, \"rgb_3D.tif\")\n",
        "\n",
        "dat = np.load(filename, allow_pickle=True)[\"arr_0\"].item()\n",
        "\n",
        "imgs = dat[\"imgs\"]\n",
        "masks_true = dat[\"masks_true\"]\n",
        "\n",
        "plt.figure(figsize=(8,3))\n",
        "for i, iex in enumerate([9, 16, 21]):\n",
        "    img = imgs[iex].squeeze()\n",
        "    plt.subplot(1,3,1+i)\n",
        "    plt.imshow(img[0], cmap=\"gray\", vmin=0, vmax=1)\n",
        "    plt.axis('off')\n",
        "plt.tight_layout()\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "M-jKt9wsm1Pz"
      },
      "source": [
        "### Run Cellpose-SAM"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "cellView": "form",
        "id": "98DA8zm4A__m"
      },
      "outputs": [],
      "source": [
        "masks_pred, flows, styles = model.eval(imgs, niter=1000) # using more iterations for bacteria\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "3JRxBPmatrK7"
      },
      "source": [
        "plot results"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "teNSdi1_m1Pz"
      },
      "outputs": [],
      "source": [
        "from cellpose import transforms, plot\n",
        "\n",
        "titles = [\n",
        "        \"Cellpose\", \"Nuclei\", \"Tissuenet\", \"Livecell\", \"YeaZ\",\n",
        "         \"Omnipose\\nphase-contrast\", \"Omnipose\\nfluorescent\",\n",
        "        \"DeepBacs\"\n",
        "    ]\n",
        "\n",
        "plt.figure(figsize=(12,6))\n",
        "ly = 400\n",
        "for iex in range(len(imgs)):\n",
        "    img = imgs[iex].squeeze().copy()\n",
        "    img = np.clip(transforms.normalize_img(img, axis=0), 0, 1) # normalize images across channel axis\n",
        "    ax = plt.subplot(3, 8, (iex%3)*8 + (iex//3) +1)\n",
        "    if img[1].sum()==0:\n",
        "        img = img[0]\n",
        "        ax.imshow(img, cmap=\"gray\")\n",
        "    else:\n",
        "        # make RGB from 2 channel image\n",
        "        img = np.concatenate((np.zeros_like(img)[:1], img), axis=0).transpose(1,2,0)\n",
        "        ax.imshow(img)\n",
        "    ax.set_ylim([0, min(400, img.shape[0])])\n",
        "    ax.set_xlim([0, min(400, img.shape[1])])\n",
        "\n",
        "\n",
        "    # GROUND-TRUTH = PURPLE\n",
        "    # PREDICTED = YELLOW\n",
        "    outlines_gt = utils.outlines_list(masks_true[iex])\n",
        "    outlines_pred = utils.outlines_list(masks_pred[iex])\n",
        "    for o in outlines_gt:\n",
        "        plt.plot(o[:,0], o[:,1], color=[0.7,0.4,1], lw=0.5)\n",
        "    for o in outlines_pred:\n",
        "        plt.plot(o[:,0], o[:,1], color=[1,1,0.3], lw=0.75, ls=\"--\")\n",
        "    plt.axis('off')\n",
        "\n",
        "    if iex%3 == 0:\n",
        "        ax.set_title(titles[iex//3])\n",
        "\n",
        "plt.tight_layout()\n",
        "plt.show()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "rMyZtY6ym1P0"
      },
      "source": [
        "# Run Cellpose-SAM in 3D\n",
        "\n",
        "There are two ways to run cellpose in 3D, this cell shows both, choose which one works best for you.\n",
        "\n",
        "First way: computes flows from 2D slices and combines into 3D flows to create masks\n",
        "\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "2b2hVxCvm1P0"
      },
      "outputs": [],
      "source": [
        "img_3D = io.imread(\"rgb_3D.tif\")\n",
        "\n",
        "\n",
        "# 1. computes flows from 2D slices and combines into 3D flows to create masks\n",
        "masks, flows, _ = model.eval(img_3D, z_axis=0, channel_axis=1,\n",
        "                                batch_size=32,\n",
        "                                do_3D=True, flow3D_smooth=1)\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "KeMtAuRom1P0"
      },
      "source": [
        "Second way: computes masks in 2D slices and stitches masks in 3D based on mask overlap\n",
        "\n",
        "Note stitching (with stitch_threshold > 0) can also be used to track cells over time."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "WTyCgBUfm1P0"
      },
      "outputs": [],
      "source": [
        "# 2. computes masks in 2D slices and stitches masks in 3D based on mask overlap\n",
        "print('running cellpose 2D + stitching masks')\n",
        "masks_stitched, flows_stitched, _ = model.eval(img_3D, z_axis=0, channel_axis=1,\n",
        "                                                  batch_size=32,\n",
        "                                                  do_3D=False, stitch_threshold=0.5)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "wbu1j0h6m1P0"
      },
      "source": [
        "Results from 3D flows => masks computation"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "Vfg67u2dm1P0"
      },
      "outputs": [],
      "source": [
        "# DISPLAY RESULTS 3D flows => masks\n",
        "plt.figure(figsize=(15,3))\n",
        "for i,iplane in enumerate(np.arange(0,75,10,int)):\n",
        "  img0 = plot.image_to_rgb(img_3D[iplane, [1,0]].copy(), channels=[2,3])\n",
        "  plt.subplot(1,8,i+1)\n",
        "  outlines = utils.masks_to_outlines(masks[iplane])\n",
        "  outX, outY = np.nonzero(outlines)\n",
        "  imgout= img0.copy()\n",
        "  imgout[outX, outY] = np.array([255,75,75])\n",
        "  plt.imshow(imgout)\n",
        "  plt.title('iplane = %d'%iplane)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "dj18ZyzHm1P0"
      },
      "source": [
        "Results from stitching"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "fd-6Hji-n9_H"
      },
      "outputs": [],
      "source": [
        "# DISPLAY RESULTS stitching\n",
        "plt.figure(figsize=(15,3))\n",
        "for i,iplane in enumerate(np.arange(0,75,10,int)):\n",
        "  img0 = plot.image_to_rgb(img_3D[iplane, [1,0]].copy(), channels=[2,3])\n",
        "  plt.subplot(1,8,i+1)\n",
        "  outlines = utils.masks_to_outlines(masks_stitched[iplane])\n",
        "  outX, outY = np.nonzero(outlines)\n",
        "  imgout= img0.copy()\n",
        "  imgout[outX, outY] = np.array([255,75,75])\n",
        "  plt.imshow(imgout)\n",
        "  plt.title('iplane = %d'%iplane)"
      ]
    }
  ],
  "metadata": {
    "accelerator": "GPU",
    "colab": {
      "include_colab_link": true,
      "provenance": []
    },
    "kernelspec": {
      "display_name": "s2p_test",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3.11.14"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}