Source code for dipy.denoise.non_local_means
from numbers import Number
import numpy as np
from dipy.denoise.nlmeans_block import nlmeans_block
from dipy.testing.decorators import warning_for_keywords
[docs]
@warning_for_keywords()
def non_local_means(
arr, sigma, *, mask=None, patch_radius=1, block_radius=5, rician=True
):
r"""Non-local means for denoising 3D and 4D images, using blockwise
averaging approach.
See :footcite:p:`Coupe2008` and :footcite:p:`Coupe2012` for further details
about the method.
Parameters
----------
arr : 3D or 4D ndarray
The array to be denoised
mask : 3D ndarray
Mask on data where the non-local means will be applied.
sigma : float or ndarray
standard deviation of the noise estimated from the data
patch_radius : int
patch size is ``2 x patch_radius + 1``. Default is 1.
block_radius : int
block size is ``2 x block_radius + 1``. Default is 5.
rician : boolean
If True the noise is estimated as Rician, otherwise Gaussian noise
is assumed.
Returns
-------
denoised_arr : ndarray
the denoised ``arr`` which has the same shape as ``arr``.
References
----------
.. footbibliography::
"""
if isinstance(sigma, np.ndarray) and sigma.size == 1:
sigma = sigma.item()
if isinstance(sigma, np.ndarray):
if arr.ndim == 3:
raise ValueError("sigma should be a scalar for 3D data", sigma)
if not np.issubdtype(sigma.dtype, np.number):
raise ValueError("sigma should be an array of floats", sigma)
if arr.ndim == 4 and sigma.ndim != 1:
raise ValueError("sigma should be a 1D array for 4D data", sigma)
if arr.ndim == 4 and sigma.shape[0] != arr.shape[-1]:
raise ValueError(
"sigma should have the same length as the last "
"dimension of arr for 4D data",
sigma,
)
else:
if not isinstance(sigma, Number):
raise ValueError("sigma should be a float", sigma)
# if sigma is a scalar and arr is 4D, we assume the same sigma for all
if arr.ndim == 4:
sigma = np.array([sigma] * arr.shape[-1])
if mask is None and arr.ndim > 2:
mask = np.ones((arr.shape[0], arr.shape[1], arr.shape[2]), dtype="f8")
else:
mask = np.ascontiguousarray(mask, dtype="f8")
if mask.ndim != 3:
raise ValueError("mask needs to be a 3D ndarray", mask.shape)
if arr.ndim == 3:
return np.array(
nlmeans_block(
np.double(arr), mask, patch_radius, block_radius, sigma, int(rician)
)
).astype(arr.dtype)
elif arr.ndim == 4:
denoised_arr = np.zeros_like(arr)
for i in range(arr.shape[-1]):
denoised_arr[..., i] = np.array(
nlmeans_block(
np.double(arr[..., i]),
mask,
patch_radius,
block_radius,
sigma[i],
int(rician),
)
).astype(arr.dtype)
return denoised_arr
else:
raise ValueError("Only 3D or 4D array are supported!", arr.shape)