Source code for pyfibre.model.tools.filters
import numpy as np
from scipy.ndimage.filters import gaussian_filter
from skimage.feature import structure_tensor
from skimage.filters import (
threshold_li, threshold_isodata, threshold_mean,
apply_hysteresis_threshold, sato)
[docs]def gaussian(image, sigma=None):
"""Perform gaussian smoothing on image using sigma
standard deviation"""
if sigma is None:
return image
return gaussian_filter(image, sigma=sigma)
[docs]def tubeness(image, sigma_max=3):
"""Wrapper around the scikit-image sato tubeness filter"""
tube = sato(
image,
sigmas=range(1, sigma_max+1),
black_ridges=False
)
return tube
[docs]def hysteresis(image, alpha=1.0):
"""Hystersis thresholding with low and high clipped values
determined by the mean, li and isodata threshold"""
low = np.min([
alpha * threshold_mean(image), threshold_li(image)])
high = threshold_isodata(image)
threshold = apply_hysteresis_threshold(image, low, high)
return threshold
[docs]def derivatives(image, rank=1):
"""
Returns derivates of order "rank" for imput image at each pixel
Parameters
----------
image: array_like (float); shape(n_y, n_x)
Image to analyse
rank: int (optional)
Order of derivatives to return (1 = first order, 2 = second order)
Returns
-------
derivative: array_like (float); shape=(2 or 4, n_y, n_x)
First or second order derivatives at each image pixel
"""
derivative = np.zeros(((2,) + image.shape))
derivative[0] += np.nan_to_num(
np.gradient(image, edge_order=1, axis=-2))
derivative[1] += np.nan_to_num(
np.gradient(image, edge_order=1, axis=-1))
if rank == 2:
second_derivative = np.zeros(((4,) + image.shape))
second_derivative[0] += np.nan_to_num(
np.gradient(derivative[0], edge_order=1, axis=-2))
second_derivative[1] += np.nan_to_num(
np.gradient(derivative[1], edge_order=1, axis=-2))
second_derivative[2] += np.nan_to_num(
np.gradient(derivative[0], edge_order=1, axis=-1))
second_derivative[3] += np.nan_to_num(
np.gradient(derivative[1], edge_order=1, axis=-1))
return second_derivative
return derivative
[docs]def form_nematic_tensor(image, sigma=0.0001):
"""
form_nematic_tensor(dx_shg, dy_shg)
Create local nematic tensor n for each pixel in dx_shg, dy_shg
Parameters
----------
image: array_like (float); shape(n_y, n_x)
Image to analyse
sigma: float, optional
Gaussian smoothing standard deviation
Returns
-------
n_vector: array_like (float); shape(nframe, n_y, n_x, 2, 2)
Flattened 2x2 nematic vector for each pixel in
dx_shg, dy_shg (n_xx, n_xy, n_yx, n_yy)
"""
if image.ndim == 2:
image = image.reshape((1,) + image.shape)
nframe = image.shape[0]
dx_shg, dy_shg = derivatives(image)
r_xy_2 = (dx_shg**2 + dy_shg**2)
indicies = np.where(r_xy_2 > 0)
nxx = np.zeros(dx_shg.shape)
nyy = np.zeros(dx_shg.shape)
nxy = np.zeros(dx_shg.shape)
nxx[indicies] += dy_shg[indicies]**2 / r_xy_2[indicies]
nyy[indicies] += dx_shg[indicies]**2 / r_xy_2[indicies]
nxy[indicies] -= dx_shg[indicies] * dy_shg[indicies] / r_xy_2[indicies]
for frame in range(nframe):
nxx[frame] = gaussian_filter(nxx[frame], sigma=sigma)
nyy[frame] = gaussian_filter(nyy[frame], sigma=sigma)
nxy[frame] = gaussian_filter(nxy[frame], sigma=sigma)
n_tensor = np.stack((nxx, nxy, nxy, nyy), -1).reshape(
nxx.shape + (2, 2))
if nframe == 1:
n_tensor = n_tensor.reshape(n_tensor.shape[1:])
return n_tensor
[docs]def form_structure_tensor(image, sigma=0.0001):
"""
form_structure_tensor(image)
Create local structure tensor n for each pixel in image
Parameters
----------
image: array_like (float); shape(n_y, n_x)
Image to analyse
sigma: float, optional
Gaussian smoothing standard deviation
Returns
-------
j_tensor: array_like (float); shape(nframe, n_y, n_x, 2, 2)
2x2 structure tensor for each pixel in image stack
"""
if image.ndim == 2:
image = image.reshape((1,) + image.shape)
nframe = image.shape[0]
jxx = np.zeros(image.shape)
jxy = np.zeros(image.shape)
jyy = np.zeros(image.shape)
for frame in range(nframe):
jxx[frame], jxy[frame], jyy[frame] = structure_tensor(
image[frame], sigma=sigma)
j_tensor = np.stack((jxx, jxy, jxy, jyy), -1).reshape(
jxx.shape + (2, 2))
if nframe == 1:
j_tensor = j_tensor.reshape(j_tensor.shape[1:])
return j_tensor