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:
- Python v3 or later
- Anaconda Distribution
- Jupyter Notebook
- The following required Python packages:
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
-
In the CLI terminal with Anaconda, run the following command to open Jupyter Notebook:
jupyter notebook -
To download Element custom Cellpose models, 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, transformsimport skimageimport osimport numpy as npimport jsonimport warningswarnings.filterwarnings("ignore", message=".*weights_only=False.*")warnings.filterwarnings("ignore", message=".*low contrast image.*") -
To run segmentation, copy the following code into a second cell and update the following variables:
- Update
run_pathto the run output files folder. - Update
model_dirto the path of your installation of the cytoprofiling repository. - Update
output_locationto your preferred output location for the resegmentation files. - Update
cell_typesandcell_diametersbased on your samples in each well. - To use your own segmenation models, change
model_dirandelement_modelsto point to your model files.
# define the cell type per wellcell_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 typescell_diameters = {"B2":100,"D2":75}# Element Biosciences pre-trained nuclear segmentation modelnuclear_model = "20240629_cellpose_nuc_8diam"# Element Biosciences pre-trained segmentation modelselement_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] = croppedreturn image_normdef 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 = 1nuclear_channel = 2channels = [segment_channel, nuclear_channel]composite = np.zeros((cell_image.shape[0], cell_image.shape[1], 3))composite[:, :, 0] = cell_imagecomposite[:, :, 1] = nuclear_imagecomposite[:, :, 2] = actin_imageprint(f"using {cell_model_path} for cell segmentation")# segment cellsif 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 nucleimodel = 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] = 1return cell_mask, binary_nuclei# load run paramters filewith 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 segmentationfor 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.astype(np.uint16))skimage.io.imsave(os.path.join(run_path,output_location,f"Well{well}",f"{tile}_Nuclear.tif"), binary_nuclei.astype(np.uint8))print(f"finished segmenting {tile}") - Update
-
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.