Skip to main content

Performing Resegmentation and Cell Assignment Using Python

If you want to improve the segmentation of your data, you can rerun segmentation with the AVITI24 output data. One common framework for resegmentation is Cellpose, which lets you apply various pretrained segmentation models or customize one for your data. Additionally, you can try a different pre-trained Element Biosciences segmentation model than was used on instrument.

This tutorial describes how to use Python-based tools to apply Cellpose resegmentation models to AVITI24 cytoprofiling run data. To perform additional analyses for morphology or image quantification metrics, see the Running CellProfiler with AVITI24 Data tutorial.

Before You Begin

Make sure you have the following prerequisites for this tutorial:

To install the required Python packages and enable all prerequisites, run the following commands in a CLI with Anaconda:

pip install notebook
conda create --name resegmentation python=3.10
conda activate resegmentation
conda install -c conda-forge cellpose scikit-image
conda install -c anaconda ipykernel
python -m ipykernel install --user --name=resegmentation

Rerun Segmentation with a Custom Model

  1. In the CLI terminal with Anaconda, run the following command to open Jupyter Notebook.
jupyter notebook
  1. To download Element Biosciences custom Cellpose models, follow instructions to install the Element cytoprofiling package.
  2. Select New, and then select Notebook.
  3. In the drop-down menu, select the resegmentation kernel.
  4. To import required packages, copy the following code into the first cell.
from cellpose import models, transforms
import skimage
import os
import numpy as np
import json
  1. Copy the following code into a second cell to run segmentation, updating the following variables:
    • Update run_path to the run output files folder.
    • Update model_dir to the path of your installation of the cytoprofiling repository.
    • Update output_location to your preferred output location for the resegmentation files.
    • Update cell_types and cell_diameters based on your samples in each well.
    • To use your own segmenation models, change model_dir and element_models to point to your model files.
# define the cell type per well
cell_types = {
"A1":"HELA",
"A2":"HELA",
"B1":"HUVEC",
"B2":"OTHER",
"C1":"MCF7",
"C2":"PC3",
"D1":"HEK293",
"D2":"OTHER",
"E1":"JURKAT",
"E2":"HUVEC",
"F1":"MCF7",
"F2":"HEPG2"
}

# set the cell diameter to be used for segmentation of "OTHER" cell types
cell_diameters = {
"B2":100,
"D2":75
}

# Element Biosciences pre-trained nuclear segmentation model
nuclear_model = "20240629_cellpose_nuc_8diam"

# Element Biosciences pre-trained segmentation models
element_models = {
"OTHER":"20240905_general_15diam_3ch",
"HELA":"20240905_hela_15diam_3ch",
"HUVEC":"20240905_huvec_15diam_3ch",
"MCF7":"20240924_mcf7_15diam_3ch",
"PC3":"20240924_pc3_15diam_3ch",
"HEK293":"20240924_hek293_15diam_3ch",
"JURKAT":"20240924_jurkat_15diam_3ch",
"HEPG2":"20240924_hepg2_15diam_3ch",
"HCT116":"20240924_hct116_15diam_3ch"
}

model_dir = "C:/cytoprofiling/Package/Path/segmentationModels"

run_path = "C:/Run/Output/Folder/Location"

output_location = "C:/Output/Location/CellSegmentation_modelv2"

def normalize_image(image, region_size=1824):
"""
Normalize an image within a defined region size.
"""
image_norm = np.zeros_like(image, np.single)

for xi in range(int(image.shape[1] / region_size)):
for yi in range(int(image.shape[0] / region_size)):
cropped = image[
yi * region_size: (yi + 1) * region_size, xi * region_size: (xi + 1) * region_size
]
cropped = transforms.normalize_img(cropped.reshape(
cropped.shape[0], cropped.shape[1], 1)).reshape(cropped.shape[0], cropped.shape[1])
image_norm[
yi * region_size: (yi + 1) * region_size, xi * region_size: (xi + 1) * region_size
] = cropped

return image_norm

def segment_cells(cell_image, nuclear_image, actin_image, cell_model_path, nuclear_model_path, cell_diameter, normalization=False, use_gpu=False):

cell_image = normalize_image(cell_image)
nuclear_image = normalize_image(nuclear_image)
actin_image = normalize_image(actin_image)

segment_channel = 1

nuclear_channel = 2

channels = [segment_channel, nuclear_channel]

composite = np.zeros((cell_image.shape[0], cell_image.shape[1], 3))
composite[:, :, 0] = cell_image
composite[:, :, 1] = nuclear_image
composite[:, :, 2] = actin_image

print(f"using {cell_model_path} for cell segmentation")

# segment cells
if cell_model_path in ["cyto3","cyto2"]:
"""
Use the default Cellpose3 model.
Cell diameter from the user is used here.
"""
model = models.Cellpose(gpu=use_gpu, model_type=cell_model_path)

cell_mask, _, _, _ = model.eval(
composite,
diameter=cell_diameter,
channels=channels,
normalize=normalization
)

elif cell_model_path == "20240903_general_15diam_3ch":
"""
Use the general Element Biosciences model.
Cell diameter from the user is used here.
"""
model = models.CellposeModel(gpu=use_gpu,pretrained_model=False,nchan=3,
model_type=cell_model_path)

cell_mask, _, _ = model.eval(
composite,
diameter=cell_diameter,
channels=None,
normalize=normalization
)

else:
"""
Use a custom Cellpose model trained trained on 3 channels.
Cell diameter from the user is not used and the mean diameter from the training set is used instead.
"""
model = models.CellposeModel(gpu=use_gpu,pretrained_model=False,nchan=3,
model_type=cell_model_path)

cell_mask, _, _ = model.eval(
composite,
channels=None,
normalize=normalization
)

cell_mask = cell_mask.astype(np.uint32)

print(f"using {nuclear_model_path} for nuclear segmentation")

# segment nuclei
model = models.CellposeModel(pretrained_model=False, model_type=nuclear_model_path)

nuclear_mask, _, _ = model.eval(
nuclear_image
)

binary_nuclei = nuclear_mask.copy()
binary_nuclei[nuclear_mask > 0] = 1

return cell_mask, binary_nuclei

# load run paramters file
with open(os.path.join(run_path,"RunParameters.json")) as f:
run_parameters = json.load(f)

tile2well = {}
tiles = []

for well in run_parameters["Wells"]:
for tile in well["Tiles"]:
tile2well[tile["Name"]] = well["WellLocation"]
tiles.append(tile["Name"])

# do segmentation
for tile in tiles:
well = tile2well[tile]
cell_type = cell_types[well]
cell_diameter = cell_diameters.get(well, 0)

cell_model_path = os.path.join(model_dir,element_models.get(cell_type.upper(),element_models["OTHER"]))
nuclear_model_path = os.path.join(model_dir,nuclear_model)

os.makedirs(os.path.join(run_path,output_location,f"Well{well}"), exist_ok=True)

cell_image = skimage.io.imread(os.path.join(run_path,"Projection",f"Well{well}",f"CP01_{tile}_Cell-Membrane.tif"))
nuclear_image = skimage.io.imread(os.path.join(run_path,"Projection",f"Well{well}",f"CP01_{tile}_Nucleus.tif"))
actin_image = skimage.io.imread(os.path.join(run_path,"Projection",f"Well{well}",f"CP01_{tile}_Actin.tif"))

cell_mask, binary_nuclei = segment_cells(cell_image, nuclear_image, actin_image, cell_model_path, nuclear_model_path, cell_diameter)

skimage.io.imsave(os.path.join(run_path,output_location,f"Well{well}",f"{tile}_Cell.tif"), cell_mask)
skimage.io.imsave(os.path.join(run_path,output_location,f"Well{well}",f"{tile}_Nuclear.tif"), binary_nuclei)

print(f"finished segmenting {tile}")
  1. Select the Run icon to test the workflow.

    The resegmentation output files appears in the output path location.

Cell Assignment

After completing resegmentation, you must also reassign cell barcodes and regenerate the cell table using Cells2Stats with the --segmentation option.