Source code for ClearMap.Analysis.Measurements.shape_detection

# -*- coding: utf-8 -*-
"""
ShapeDetection
==============

Module with routines for shape and size detection of objects such as cells.

Note
----
The shape detection is based on a seeded and masked watershed. The module is 
based on the ndimage library. For faster implementation of intensity 
and radial measurements see the modules listed below.

See also
--------
:mod:`ClearMap.Analysis.Measurements.MeasureExpression` and 
:mod:`ClearMap.Analysis.Measurements.MeasureRadius` 
"""
__author__ = 'Christoph Kirst <christoph.kirst.ck@gmail.com>'
__license__ = 'GPLv3 - GNU General Pulic License v3 (see LICENSE.txt)'
__copyright__ = 'Copyright © 2020 by Christoph Kirst'
__webpage__ = 'https://idisco.info'
__download__ = 'https://www.github.com/ChristophKirst/ClearMap2'


import numpy as np

import skimage.morphology
import scipy.ndimage.measurements

import ClearMap.IO.IO as io

import ClearMap.Analysis.Measurements.Voxelization as vox

import ClearMap.Utils.Timer as tmr
import ClearMap.Utils.HierarchicalDict as hdict


##############################################################################
# Cell shape detection
##############################################################################


[docs] def detect_shape(source, seeds, threshold=None, verbose=False, processes=None): """ Detect object shapes by generating a labeled image from seeds. Arguments --------- source : array, str or Source Source image. seeds : array, str or Source Cell centers as point coordinates. threshold : float or None Threshold to determine mask for watershed, pixel below this are treated as background. If None, the seeds are expanded indefinitely. verbose :bool If True, print progress info. Returns ------- shapes : array Labeled image, where each label indicates an object. """ if verbose: timer = tmr.Timer() hdict.pprint(head='Shape detection', threshold=threshold) source = io.as_source(source).array seeds = io.as_source(seeds) mask = None if threshold is None else source > threshold peaks = vox.voxelize(seeds, shape=source.shape, weights=np.arange(1, seeds.shape[0]+1), processes=processes).array try: shapes = skimage.morphology.watershed(-source, peaks, mask=mask) except AttributeError: shapes = skimage.segmentation.watershed(-source, peaks, mask=mask) # shapes = watershed_ift(-source.astype('uint16'), peaks) # shapes[numpy.logical_not(mask)] = 0 if verbose: timer.print_elapsed_time('Shape detection') return shapes
[docs] def find_size(label, max_label=None, verbose=False): """ Find size given object shapes as a labled image Arguments --------- label : array, str or Source Labeled image in which each object has its own label. max_label : int or None Maximal label to include, if None use all label. verbose : bool Print progress info. Returns ------- sizes : array Measured intensities """ if verbose: timer = tmr.Timer() hdict.pprint(head='Size detection:', max_label=max_label) label = io.as_source(label) if max_label is None: max_label = int(label.max()) sizes = scipy.ndimage.measurements.sum(np.ones(label.shape, dtype=bool), labels=label, index=np.arange(1, max_label + 1)) if verbose: timer.print_elapsed_time(head='Size detection') return sizes
[docs] def find_intensity(source, label, max_label=None, method='sum', verbose=False): """ Find integrated intensity given object shapes as labeled image. Arguments --------- source : array, str, or Source Source to measure intensities from. label : array, str, or Source Labeled image with a separate label for each object. max_label : int or None Maximal label to include. If None, use all. method : {'sum', 'mean', 'max', 'min'} Method to use to measure the intensities in each object's area. verbose : bool If True, print progress information. Returns ------- intensities : array Measured intensities. """ method = method.lower() if verbose: timer = tmr.Timer() hdict.pprint(head='Intensity detection:', max_label=max_label, method=method) source = io.as_source(source).array label = io.as_source(label) if max_label is None: max_label = label.max() measure_functions = { 'sum': scipy.ndimage.measurements.sum, 'mean': scipy.ndimage.measurements.mean, 'max': scipy.ndimage.measurements.maximum, 'min': scipy.ndimage.measurements.minimum } try: intensities = measure_functions[method](source, labels=label, index=np.arange(1, max_label + 1)) except KeyError: raise RuntimeError(f'Unknown method {method}, expected one of {measure_functions.keys()}') if verbose: timer.print_elapsed_time(head='Intensity detection') return intensities