Skip to main content

qsm_core/bgremove/
mod.rs

1//! Background field removal methods
2//!
3//! This module provides methods to separate local from background field:
4//! - SHARP: Sophisticated harmonic artifact reduction for phase data
5//! - RESHARP: Regularized SHARP with Tikhonov regularization
6//! - V-SHARP: Variable kernel SHARP
7//! - PDF: Projection onto dipole fields
8//! - iSMV: Iterative spherical mean value
9//! - LBV: Laplacian boundary value
10//! - SDF: Spatially Dependent Filtering (QSMART)
11//!
12//! mSMV (maximum spherical mean value) is not here: it is part of MEDI-mSMV, which fits its
13//! SMV-filtered field with the SMV-filtered dipole kernel, so its output is not a local field for
14//! the other inversions. See [`crate::inversion::msmv`](mod@crate::inversion::msmv).
15//!
16//! Note: The `smv` module provides simple spherical mean value filtering,
17//! used internally by SHARP, V-SHARP, and iSMV. It is not recommended as
18//! a standalone background removal method (it lacks the deconvolution step
19//! that SHARP provides).
20//!
21//! ## 2D multi-slice data: background removal stays 3D
22//!
23//! Background field removal is **3D** even for 2D multi-slice acquisitions, and so is the
24//! dipole inversion. SHARP and its variants rest on the mean value property of harmonic
25//! functions, which is three-dimensional; a disc has no equivalent, so V-SHARP run slice by
26//! slice would remove only the in-plane component of a field that is not separable that way.
27//! A 2D multi-slice acquisition still assembles into a 3D volume, so there is nothing to
28//! replace here, only anisotropic voxels to handle, which the kernels already do through their
29//! frequency axes. (Phase *unwrapping* is the stage that does go per slice; see
30//! [`crate::unwrap::slicewise`].)
31//!
32//! A 2D V-SHARP stage chained into 3D PDF, as the EPI-QSM literature uses, was implemented,
33//! measured and removed. The numbers are kept here so the case does not have to be
34//! re-implemented to be re-litigated.
35//!
36//! On a synthetic background with every source outside the ROI, where the ground truth is
37//! exactly zero (residual RMS, lower is better):
38//!
39//! | | slab coverage | enclosed ROI |
40//! |---|---|---|
41//! | 2D V-SHARP | 1.18 | 0.47 |
42//! | 3D V-SHARP | 1.69 | **0.14** |
43//! | 2D V-SHARP → 3D PDF | **0.99** | 0.24 |
44//!
45//! On the qsm-forward 2D phantom's `ses-thick` session, correlation against the local field
46//! (higher is better), using the whole head for the enclosed case and a 16-slice slab cut so
47//! the tissue reaches its end slices for the other:
48//!
49//! | | 48 mm slab | enclosed ROI |
50//! |---|---|---|
51//! | 2D V-SHARP | 0.9792 | **0.9597** |
52//! | 3D V-SHARP | **0.9820** | 0.9506 |
53//! | 2D V-SHARP → 3D PDF | 0.9791 | 0.8963 |
54//!
55//! The real-phantom differences are not large enough to decide anything, and on the enclosed
56//! ROI the disc edges the sphere out. What does carry is that the chain, the arrangement
57//! actually proposed for 2D data, is the worst of the three on the enclosed ROI and does not
58//! improve on the 2D stage alone on the slab. Together with the synthetic case, where the
59//! ground truth is exact and 3D wins the enclosed ROI by a factor of three, and with the
60//! theory, there was no demonstrated benefit to ship. The open question is whether a real
61//! acquisition has a slab thin enough relative to a useful kernel radius for the disc to earn
62//! its place; see astewartau/QSM.rs#75.
63//!
64//! A slice **gap** (excited slabs thinner than the slice pitch) is refused rather than
65//! approximated, because the spherical kernels are defined on a uniform grid; see
66//! [`crate::Grid::require_contiguous_slices`].
67
68pub mod smv;
69pub mod sharp;
70pub mod resharp;
71pub mod vsharp;
72pub mod pdf;
73pub mod ismv;
74pub mod lbv;
75pub mod sdf;
76pub mod iharperella;
77#[cfg(feature = "onnx")]
78pub mod bfrnet;
79
80pub use smv::smv;
81pub use sharp::{sharp, SharpParams, SharpVariant};
82pub use resharp::{resharp, ResharpParams};
83pub use vsharp::{vsharp, VsharpBall, VsharpGrid, VsharpParams};
84pub use pdf::{pdf, DipoleKernelSpace, PdfParams};
85pub use ismv::{ismv, IsmvParams, IsmvVariant};
86pub use lbv::{lbv, lbv_multigrid, LbvParams, LbvPrecision};
87pub use sdf::{sdf, sdf_curvature, sdf_simple, SdfParams};
88pub use iharperella::{
89    harperella, iharperella,
90    HarperellaInput, HarperellaParams, IharperellaParams,
91};
92#[cfg(feature = "onnx")]
93pub use bfrnet::{bfrnet, bfrnet_tiled};