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:
- Python v3 or later
- Anaconda Distribution software
- Jupyter Notebook
- The following required Python packages:
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
- In the CLI terminal with Anaconda, run the following command to open Jupyter Notebook.
jupyter notebook
- To download Element Biosciences custom Cellpose models, follow instructions to install the Element cytoprofiling package.
- Select New, and then select Notebook.
- In the drop-down menu, select the resegmentation kernel.
- 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
- 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
andcell_diameters
based on your samples in each well. - To use your own segmenation models, change
model_dir
andelement_models
to point to your model files.
- Update
# 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}")
- 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.