dipy / dipy

DIPY is the paragon 3D/4D+ imaging library in Python. Contains generic methods for spatial normalization, signal processing, machine learning, statistical analysis and visualization of medical images. Additionally, it contains specialized methods for computational anatomy including diffusion, perfusion and structural imaging.
https://dipy.org
Other
688 stars 431 forks source link

Awkward interaction of dipy.denoise.non_local_means.non_local_means and dipy.denoise.noise_estimate.estimate_sigma #3285

Open MartinKjunior opened 4 days ago

MartinKjunior commented 4 days ago

I was following the ASCM tutorial and ran into an issue when I was trying to run

sigma = estimate_sigma(data, N=4)

den_small = non_local_means(
    data,
    sigma=sigma,
    mask=mask,
    patch_radius=1,
    block_radius=1,
    rician=True)

using a 4D DWI dataset (3D + diffusion directions). non_local_means() docstring says that arr : 3D or 4D ndarray, but the argument sigma only accepts a single value, despite estimate_sigma() returning one value per 3D volume (an array). Therefore, non_local_means() raises an error using

    if not np.isscalar(sigma) and not sigma.shape == (1, ):
        raise ValueError("Sigma input needs to be of type float", sigma)

despite later in the code applying the nlmeans_block() on each 3D volume individually

    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,
                int(rician))).astype(arr.dtype)

, yet you are expected to provide just a single sigma for all volumes. I believe this is an easy fix, if the input is 3D, check that sigma is float, if the input is 4D, check that len(sigma) == arr.shape[-1] and when passing sigma into nlmeans_block(), rewrite sigma -> sigma[i].