Source code for data_processing.image_analysis.cellpose

from cellpose import models
import pandas as pd
from skimage.measure import regionprops_table
import numpy as np
import torch

from data_processing.image_analysis.base_image_analyzer import ImageAnalysisTemplate
from data_processing.image_analysis.analysis_registry import register_class
from data_processing.image_analysis.pixel_stage_converter import z_normal


[docs] @register_class class Cellpose_algorithm(ImageAnalysisTemplate): """ Class utilizing the Cellpose 3.0 algorithm for finding the objects on transmitted light and filter them by circularity, solidity and eccentricity. """
[docs] @staticmethod def filter_cellpose_masks(df, circ_thr=0.65, ecc_thr=0.5, sol_thr=0.85): """ Function for the filtration of the founded objects. :param df: pandas DF with the founded objects. :param circ_thr: float minimal circularity filtering threshold :param ecc_thr: float maximal eccentricity filtering threshold :param sol_thr: float maximal solidity filtering threshold :return: filtered pandas df """ df['circularity'] = 4 * np.pi * df['area'] / (df['perimeter'] ** 2) mask = ((df['circularity'] > circ_thr) & (df['solidity'] > sol_thr) & (df['eccentricity'] < ecc_thr)) df_filtered = df.loc[mask].copy() return df_filtered
[docs] def image_segmentation(self, objects_diameter=None, circ_thr=0.65, ecc_thr=0.5, sol_thr=0.85): """ Initializing Cellpose algorithm. :param objects_diameter: float size in um, passed to Cellpose model eval :param circ_thr: float minimal circularity filtering threshold :param ecc_thr: float maximal eccentricity filtering threshold :param sol_thr: float maximal solidity filtering threshold :return: pandas df with objects center positions and their properties """ model = models.Cellpose(model_type='cyto', gpu=True) scaling = self.metadata["scaling_um_per_pixel"] if objects_diameter is None: object_pixel_diameter = None else: object_pixel_diameter = int( np.round(objects_diameter / np.mean([scaling['X'] * 10 ** (6), scaling['Y'] * 10 ** (6)]), 0)) masks, flows, styles, diam_mean = model.eval([self.image], diameter=object_pixel_diameter, channels=[0, 0]) props_table = pd.DataFrame(regionprops_table(masks[0], properties=( 'label', 'area', 'centroid', 'perimeter', 'eccentricity', 'solidity'))) filtered_props_table = self.filter_cellpose_masks(props_table, circ_thr, ecc_thr, sol_thr) return filtered_props_table
[docs] def get_measurement_points(self): """ Utilizes methods above for image segmentation and obtains o :return: lists of dictionaries with the founded objects properties and their positions in the pixels coordinates and in the stage coordinates in um. """ objects_df = self.image_segmentation(**{k: v for k, v in self.analysis_details.items() if k in ["objects_diameter", "circ_thr", "ecc_thr", "sol_thr"]}) scaling = self.metadata["scaling_um_per_pixel"] mean_scale = np.mean([scaling["X"] * 10 ** (6), scaling["Y"] * 10 ** (6)]) objects_df["area"] = objects_df["area"] * (mean_scale ** 2) objects_df["radius"] = np.sqrt(objects_df["area"] / np.pi) objects_df['position'] = objects_df[['centroid-1', 'centroid-0']].values.tolist() measurement_points = ( objects_df[['position', 'radius', 'area', 'circularity', 'solidity', 'eccentricity']].to_dict( orient='records')) transformed_points = self.pixel_converter.convert_points(measurement_points, xy_mode='normal', z_strategy=z_normal) return measurement_points, transformed_points