qsm_core/inversion/iqfm.rs
1//! iQFM single-step deep-learning tissue-field mapping (`onnx` feature).
2//!
3//! iQFM (Gao 2022) is the **local (tissue) field** output of the *same network as
4//! iQSM* — a learnable-Laplacian "LoT" front-end + U-Net that maps raw wrapped MRI
5//! **phase** (radians) straight to the background-removed local field (ppm),
6//! folding phase unwrapping and background-field removal into one network. It is
7//! the `iQFM` head of the authors' repo (weights `iQFM_40_v2.pth` +
8//! `LoTLayer_lfs_40_v2.pth`), the sibling of the χ head used by [`super::iqsm`].
9//!
10//! The exported graph, the four+border inputs, the preprocessing (phase sign,
11//! sphere erosion, centre-pad to /16, mask, crop) and the multi-echo magnitude·TE²
12//! combination are **identical** to iQSM — only the trained weights and the meaning
13//! of the output (local field vs susceptibility) differ. So the Rust glue simply
14//! runs iQSM's exact pipeline with the `iqfm.onnx` bytes.
15//!
16//! Weights are not bundled; the caller passes the exported `iqfm.onnx` bytes.
17
18use crate::grid::Grid;
19use crate::models::onnx::OnnxError;
20
21/// Run iQFM on a single echo of wrapped phase; returns the local field (ppm),
22/// masked, column-major `(nx,ny,nz)`. See [`super::iqsm::iqsm`] for the argument
23/// semantics — they are shared verbatim (only the network and its output differ).
24#[allow(clippy::too_many_arguments)]
25pub fn iqfm(
26 phase_rad: &[f64],
27 mask: &[u8],
28 grid: &Grid,
29 te: f64,
30 b0: f64,
31 phase_sign: f64,
32 eroded_rad: i32,
33 model_onnx: &[u8],
34) -> Result<Vec<f64>, OnnxError> {
35 super::iqsm::iqsm(phase_rad, mask, grid, te, b0, phase_sign, eroded_rad, model_onnx)
36}
37
38/// Multi-echo iQFM: reconstruct each echo and combine with magnitude·TE² weights,
39/// exactly as [`super::iqsm::iqsm_multi_echo`] (the authors' `--echo_4d` path).
40#[allow(clippy::too_many_arguments)]
41pub fn iqfm_multi_echo(
42 phases: &[&[f64]],
43 magnitudes: &[&[f64]],
44 mask: &[u8],
45 grid: &Grid,
46 tes: &[f64],
47 b0: f64,
48 phase_sign: f64,
49 eroded_rad: i32,
50 model_onnx: &[u8],
51) -> Result<Vec<f64>, OnnxError> {
52 super::iqsm::iqsm_multi_echo(
53 phases, magnitudes, mask, grid, tes, b0, phase_sign, eroded_rad, model_onnx,
54 )
55}