Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New command dwi2noise #3035

Closed
Lestropie opened this issue Nov 10, 2024 · 3 comments
Closed

New command dwi2noise #3035

Lestropie opened this issue Nov 10, 2024 · 3 comments
Assignees
Labels

Comments

@Lestropie
Copy link
Member

Strongly related to #2274.

In the scenario where one fully intends to perform a two-pass operation, one to estimate the noise level and then one to denoise based on a (possibly filtered in an intermediate phase) noise level input map, it would be wasteful to necessitate use of the dwidenoise command for the first step. It would involve reconstructing and writing a denoised DWI series that is to be discarded. Further, there are likely a few command-line options for dwidenoise that would be entirely inapplicable for the first step.

What I'd like to do is move much of the denoising code into src/, and then have two commands, dwi2noise and dwidenoise. The former would be constrained to noise level estimation and exporting of features such as rank. For the second, the noise level for denoising would either be provided via command-line option, or operate using the same mechanism as dwi2noise if not provided.

@Lestropie
Copy link
Member Author

@tsalo Regarding the NORDIC approach of estimating the noise level via no-RF volumes as mentioned in nipreps/fmriprep#3395:

There's already a bit of a misnomer here, the existing dwidenoise command technically doesn't operate exclusively on DWI data as one would expect given the name (which we've been quite pedantic about elsewhere). I think we can nevertheless extend that naming to a dwi2noise in the case where the same PCA-based noise level estimation is happening. However for utilisation of the no-RF volumes for noise level estimation it's probably straying too far away from a "this command operates on DWI data" label. So it might warrant a different command.

Do you have any capability for contributing toward such? I've never seen or acquired no-RF volumes, so don't have any particular vested interest in it, and I've suddenly generated a whole lot of other changes I'd like to make to denoising (#3023); but if there's anyone interested in taking it on I'm happy to assist in doing so within the MRtrix3 API to keep it all together.

@tsalo
Copy link

tsalo commented Dec 11, 2024

@Lestropie I know you closed this since you implemented a dwi2noise command, but I just reviewed the NORDIC code and here's how it seems to work:

  1. Select the first noise volume (noRF volume) from a complex-valued 4D scan, after g-factor correction.
    • I'm almost certain this is a bug and it's supposed to grab all of the noRF volumes.
  2. Replace NaNs in the noRF array with zeros.
  3. Replace Infs in the noRF array with zeros.
  4. Calculate the standard deviation of non-zero elements in the noRF array.
    • This is a single value, not a noise map.
  5. Divide the value by sqrt(2).

@Lestropie
Copy link
Member Author

I figured it was probably something relatively simple like that. I don't know enough about it to know how it is that they derive the g-factor term.

For the rest of it, there doesn't strictly need to be a named command to serve that purpose, it can be done using a one-liner (admittedly a complex one).

  • It takes a little additional fudging because for a complex input image, mrstats yields a complex standard deviation. In the absence of adding a command-line option to mrstats to adjust its handling of complex data (which could totally be done), this snippet extracts the real and imaginary components and concatenates them into a 4D image with 2 volumes, then computes the standard deviation across the whole series.

  • mrstats already skips non-finite values. So rather than setting non-finite values to 0 and then omitting zero values from the calculation (-ignorezero option), it should be possible to just do nothing, and such voxels will automatically get skipped.

mrcalc \
$( \
    mrstats -allvolumes -output std \
    $( \
        mrcat \
        $( \
            mrconvert <fMRI_series> -coord 3 0 - | mrcalc - -real - \
        ) \
        $( \
            mrconvert <fMRI_series> -coord 3 0 - | mrcalc - -imag - \
        ) -axis 3 - \
    ) \
) 2 -sqrt -div

The option of providing as input not a noise map, but just a fixed noise level, should be trivial: #3051. From the data I've been working with I'm a little pessimistic about such an assumption, but there's little harm in having it available.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants