Source code for pyfibre.model.tools.utilities

"""
PyFibre
Image Segmentation Library

Created by: Frank Longford
Created on: 18/02/2019

Last Modified: 18/02/2019
"""

import logging
import numpy as np

from scipy.ndimage.filters import gaussian_filter
from scipy.ndimage.morphology import binary_dilation

from skimage import measure
from skimage.morphology import remove_small_objects, remove_small_holes

logger = logging.getLogger(__name__)


[docs]def bbox_indices(region): """Return indices identifying region bounding box""" minr, minc, maxr, maxc = region.bbox indices = np.mgrid[minr:maxr, minc:maxc] return indices[0], indices[1]
[docs]def bbox_sample(region, metric): """Extract image that lies within region bounding box Parameters ---------- region: skimage.RegionProperties Region defining pixels within image to analyse metric: array-like Metric for all pixels in image to be analysed """ # Identify metrics for pixels within bounding box indices = bbox_indices(region) return metric[indices]
[docs]def smooth_binary(binary, sigma=None): """Smooths binary image based on Gaussian filter with sigma standard deviation""" if sigma is not None: smoothed = gaussian_filter( binary.astype(float), sigma=sigma ) # Convert float image back to binary binary = np.where(smoothed, 1, 0) return binary
[docs]def region_check(region, min_size=0, min_frac=0, edges=False, max_x=0, max_y=0): """Return whether input region passes minimum area and average intensity checks""" check = True if edges: minr, minc, maxr, maxc = region.bbox edge_check = (minr != 0) * (minc != 0) edge_check *= (maxr != max_x) edge_check *= (maxc != max_y) check *= edge_check check *= region.filled_area >= min_size if region._intensity_image is not None: region_filter = (region.image * region.intensity_image) region_frac = region_filter.sum() / region.filled_area check *= (region_frac >= min_frac) return check
[docs]def region_swap(masks, images, min_sizes, min_fracs): """Performs a region_check on each region present in masks using images as intensity image. If check fails, removes region from mask and performs another region_check using same region with other image as intensity image. If this check passes, assigns region onto other mask.""" for i, j in [[0, 1], [1, 0]]: labels = measure.label(masks[i].astype(np.int)) for region_1 in measure.regionprops( labels, intensity_image=images[i]): if not region_check(region_1, min_sizes[i], min_fracs[i]): intensity_image = bbox_sample(region_1, images[j]) masks[i][np.where(labels == region_1.label)] = False region_2 = measure.regionprops( np.array(region_1.image, dtype=int), intensity_image=intensity_image)[0] if region_check(region_2, 0, min_fracs[j]): masks[j][np.where(labels == region_1.label)] = True
[docs]def mean_binary(binaries, image, iterations=1, min_intensity=0, area_threshold=0, sigma=None): """Compares two binary of image and produces a filter based on the overlap""" intensity_map = image * np.mean(binaries, axis=0) intensity_mask = np.where(intensity_map > min_intensity, True, False) # Remove small holes and objects from masks intensity_mask = remove_small_holes( intensity_mask, area_threshold=area_threshold) intensity_mask = remove_small_objects( intensity_mask, min_size=area_threshold) # Dilate image binary = binary_dilation(intensity_mask, iterations=iterations) smooth_binary(binary, sigma) return binary.astype(int)