"""
Classes in this module return filtered images with the same shape as the
required image.
"""
import importlib # skimage
import numpy as np
import cv2
import scipy
from ..img.image import Image
[docs]
class Gauss(Image):
"""Apply Gaussian filter to images using cv2.GaussBlur.
Args:
reqs[0] (Image): Image stack.
param["kernel_size"] (odd integer): GaussianBlur kernel size.
param["split_depth"] (int): File split depth number.
Return:
Image: Filtered Image
"""
[docs]
def set_info(self, param={}):
"""Copy info from reqs[0] and add params.
"""
self.info.copy_req(0)
self.info.add_param("kernel_size", param["kernel_size"], "int",
"GaussianBlur kernel size must be odd.")
self.info.set_split_depth(param["split_depth"])
[docs]
@staticmethod
def process(reqs, param):
"""Apply Gaussian filter to images using cv2.GaussBlur.
Args:
reqs[0] (numpy.ndarray): Numpy 3D array with the shape of
(frame number, height, width).
param["kernel_size"] (odd integer): GaussianBlur kernel size.
Returns:
numpy.ndarray: Filtered image array
"""
img = reqs[0].copy()
for i in range(img.shape[0]):
x = img[i, :, :]
img[i, :, :] = cv2.GaussianBlur(x, (param["kernel_size"],
param["kernel_size"]), 0)
return img
[docs]
class DifferenceOfGaussian(Image):
"""Apply the Difference of Gaussian filter for particle detection.
This filter follows the strategy of TrackMate, where sigma_1 and sigma_2
of the DoG filter are determined from the particle diameter.
See also `trackmate algorithms
<https://imagej.net/plugins/trackmate/algorithms>`_ .
In this class, the particle diameter is set to the size of the Airy disc,
d_psf = (1.22 * wavelength / NA) / pitch.
You can adjust the particle size by multiplying it with ``size_factor``.
The ``wavelength`` parameter should have the same unit with
``length_unit``.
Args:
reqs[0] (Image): Image to apply the filter to. Required parameters;
``length_unit``, ``pitch``.
param["wavelength"] (int): Emission wavelength in length_unit.
param["NA"] (float): Numerical aperture.
param["size_factor"] (float, optional): Particle size factor to
multiply PSF size. Defaults to 1.
param["split_depth"] (int): File split depth number.
Returns:
Image: Filtered image object in ``float32``
"""
[docs]
def set_info(self, param={}):
"""Copy info from reqs[0] and add params.
"""
self.info.copy_req(0)
length_unit = self.info.get_param_value("length_unit")
col = self.info.get_column_dict("intensity")
self.info.delete_column(["intensity"])
self.info.add_column(
col["depth"], col["name"], "float32", col["unit"],
col["description"])
pitch = self.info.get_param_value("pitch")
d_psf_pix = (1.22 * param["wavelength"] / (param["NA"] * pitch))
self.info.add_param(
"d_psf", d_psf_pix, "pix", "PSF diameter")
self.info.add_param(
"wavelength", param["wavelength"], length_unit, "Wavelength")
self.info.add_param(
"NA", param["NA"], "none", "Numerical aperture")
if "size_factor" not in param:
param["size_factor"] = 1
self.info.add_param(
"size_factor", param["size_factor"], "none",
"Particle size factor to multiply PSF size")
particle_size = param["size_factor"] * d_psf_pix
dog_sd1 = particle_size / (1 + np.sqrt(2))
dog_sd2 = np.sqrt(2) * dog_sd1
self.info.add_param(
"dog_sd1", dog_sd1, "pix", "SD of Gauss filter 1")
self.info.add_param(
"dog_sd2", dog_sd2, "pix", "SD of Gauss filter 2")
self.info.set_split_depth(param["split_depth"])
[docs]
@staticmethod
def process(reqs, param):
"""Apply the Difference of Gaussian filter for particle detection.
Args:
reqs[0] (numpy.ndarray): Image to apply the DoG filter to. The
image should have the shape of (frame number, height, width).
param["dog_sd1"] (float): Standard deviation of the first Gaussian
filter.
param["dog_sd2"] (float): Standard deviation of the second Gaussian
filter.
Returns:
numpy.ndarray: Filtered image
"""
img = reqs[0].copy().astype(np.float32)
for i in range(img.shape[0]):
frm = img[i, :, :]
blur1 = scipy.ndimage.gaussian_filter(frm, param["dog_sd1"])
blur2 = scipy.ndimage.gaussian_filter(frm, param["dog_sd2"])
img[i, :, :] = blur1 - blur2
return img
[docs]
class LocalMax(Image):
"""Local maximum filter for particle images.
Get local maximum values by using maximum_filter in SciPy. Surrounding
pixel values except local maximum are set to 0.
Args:
reqs[0] (DifferenceOfGaussian): DoG filtered Image to apply this
filter to. Required params; ``d_psf``.
param["mask_factor"] (float, optional): Mask size factor to multiply
PSF diameter. Defaults to 1.
param["split_depth"] (int): File split depth number.
Returns:
Image: Filtered image object
"""
[docs]
def set_info(self, param={}):
"""Copy info from reqs[0] and add params.
"""
self.info.copy_req(0)
d_psf = self.info.get_param_value("d_psf")
if "mask_factor" not in param:
param["mask_factor"] = 1
self.info.add_param(
"mask_factor", param["mask_factor"], "none",
"Local maximum mask size factor")
mask_size = int(np.ceil(param["mask_factor"] * d_psf))
self.info.add_param(
"mask_size", mask_size, "pix", "Local maximum mask size")
self.info.set_split_depth(param["split_depth"])
[docs]
@staticmethod
def process(reqs, param):
"""Local maximum filter for particle images.
Args:
reqs[0] (numpy.ndarray): DoG filtered Image to apply the
local maximum filter to. The image should have the shape of
(frame number, height, width).
param["mask_size"] (int): Mask size factor to multiply PSF
diameter.
Returns:
numpy.ndarray: Filtered image
"""
skimage = importlib.import_module("skimage")
img = reqs[0].copy().astype(np.float32)
for i in range(img.shape[0]):
frm = img[i, :, :]
max_img = scipy.ndimage.maximum_filter(
frm, footprint=skimage.morphology.disk(param["mask_size"]))
max_img[np.logical_not(max_img == frm)] = 0
img[i, :, :] = max_img
return img
[docs]
class LocalMaxWithDoG(Image):
"""Local max image for particle detection with the Difference of Gaussian.
This class is the combination of
:class:`~slitflow.img.filter.DifferenceOfGaussian` and
:class:`~slitflow.img.filter.LocalMax`.
You can use this class to skip exporting the result of DifferenceOfGaussian
.
Args:
reqs[0] (Image): Image to apply the filter to. Required parameters;
``length_unit``, ``pitch``.
param["wavelength"] (int): Emission wavelength in length_unit.
param["NA"] (float): Numerical aperture.
param["size_factor"] (float, optional): Particle size factor to
multiply PSF size. Defaults to 1.
param["mask_factor"] (float): Mask size factor to multiply PSF
diameter. Defaults to 1.
param["split_depth"] (int): File split depth number.
Returns:
Image: Filtered image object
"""
[docs]
def set_info(self, param={}):
"""Copy info from reqs[0] and add params.
"""
self.info.copy_req(0)
length_unit = self.info.get_param_value("length_unit")
col = self.info.get_column_dict("intensity")
self.info.delete_column(["intensity"])
self.info.add_column(
col["depth"], col["name"], "float32", col["unit"],
col["description"])
pitch = self.info.get_param_value("pitch")
d_psf_pix = (1.22 * param["wavelength"] / (param["NA"] * pitch))
self.info.add_param(
"d_psf", d_psf_pix, "pix", "PSF diameter")
self.info.add_param(
"wavelength", param["wavelength"], length_unit, "Wavelength")
self.info.add_param(
"NA", param["NA"], "none", "Numerical aperture")
if "size_factor" not in param:
param["size_factor"] = 1
self.info.add_param(
"size_factor", param["size_factor"], "none",
"Particle size factor to multiply PSF size")
particle_size = param["size_factor"] * d_psf_pix
dog_sd1 = particle_size / (1 + np.sqrt(2))
dog_sd2 = np.sqrt(2) * dog_sd1
self.info.add_param(
"dog_sd1", dog_sd1, "pix", "SD of Gauss filter 1")
self.info.add_param(
"dog_sd2", dog_sd2, "pix", "SD of Gauss filter 2")
if "mask_factor" not in param:
param["mask_factor"] = 1
self.info.add_param(
"mask_factor", param["mask_factor"], "none",
"Local maximum mask size factor")
mask_size = int(np.ceil(param["mask_factor"] * d_psf_pix))
self.info.add_param(
"mask_size", mask_size, "pix", "Local maximum mask size")
self.info.set_split_depth(param["split_depth"])
[docs]
@staticmethod
def process(reqs, param):
"""Local max image for particle detection with the DoG filtering.
Args:
reqs[0] (numpy.ndarray): Image to apply the filter to. The image
should have the shape of (frame number, height, width).
param["dog_sd1"] (float): Standard deviation of the first Gaussian
filter.
param["dog_sd2"] (float): Standard deviation of the second Gaussian
filter.
param["mask_size"] (int): Mask size factor to multiply PSF
diameter.
Returns:
numpy.ndarray: Filtered image
"""
img = DifferenceOfGaussian.process(reqs, param)
img = LocalMax.process([img], param)
return img