Source code for minian.preprocessing

import cv2
import numpy as np
import xarray as xr
from medpy.filter.smoothing import anisotropic_diffusion
from scipy.ndimage import uniform_filter
from skimage.morphology import disk


[docs]def remove_background(varr: xr.DataArray, method: str, wnd: int) -> xr.DataArray: """ Remove background from a video. This function remove background frame by frame. Two methods are available for use: if `method == "uniform"`, then the background is estimated by convolving the frame with a uniform/mean kernel and then subtract it from the frame. If `method == "tophat"`, then a morphological tophat operation is applied to each frame. Parameters ---------- varr : xr.DataArray The input movie data, should have dimensions "height", "width" and "frame". method : str The method used to remove the background. Should be either `"uniform"` or `"tophat"`. wnd : int Window size of kernels used for background removal, specified in pixels. If `method == "uniform"`, this will be the size of a box kernel convolved with each frame. If `method == "tophat"`, this will be the radius of a disk kernel used for morphological operations. Returns ------- res : xr.DataArray The resulting movie with background removed. Same shape as input `varr` but will have `"_subtracted"` appended to its name. See Also -------- `Morphology <https://docs.opencv.org/4.5.2/d9/d61/tutorial_py_morphological_ops.html>`_ : for details about morphological operations """ selem = disk(wnd) res = xr.apply_ufunc( remove_background_perframe, varr, input_core_dims=[["height", "width"]], output_core_dims=[["height", "width"]], vectorize=True, dask="parallelized", output_dtypes=[varr.dtype], kwargs=dict(method=method, wnd=wnd, selem=selem), ) res = res.astype(varr.dtype) return res.rename(varr.name + "_subtracted")
[docs]def remove_background_perframe( fm: np.ndarray, method: str, wnd: int, selem: np.ndarray ) -> np.ndarray: """ Remove background from a single frame. Parameters ---------- fm : np.ndarray The input frame. method : str Method to use to remove background. Should be either `"uniform"` or `"tophat"`. wnd : int Size of the uniform filter. Only used if `method == "uniform"`. selem : np.ndarray Kernel used for morphological operations. Only used if `method == "tophat"`. Returns ------- fm : np.ndarray The frame with background removed. See Also -------- remove_background : for detailed explanations """ if method == "uniform": return fm - uniform_filter(fm, wnd) elif method == "tophat": return cv2.morphologyEx(fm, cv2.MORPH_TOPHAT, selem)
def stripe_correction(varr, reduce_dim="height", on="mean"): if on == "mean": temp = varr.mean(dim="frame") elif on == "max": temp = varr.max(dim="frame") elif on == "perframe": temp = varr else: raise NotImplementedError("on {} not understood".format(on)) mean1d = temp.mean(dim=reduce_dim) varr_sc = varr - mean1d return varr_sc.rename(varr.name + "_Stripe_Corrected")
[docs]def denoise(varr: xr.DataArray, method: str, **kwargs) -> xr.DataArray: """ Denoise the movie frame by frame. This function wraps around several image processing functions to denoise the data frame by frame. All additional keyword arguments will be passed directly to the underlying functions. Parameters ---------- varr : xr.DataArray The input movie data, should have dimensions "height", "width" and "frame". method : str The method to use to denoise each frame. If `"gaussian"`, then a gaussian filter will be applied using :func:`cv2.GaussianBlur`. If `"anisotropic"`, then anisotropic filtering will be applied using :func:`medpy.filter.smoothing.anisotropic_diffusion`. If `"median"`, then a median filter will be applied using :func:`cv2.medianBlur`. If `"bilateral"`, then a bilateral filter will be applied using :func:`cv2.bilateralFilter`. Returns ------- res : xr.DataArray The resulting denoised movie. Same shape as input `varr` but will have `"_denoised"` appended to its name. Raises ------ NotImplementedError if the supplied `method` is not recognized """ if method == "gaussian": func = cv2.GaussianBlur elif method == "anisotropic": func = anisotropic_diffusion elif method == "median": func = cv2.medianBlur elif method == "bilateral": func = cv2.bilateralFilter else: raise NotImplementedError("denoise method {} not understood".format(method)) res = xr.apply_ufunc( func, varr, input_core_dims=[["height", "width"]], output_core_dims=[["height", "width"]], vectorize=True, dask="parallelized", output_dtypes=[varr.dtype], kwargs=kwargs, ) res = res.astype(varr.dtype) return res.rename(varr.name + "_denoised")