Source code for upxo.propOps.morphops

"""Morphological property helpers for labelled grain structures."""

from math import floor
import numpy as np


[docs] def volumes_with_bincount(label_image, nlabels=None): """Return voxel counts indexed by label ID.""" label_image = np.asarray(label_image) if nlabels is None: nlabels = int(label_image.max()) return np.bincount(label_image.ravel(), minlength=int(nlabels)+1)
[docs] def volume_dict(label_image, labels): """Return ``{label: voxel_count}`` for requested labels.""" counts = volumes_with_bincount(label_image, max(labels)) return {int(label): counts[int(label)] for label in labels}
[docs] def values_array(prop_dict): """Return property dictionary values as an array.""" return np.array(list(prop_dict.values()))
[docs] def gids_with_value(prop_dict, value): """Return one-based IDs whose property equals ``value``.""" vals = values_array(prop_dict) return np.where(vals == value)[0] + 1
[docs] def gids_with_min(prop_dict): """Return IDs whose property equals the minimum value.""" vals = values_array(prop_dict) return np.where(vals == vals.min())[0] + 1
[docs] def gids_with_max(prop_dict): """Return IDs whose property equals the maximum value.""" vals = values_array(prop_dict) return np.where(vals == vals.max())[0] + 1
[docs] def gids_le(prop_dict, threshold): """Return IDs whose property is less than or equal to threshold.""" return np.where(values_array(prop_dict) <= threshold)[0] + 1
[docs] def gids_ge(prop_dict, threshold): """Return IDs whose property is greater than or equal to threshold.""" return np.where(values_array(prop_dict) >= threshold)[0] + 1
[docs] def prop_values_for_gids(prop_dict, gids): """Return floored property values for requested IDs.""" return [floor(prop_dict[gid]) for gid in gids]
[docs] def gids_in_range(prop_dict, low=10, high=15, low_ineq='ge', high_ineq='le'): """Return IDs whose property values fall in the requested range.""" low_ineq = low_ineq if low_ineq in ('ge', 'gt') else 'ge' high_ineq = high_ineq if high_ineq in ('le', 'lt') else 'le' prop = values_array(prop_dict) low_mask = prop >= low if low_ineq == 'ge' else prop > low high_mask = prop <= high if high_ineq == 'le' else prop < high gids = np.argwhere(np.logical_and(low_mask, high_mask)).squeeze() + 1 if gids.ndim == 0: gids = np.expand_dims(gids, 0) return gids
[docs] def voxel_volume(spacing): """Return voxel volume from spacing.""" return np.prod(spacing)
[docs] def voxel_surface_areas(spacing, ret_metric='mean'): """Return voxel face areas for a spacing tuple.""" areas = [spacing[0]*spacing[1], spacing[1]*spacing[2], spacing[2]*spacing[0]] if ret_metric == 'mean': return sum(areas)/3.0 if ret_metric == 'min': return min(areas) if ret_metric == 'max': return max(areas) if ret_metric == 'all': return areas raise ValueError("ret_metric must be 'mean', 'min', 'max' or 'all'.")