Source code for bimato.core

# Copyright (C) 2022 Tony Fischer
#
# This file is part of Bio Matrix Topology (BiMaTo).
#
# Bio Matrix Topology (BiMaTo) is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Bio Matrix Topology (BiMaTo) is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Bio Matrix Topology (BiMaTo).  If not, see <http://www.gnu.org/licenses/>.

'''The module :mod:`bimato.core` contains some fundamental functions for the `bimato` project. Mainly it contains the
custom binarization technique tailored towards 3D biompolymer network images and others.

See documentation for a general user guide.
'''


__author__ = "Tony Fischer (tku137)"
__copyright__ = "Copyright 2022, Tony Fischer (tku137)"
__license__ = "GPLv3"
__email__ = "tonyfischer@mailbox.org"
__status__ = "Development"
__version__ = "2022.2.1"
__credits__ = ["Tony Fischer (tku137)", "Alexander Hayn"]


from skimage.filters import threshold_local  # pylint: disable=no-name-in-module
from skimage.morphology import binary_closing, disk, ball, remove_small_objects
from scipy.ndimage.morphology import distance_transform_edt as edt

import numpy as np


[docs]def get_binary(data, bw_closing_frac=1024, min_obj_frac=256, win_frac=8, thresh_shift_percentage=0.01, morph_3d=True): '''Function to get a segmentation of input biopolymer network image data. Parameters are optional, but should be considered. Optimal values can vary for drastically differing image data. Notes ----- All Parameters are determined automatically depending on input image properties. However, they can be influenced by specifying a factor. Parameters ---------- data : numpy.ndarray Input image data bw_closing_frac : int Factor for calculation of the ball size during binary closing morphological operations min_obj_frac : int Factor for determining the minimum object size win_frac : int Factor for determining the local adaptive threshold window size thresh_shift_percentage : float Percentage factor in [0,1] specifying the amount the threshold should be shifted morph_3d : bool If morphological operations should be applied in 2D or 3D, default is 3D Returns ------- numpy.ndarray Binary segmentation output ''' # calc the threshold shift thresh_shift = thresh_shift_percentage * data.max() # determine optimal parameters small_edge_size = np.min(data.shape[:2]) # size of the smaller dim of an x-y image threshold_win = 2 * int(small_edge_size / (win_frac * 2)) + 1 # threshold_local window bw_closing_size = int(np.ceil(small_edge_size / bw_closing_frac)) # ball size for morphological closing min_obj_exp = 3 if morph_3d else 2 # wanna morph in 3D or 2D? min_obj = int(np.ceil(small_edge_size / min_obj_frac) ** min_obj_exp) # objects must be this large # per plane adaptive threshold binary = np.zeros_like(data, dtype=np.bool) for z in range(data.shape[2]): # get the local threshold map t = threshold_local(data[..., z], threshold_win) # threshold the image with it binary[..., z] = data[..., z] > (t + thresh_shift) if not morph_3d: # do morphological operation in 2D, because 3D would cut of the bw_closing_size size in z direction! binary[..., z] = binary_closing(binary[..., z], footprint=disk(bw_closing_size)) # morphological closing in 3D if morph_3d: binary = binary_closing(binary, footprint=ball(bw_closing_size)) # remove small objects and holes binary = remove_small_objects(binary, min_size=min_obj) # return binary
[docs]def get_edm(binary, sampling): '''It takes a binary image and a dictionary of sampling rates and returns the Euclidean distance map Parameters ---------- binary : numpy.ndarray a 3D binary array sampling : dict a dictionary with keys 'x', 'y', and 'z' that contain the voxel size in each dimension Returns ------- numpy.ndarray The Euclidean distance map (EDM) of the binary image. ''' edm = edt( np.logical_not(binary), sampling=[sampling['x'], sampling['y'], sampling['z']] ) return edm