Source code for arthropod_describer.plugins.test_plugin.properties.circularity

import copy
import typing
from typing import List, Optional

import numpy as np
import skimage

from arthropod_describer.common.common import Info
from arthropod_describer.common.label_image import RegionProperty, PropertyType
from arthropod_describer.common.photo import Photo
from arthropod_describer.common.plugin import PropertyComputation
from arthropod_describer.common.regions_cache import RegionsCache, Region
from arthropod_describer.common.units import Value, Unit, BaseUnit, SIPrefix
from arthropod_describer.common.user_params import UserParam


[docs]class Circularity(PropertyComputation): """ GROUP: Basic properties NAME: Circularity DESCRIPTION: Circularity (0.0 to 1.0, where 1.0 = perfect circle) KEY: circularity """ def __init__(self, info: Optional[Info] = None): super().__init__(info) def __call__(self, photo: Photo, region_labels: typing.List[int], regions_cache: RegionsCache) -> \ typing.List[RegionProperty]: lab_img = photo['Labels'].label_image reg_props = skimage.measure.regionprops_table(lab_img, photo.image, properties=['label', 'perimeter']) #perimeter_measurement_flavor]) props: List[RegionProperty] = [] for idx, label in enumerate(reg_props['label']): if label not in region_labels: continue perimeter = reg_props['perimeter'][idx]#[perimeter_measurement_flavor][idx] area = int(np.count_nonzero(lab_img == label)) if perimeter == 0: circularity = 0 # TODO: Careful about division by zero (can we somehow return N/A here?) else: circularity = np.clip((4 * np.pi * area) / (perimeter ** 2), 0.0, 1.0) #print(f'idx: {idx}, label: {label}') #print(f' perimeter: {perimeter}') #print(f' area: {area}') #print(f' circularity: {circularity}') prop = RegionProperty() prop.label = int(label) prop.info = copy.deepcopy(self.info) prop.value = Value(float(circularity), self._no_unit) # prop.unit = '' # TODO: Is this ok for a unitless property? prop.prop_type = PropertyType.Scalar prop.val_names = [self.info.name] prop.num_vals = 1 props.append(prop) return props @property def user_params(self) -> List[UserParam]: return super().user_params @property def region_restricted(self) -> bool: return super().region_restricted @property def computes(self) -> typing.Dict[str, Info]: return {self.info.key: self.info}
[docs] def example(self, prop_name: str) -> RegionProperty: prop = RegionProperty() prop.label = 0 prop.info = copy.deepcopy(self.info) # prop.value = int(np.count_nonzero(lab_img == label)) prop.value = Value(0, self._no_unit) prop.prop_type = PropertyType.Scalar prop.val_names = [self.info.name] prop.num_vals = 1 return prop
[docs] def target_worksheet(self, prop_name: str) -> str: return super(Circularity, self).target_worksheet(self.info.key)
@property def group(self) -> str: return super().group