Skip to main content

Performing Resegmentation and Cell Assignment Using Python

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

This tutorial provides steps on 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

The following are required prerequisites for this tutorial:

To install the required Python packages and enable all prerequisites, run the following commands in a command-line interface (CLI) with Anaconda:

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

Re-run Segmentation with a Custom Model

  1. In the CLI terminal with Anaconda, run the following command to open Jupyter Notebook:

    jupyter notebook
  2. To download Element custom Cellpose models, install the Element cytoprofiling package.

  3. Select New, and then select Notebook.

  4. In the drop-down menu, select the resegmentation kernel.

  5. 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

    import warnings
    warnings.filterwarnings("ignore", message=".*weights_only=False.*")
    warnings.filterwarnings("ignore", message=".*low contrast image.*")
  6. To run segmentation, copy the following code into a second cell and update 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 = "/cytoprofiling/Package/Path/segmentationModels"

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

    output_location = "/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,
    resample=False
    )

    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,
    resample=False
    )

    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,
    resample=False
    )

    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,
    resample=False
    )

    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}")
  7. Select the Run icon to test the workflow.

    The resegmentation output files appear in the output path location.

Cell Assignment

After you complete resegmentation, use Cells2Stats with the --segmentation argument to re-assign cell barcodes and re-generate the cell table.