OSCR

A Deep Nonlinear Subspace Modeling and Reconstruction for Diffusion-Weighted Imaging Using Denoising Auto-Encoder.

Code ↔ Paper

5 matches between paragraphs of the paper and lines of its authors' code, computed by the harvester (lexical-v1). Click a colored paragraph or line to see its counterpart.

The 5 matches
  1. [1] § Methods › Bias and Precision Analysis ↔ figures/fig5/create_violin_plots.py, lines 350–437 · score 0.87 · Cortico Spinal Tract, Corpus Callosum, CST, CC, crossing, precision
  2. [2] § Methods › Latent‐Space Decoded Reconstruction ↔ sigpy/mri/app.py, lines 723–817 · score 0.75 · coil sensitivity maps, Fourier transform, phase maps, shot phases, SMS, operator
  3. [3] § Methods › Latent‐Space Decoded Reconstruction ↔ code/laser/reconstruction/reconstruction.py, lines 447–555 · score 0.65 · phase encoding, diffusion weightings, multi shot, collapsed, readout, SMS
  4. [4] § Methods › Latent‐Space Decoded Reconstruction ↔ sigpy/mri/muse.py, lines 230–300 · score 0.65 · phase encoding, diffusion weightings, multi shot, collapsed, readout, SMS
  5. [5] § Methods › Reconstruction Comparison ↔ sigpy/mri/app.py, lines 723–817 · score 0.59 · low rank, Shot phases, block, TV, stride, LLR

Paper

Loaded from Europe PMC by your browser, not stored by OSCR: doi.org · Europe PMC

The paper is loaded when this pane is shown.

The authors' code

Python · 1,151 lines · 36 KB · BSD-3-Clause · 2 matches

  1. # -*- coding: utf-8 -*-
  2. """MRI applications.
  3. """
  4. import numpy as np
  5. import sigpy as sp
  6. from sigpy.mri import linop, nlop
  7. from sigpy.mri.dims import *
  8. __all__ = ['SenseRecon', 'L1WaveletRecon', 'TotalVariationRecon',
  9. 'JsenseRecon', 'EspiritCalib', 'HighDimensionalRecon',
  10. 'ModelDiffRecon']
  11. def _estimate_weights(y, weights, coord, coil_dim=0):
  12. if weights is None and coord is None:
  13. with sp.get_device(y):
  14. weights = (sp.rss(y, axes=(coil_dim, ),
  15. keepdims=True) > 0).astype(y.dtype)
  16. if weights is None and coord is not None:
  17. with sp.get_device(y):
  18. weights = (sp.rss(y, axes=(coil_dim, ),
  19. keepdims=True) > 0).astype(y.dtype)
  20. return weights
  21. class SenseRecon(sp.app.LinearLeastSquares):
  22. r"""SENSE Reconstruction.
  23. Considers the problem
  24. .. math::
  25. \min_x \frac{1}{2} \| P F S x - y \|_2^2 +
  26. \frac{\lambda}{2} \| x \|_2^2
  27. where P is the sampling operator, F is the Fourier transform operator,
  28. S is the SENSE operator, x is the image, and y is the k-space measurements.
  29. Args:
  30. y (array): k-space measurements.
  31. mps (array): sensitivity maps.
  32. lamda (float): regularization parameter.
  33. weights (float or array): weights for data consistency.
  34. tseg (None or Dictionary): parameters for time-segmented off-resonance
  35. correction. Parameters are 'b0' (array), 'dt' (float),
  36. 'lseg' (int), and 'n_bins' (int). Lseg is the number of
  37. time segments used, and n_bins is the number of histogram bins.
  38. coord (None or array): coordinates.
  39. device (Device): device to perform reconstruction.
  40. coil_batch_size (int): batch size to process coils.
  41. Only affects memory usage.
  42. comm (Communicator): communicator for distributed computing.
  43. **kwargs: Other optional arguments.
  44. References:
  45. Pruessmann, K. P., Weiger, M., Scheidegger, M. B., & Boesiger, P.
  46. (1999).
  47. SENSE: sensitivity encoding for fast MRI.
  48. Magnetic resonance in medicine, 42(5), 952-962.
  49. Pruessmann, K. P., Weiger, M., Bornert, P., & Boesiger, P. (2001).
  50. Advances in sensitivity encoding with arbitrary k-space trajectories.
  51. Magnetic resonance in medicine, 46(4), 638-651.
  52. """
  53. def __init__(
  54. self,
  55. y,
  56. mps,
  57. lamda=0,
  58. weights=None,
  59. tseg=None,
  60. coord=None,
  61. device=sp.cpu_device,
  62. coil_batch_size=None,
  63. comm=None,
  64. show_pbar=True,
  65. transp_nufft=False,
  66. **kwargs
  67. ):
  68. weights = _estimate_weights(y, weights, coord)
  69. if weights is not None:
  70. y = sp.to_device(y * weights**0.5, device=device)
  71. else:
  72. y = sp.to_device(y, device=device)
  73. A = linop.Sense(
  74. mps,
  75. coord=coord,
  76. weights=weights,
  77. tseg=tseg,
  78. coil_batch_size=coil_batch_size,
  79. comm=comm,
  80. transp_nufft=transp_nufft,
  81. )
  82. if comm is not None:
  83. show_pbar = show_pbar and comm.rank == 0
  84. super().__init__(A, y, lamda=lamda, show_pbar=show_pbar, **kwargs)
  85. class L1WaveletRecon(sp.app.LinearLeastSquares):
  86. r"""L1 Wavelet regularized reconstruction.
  87. Considers the problem
  88. .. math::
  89. \min_x \frac{1}{2} \| P F S x - y \|_2^2 + \lambda \| W x \|_1
  90. where P is the sampling operator, F is the Fourier transform operator,
  91. S is the SENSE operator, W is the wavelet operator,
  92. x is the image, and y is the k-space measurements.
  93. Args:
  94. y (array): k-space measurements.
  95. mps (array): sensitivity maps.
  96. lamda (float): regularization parameter.
  97. weights (float or array): weights for data consistency.
  98. coord (None or array): coordinates.
  99. wave_name (str): wavelet name.
  100. device (Device): device to perform reconstruction.
  101. coil_batch_size (int): batch size to process coils.
  102. Only affects memory usage.
  103. comm (Communicator): communicator for distributed computing.
  104. **kwargs: Other optional arguments.
  105. References:
  106. Lustig, M., Donoho, D., & Pauly, J. M. (2007).
  107. Sparse MRI: The application of compressed sensing for rapid MR imaging.
  108. Magnetic Resonance in Medicine, 58(6), 1082-1195.
  109. """
  110. def __init__(
  111. self,
  112. y,
  113. mps,
  114. lamda,
  115. weights=None,
  116. coord=None,
  117. wave_name="db4",
  118. device=sp.cpu_device,
  119. coil_batch_size=None,
  120. comm=None,
  121. show_pbar=True,
  122. transp_nufft=False,
  123. **kwargs
  124. ):
  125. weights = _estimate_weights(y, weights, coord)
  126. if weights is not None:
  127. y = sp.to_device(y * weights**0.5, device=device)
  128. else:
  129. y = sp.to_device(y, device=device)
  130. A = linop.Sense(
  131. mps,
  132. coord=coord,
  133. weights=weights,
  134. comm=comm,
  135. coil_batch_size=coil_batch_size,
  136. transp_nufft=transp_nufft,
  137. )
  138. img_shape = mps.shape[1:]
  139. W = sp.linop.Wavelet(img_shape, wave_name=wave_name)
  140. proxg = sp.prox.UnitaryTransform(sp.prox.L1Reg(W.oshape, lamda), W)
  141. def g(input):
  142. device = sp.get_device(input)
  143. xp = device.xp
  144. with device:
  145. return lamda * xp.sum(xp.abs(W(input))).item()
  146. if comm is not None:
  147. show_pbar = show_pbar and comm.rank == 0
  148. super().__init__(A, y, proxg=proxg, g=g, show_pbar=show_pbar, **kwargs)
  149. class TotalVariationRecon(sp.app.LinearLeastSquares):
  150. r"""Total variation regularized reconstruction.
  151. Considers the problem:
  152. .. math::
  153. \min_x \frac{1}{2} \| P F S x - y \|_2^2 + \lambda \| G x \|_1
  154. where P is the sampling operator, F is the Fourier transform operator,
  155. S is the SENSE operator, G is the gradient operator,
  156. x is the image, and y is the k-space measurements.
  157. Args:
  158. y (array): k-space measurements.
  159. mps (array): sensitivity maps.
  160. lamda (float): regularization parameter.
  161. weights (float or array): weights for data consistency.
  162. coord (None or array): coordinates.
  163. device (Device): device to perform reconstruction.
  164. coil_batch_size (int): batch size to process coils.
  165. Only affects memory usage.
  166. comm (Communicator): communicator for distributed computing.
  167. **kwargs: Other optional arguments.
  168. References:
  169. Block, K. T., Uecker, M., & Frahm, J. (2007).
  170. Undersampled radial MRI with multiple coils.
  171. Iterative image reconstruction using a total variation constraint.
  172. Magnetic Resonance in Medicine, 57(6), 1086-1098.
  173. """
  174. def __init__(
  175. self,
  176. y,
  177. mps,
  178. lamda,
  179. weights=None,
  180. coord=None,
  181. device=sp.cpu_device,
  182. coil_batch_size=None,
  183. comm=None,
  184. show_pbar=True,
  185. transp_nufft=False,
  186. **kwargs
  187. ):
  188. weights = _estimate_weights(y, weights, coord)
  189. if weights is not None:
  190. y = sp.to_device(y * weights**0.5, device=device)
  191. else:
  192. y = sp.to_device(y, device=device)
  193. A = linop.Sense(
  194. mps,
  195. coord=coord,
  196. weights=weights,
  197. comm=comm,
  198. coil_batch_size=coil_batch_size,
  199. transp_nufft=transp_nufft,
  200. )
  201. G = sp.linop.FiniteDifference(A.ishape)
  202. proxg = sp.prox.L1Reg(G.oshape, lamda)
  203. def g(x):
  204. device = sp.get_device(x)
  205. xp = device.xp
  206. with device:
  207. return lamda * xp.sum(xp.abs(x)).item()
  208. if comm is not None:
  209. show_pbar = show_pbar and comm.rank == 0
  210. super().__init__(
  211. A, y, proxg=proxg, g=g, G=G, show_pbar=show_pbar, **kwargs
  212. )
  213. class JsenseRecon(sp.app.App):
  214. r"""JSENSE/NLINV reconstruction.
  215. Considers the problem
  216. .. math::
  217. \min_{l, r} \frac{1}{2} \| l \ast r - y \|_2^2 +
  218. \frac{\lambda}{2} (\| l \|_2^2 + \| r \|_2^2)
  219. where :math:`\ast` is the convolution operator.
  220. This formulation with regularization corresponds to the version
  221. described in the NLINV paper. Without regularization (which is the
  222. default) this corresponds to the version from the JSENSE paper but using a
  223. truncated Fourier representation of the coils (as in NLINV) instead
  224. of polynomials.
  225. Args:
  226. y (array): k-space measurements.
  227. mps_ker_width (int): sensitivity maps kernel width.
  228. ksp_calib_width (int): k-space calibration width.
  229. lamda (float): regularization parameter.
  230. device (Device): device to perform reconstruction.
  231. weights (float or array): weights for data consistency.
  232. coord (None or array): coordinates.
  233. img_shape (None or list): Image shape.
  234. grd_shape (None or list): Shape of grid.
  235. max_iter (int): Maximum number of iterations.
  236. max_inner_iter (int): Maximum number of inner iterations.
  237. References:
  238. Ying, L., & Sheng, J. (2007).
  239. Joint image reconstruction and sensitivity estimation in SENSE
  240. (JSENSE).
  241. Magnetic Resonance in Medicine, 57(6), 1196-1202.
  242. Uecker, M., Hohage, T., Block, K. T., & Frahm, J. (2008).
  243. Image reconstruction by regularized nonlinear inversion-
  244. joint estimation of coil sensitivities and image content.
  245. Magnetic Resonance in Medicine, 60(#), 674-682.
  246. """
  247. def __init__(
  248. self,
  249. y,
  250. mps_ker_width=16,
  251. ksp_calib_width=24,
  252. lamda=0,
  253. device=sp.cpu_device,
  254. comm=None,
  255. weights=None,
  256. coord=None,
  257. img_shape=None,
  258. grd_shape=None,
  259. max_iter=10,
  260. max_inner_iter=10,
  261. normalize=True,
  262. show_pbar=True,
  263. ):
  264. self.y = y
  265. self.mps_ker_width = mps_ker_width
  266. self.ksp_calib_width = ksp_calib_width
  267. self.lamda = lamda
  268. self.weights = weights
  269. self.coord = coord
  270. self.img_shape = img_shape
  271. self.grd_shape = grd_shape
  272. self.max_iter = max_iter
  273. self.max_inner_iter = max_inner_iter
  274. self.normalize = normalize
  275. self.device = sp.Device(device)
  276. self.comm = comm
  277. self.dtype = y.dtype
  278. self.num_coils = len(y)
  279. if comm is not None:
  280. show_pbar = show_pbar and comm.rank == 0
  281. self._get_data()
  282. self._get_vars()
  283. self._get_alg()
  284. super().__init__(self.alg, show_pbar=show_pbar)
  285. def _get_data(self):
  286. if self.coord is None:
  287. self.img_shape = list(self.y.shape[1:])
  288. ndim = len(self.img_shape)
  289. self.y = sp.resize(
  290. self.y, [self.num_coils] + ndim * [self.ksp_calib_width]
  291. )
  292. if self.weights is not None:
  293. self.weights = sp.resize(
  294. self.weights, ndim * [self.ksp_calib_width]
  295. )
  296. else:
  297. if self.img_shape is None:
  298. self.img_shape = sp.estimate_shape(self.coord)
  299. else:
  300. self.img_shape = list(self.img_shape)
  301. calib_idx = (
  302. np.amax(np.abs(self.coord), axis=-1) < self.ksp_calib_width / 2
  303. )
  304. self.coord = self.coord[calib_idx]
  305. self.y = self.y[:, calib_idx]
  306. if self.weights is not None:
  307. self.weights = self.weights[calib_idx]
  308. if self.weights is None:
  309. self.y = sp.to_device(self.y, self.device)
  310. else:
  311. self.y = sp.to_device(self.weights**0.5 * self.y, self.device)
  312. if self.coord is not None:
  313. self.coord = sp.to_device(self.coord, self.device)
  314. if self.weights is not None:
  315. self.weights = sp.to_device(self.weights, self.device)
  316. self.weights = _estimate_weights(self.y, self.weights, self.coord)
  317. if self.normalize:
  318. xp = self.device.xp
  319. with self.device:
  320. self.y = self.y / xp.linalg.norm(self.y)
  321. def _get_vars(self):
  322. ndim = len(self.img_shape)
  323. mps_ker_shape = [self.num_coils] + [self.mps_ker_width] * ndim
  324. if self.coord is None:
  325. img_ker_shape = [
  326. i + self.mps_ker_width - 1 for i in self.y.shape[1:]
  327. ]
  328. else:
  329. if self.grd_shape is None:
  330. self.grd_shape = sp.estimate_shape(self.coord)
  331. img_ker_shape = [
  332. i + self.mps_ker_width - 1 for i in self.grd_shape
  333. ]
  334. self.img_ker = sp.dirac(
  335. img_ker_shape, dtype=self.dtype, device=self.device
  336. )
  337. with self.device:
  338. self.mps_ker = self.device.xp.zeros(
  339. mps_ker_shape, dtype=self.dtype
  340. )
  341. def _get_alg(self):
  342. def min_mps_ker():
  343. self.A_mps_ker = linop.ConvImage(
  344. self.mps_ker.shape,
  345. self.img_ker,
  346. coord=self.coord,
  347. weights=self.weights,
  348. )
  349. sp.app.LinearLeastSquares(
  350. self.A_mps_ker,
  351. self.y,
  352. self.mps_ker,
  353. lamda=self.lamda,
  354. max_iter=self.max_inner_iter,
  355. show_pbar=False,
  356. ).run()
  357. def min_img_ker():
  358. self.A_img_ker = linop.ConvSense(
  359. self.img_ker.shape,
  360. self.mps_ker,
  361. coord=self.coord,
  362. weights=self.weights,
  363. comm=self.comm,
  364. )
  365. sp.app.LinearLeastSquares(
  366. self.A_img_ker,
  367. self.y,
  368. self.img_ker,
  369. lamda=self.lamda,
  370. max_iter=self.max_inner_iter,
  371. show_pbar=False,
  372. ).run()
  373. self.alg = sp.alg.AltMin(
  374. min_mps_ker, min_img_ker, max_iter=self.max_iter
  375. )
  376. def _output(self):
  377. xp = self.device.xp
  378. # Normalize by root-sum-of-squares.
  379. with self.device:
  380. rss = 0
  381. mps = np.empty([self.num_coils] + self.img_shape, dtype=self.dtype)
  382. for c in range(self.num_coils):
  383. mps_c = sp.ifft(sp.resize(self.mps_ker[c], self.img_shape))
  384. rss += xp.abs(mps_c) ** 2
  385. sp.copyto(mps[c], mps_c)
  386. rss = sp.to_device(rss)
  387. if self.comm is not None:
  388. self.comm.allreduce(rss)
  389. rss = rss**0.5
  390. mps /= rss
  391. return mps
  392. class EspiritCalib(sp.app.App):
  393. """ESPIRiT calibration.
  394. Currently only supports outputting one set of maps.
  395. Args:
  396. ksp (array): k-space array of shape [num_coils, n_ndim, ..., n_1]
  397. calib (tuple of ints): length-2 image shape.
  398. thresh (float): threshold for the calibration matrix.
  399. kernel_width (int): kernel width for the calibration matrix.
  400. max_power_iter (int): maximum number of power iterations.
  401. device (Device): computing device.
  402. crop (int): cropping threshold.
  403. Returns:
  404. array: ESPIRiT maps of the same shape as ksp.
  405. References:
  406. Martin Uecker, Peng Lai, Mark J. Murphy, Patrick Virtue, Michael Elad,
  407. John M. Pauly, Shreyas S. Vasanawala, and Michael Lustig
  408. ESPIRIT - An Eigenvalue Approach to Autocalibrating Parallel MRI:
  409. Where SENSE meets GRAPPA.
  410. Magnetic Resonance in Medicine, 71:990-1001 (2014)
  411. """
  412. def __init__(
  413. self,
  414. ksp,
  415. calib_width=24,
  416. thresh=0.02,
  417. kernel_width=6,
  418. crop=0.95,
  419. max_iter=100,
  420. sets=1,
  421. device=sp.cpu_device,
  422. output_eigenvalue=False,
  423. show_pbar=True,
  424. ):
  425. self.device = sp.Device(device)
  426. self.output_eigenvalue = output_eigenvalue
  427. self.crop = crop
  428. img_ndim = ksp.ndim - 1
  429. num_coils = len(ksp)
  430. with sp.get_device(ksp):
  431. # Get calibration region
  432. calib_shape = [num_coils] + [calib_width] * img_ndim
  433. calib = sp.resize(ksp, calib_shape)
  434. calib = sp.to_device(calib, device)
  435. xp = self.device.xp
  436. with self.device:
  437. # Get calibration matrix.
  438. # Shape [num_coils] + num_blks + [kernel_width] * img_ndim
  439. mat = sp.array_to_blocks(
  440. calib, [kernel_width] * img_ndim, [1] * img_ndim
  441. )
  442. mat = mat.reshape([num_coils, -1, kernel_width**img_ndim])
  443. mat = mat.transpose([1, 0, 2])
  444. mat = mat.reshape([-1, num_coils * kernel_width**img_ndim])
  445. # Perform SVD on calibration matrix
  446. _, S, VH = xp.linalg.svd(mat, full_matrices=False)
  447. VH = VH[S > thresh * S.max(), :]
  448. # Get kernels
  449. num_kernels = len(VH)
  450. kernels = VH.reshape(
  451. [num_kernels, num_coils] + [kernel_width] * img_ndim
  452. )
  453. img_shape = ksp.shape[1:]
  454. # Get covariance matrix in image domain
  455. AHA = xp.zeros(
  456. img_shape[::-1] + (num_coils, num_coils), dtype=ksp.dtype
  457. )
  458. for kernel in kernels:
  459. img_kernel = sp.ifft(
  460. sp.resize(kernel, ksp.shape), axes=range(-img_ndim, 0)
  461. )
  462. aH = xp.expand_dims(img_kernel.T, axis=-1)
  463. a = xp.conj(aH.swapaxes(-1, -2))
  464. AHA += aH @ a
  465. AHA *= sp.prod(img_shape) / kernel_width**img_ndim
  466. self.mps = xp.ones(ksp.shape[::-1] + (1,), dtype=ksp.dtype)
  467. def forward(x):
  468. with sp.get_device(x):
  469. return AHA @ x
  470. def normalize(x):
  471. with sp.get_device(x):
  472. return (
  473. xp.sum(xp.abs(x) ** 2, axis=-2, keepdims=True) ** 0.5
  474. )
  475. alg = sp.alg.PowerMethod(
  476. forward, self.mps, norm_func=normalize, max_iter=max_iter
  477. )
  478. super().__init__(alg, show_pbar=show_pbar)
  479. self.max_eig = np.array([alg.max_eig])
  480. self.sets = sets
  481. if self.sets > 1:
  482. U, S, VH = xp.linalg.svd(AHA, full_matrices=False)
  483. print(U.shape, S.shape, VH.shape)
  484. self.mps = U[..., :self.sets]
  485. self.max_eig = S[..., :self.sets]
  486. # print('self.mps ', self.mps.shape)
  487. # print('self.max_eig ', self.max_eig.shape)
  488. def _output(self):
  489. xp = self.device.xp
  490. with self.device:
  491. mps = []
  492. max_eig = []
  493. for s in range(self.mps.shape[-1]):
  494. # Normalize phase with respect to first channel
  495. c = self.mps.T[s]
  496. c *= xp.conj(c[0] / xp.abs(c[0]))
  497. # Crop maps by thresholding eigenvalue
  498. me = self.max_eig.T[s]
  499. c *= me > self.crop
  500. mps.append( c )
  501. max_eig.append( me )
  502. mps = xp.array(mps)
  503. max_eig = xp.array(max_eig)
  504. if self.output_eigenvalue:
  505. return mps, max_eig
  506. else:
  507. return mps
  508. def _get_regularization(ishape, regu='TIK', lamda=0,
  509. regu_kspace=False,
  510. regu_axes=[-2, -1],
  511. blk_shape=(8, 8),
  512. blk_strides=(8, 8),
  513. normalization=False,
  514. thresh='soft',
  515. deep_model=None,
  516. ro_extend_fold=1):
  517. """
  518. This function constructs regularization terms.
  519. Author:
  520. Zhengguo Tan <[email hidden]>
  521. """
  522. idx = []
  523. for n in range(-len(ishape), -1, 1):
  524. idx.append(slice(0, ishape[n], 1))
  525. Nx_ext = ishape[-1]
  526. Nx = Nx_ext // ro_extend_fold
  527. Slices = []
  528. for n in range(ro_extend_fold):
  529. idn = idx.copy()
  530. idn.append(slice(n * Nx, (n+1) * Nx, 1))
  531. Slices.append(sp.linop.Slice(ishape, tuple(idn)))
  532. trafos = sp.linop.Vstack(Slices, axis=0)
  533. if regu_kspace is True:
  534. trafos = sp.linop.FFT(trafos.oshape, axes=[-2, -1]) * trafos
  535. else:
  536. trafos = sp.linop.Identity(trafos.oshape) * trafos
  537. if regu == 'TIK':
  538. proxg = None
  539. strength = lamda
  540. elif regu == 'LLR':
  541. blk_shape = list(blk_shape)
  542. blk_strides = list(blk_strides)
  543. for ind in range(len(blk_shape)):
  544. if ishape[ind-2] <= blk_shape[ind-2]:
  545. blk_shape[ind-2] = ishape[ind-2] // 3
  546. blk_strides[ind-2] = ishape[ind-2] // 3
  547. proxg = sp.prox.LLRL1Reg(trafos.oshape, lamda,
  548. blk_shape=blk_shape,
  549. blk_strides=blk_strides,
  550. normalization=normalization)
  551. # the lamda is passed into prox,
  552. # so no need for strength here.
  553. strength = 0
  554. elif regu == 'SLR':
  555. blk_shape = list(blk_shape)
  556. blk_strides = list(blk_strides)
  557. proxg = sp.prox.SLRMCReg(trafos.oshape, lamda,
  558. blk_shape=blk_shape,
  559. blk_strides=blk_strides,
  560. thresh=thresh, verbose=True)
  561. strength = 0
  562. elif regu == 'TV':
  563. T = sp.linop.FiniteDifference(trafos.oshape, axes=regu_axes)
  564. trafos = T * trafos
  565. proxg = sp.prox.L1Reg(trafos.oshape, lamda)
  566. strength = 0
  567. elif (regu == 'DAE') and (deep_model is not None):
  568. proxg = sp.prox.DAEReg(trafos.oshape, lamda, deep_model)
  569. strength = 0
  570. g = None
  571. # TODO: It is difficult to define g here, because
  572. # proxg functions like SLR and LLR contain linear transformations
  573. # inside their prox implementation.
  574. # if proxg is None:
  575. # g = None
  576. # else:
  577. # def g(input):
  578. # device = sp.get_device(input)
  579. # xp = device.xp
  580. # with device:
  581. # return lamda * xp.sum(xp.abs(input)).item()
  582. return trafos, proxg, g, strength
  583. class HighDimensionalRecon(sp.app.LinearLeastSquares):
  584. r"""High-Dimensional MRI Reconstruction.
  585. Considers the problem
  586. .. math::
  587. \min_x \frac{1}{2} \| P F S M x - y \|_2^2 +
  588. \frac{\lambda}{2} R(x)
  589. where P is the sampling operator,
  590. F is the Fourier transform operator,
  591. S is the SENSE operator (multiplication with coil sensitivity maps),
  592. M is the modeling operator, which can be
  593. - subspace matrix,
  594. - phase matrix,
  595. - etc.
  596. x is the subspace coefficient maps, and
  597. y is the k-space measurements.
  598. R(x) is the regularization term.
  599. (1) TIK: Tikhonov L2.
  600. R(x) = \| x \|_2^2
  601. (2) LLR: Locally Low Rank.
  602. R(x) = \| G(x) \|_1,
  603. where G is the transformation function.
  604. (3) SLR: Structured Low Rank.
  605. (4) TV: total variation.
  606. Args:
  607. y (array): measured k-space data.
  608. mps (array): coil sensitivity maps.
  609. weights (array): forward model weighting.
  610. coord (array): k-space non-Cartesian trajectory.
  611. model_water_fat (bool): model water/fat 2-compartment signal. [default: False]
  612. B0 (float): B0 field strength (T). [default: 3.0]
  613. TE (1D array): echo time array (ms).
  614. basis (2D array): temporal subspace matrix.
  615. phase_shot (array): shot-to-shot phase maps.
  616. combine_shot (bool): reconstructed images (x) are shot-combined,
  617. i.e., x.shape[DIM_SEG] = 1. [default: False]
  618. phase_echo (array): echo-to-echo phase maps.
  619. combine_echo (bool): reconstructed images (x) are echo-combined,
  620. i.e., x.shape[DIM_ECHO] = 1. [default: False]
  621. phase_sms (array): multi-band phase maps.
  622. scale (float): scaling factor of y. [default: 0 - no scaling]
  623. regu (str): regularization type.
  624. [choices: 'TIK' (default), 'LLR', 'TV']
  625. regu_kspace (bool): regularize the FFT of x. [default: False]
  626. This is meant for structural low-rank regularization
  627. regu_axes (list of int): on which axes the regularization is applied.
  628. [default: [-2, -1]]
  629. x (array): initialization.
  630. blk_shape (list of int): block shape in LLR. [default: [8, 8]]
  631. blk_strides (list of int): block strides in LLR. [default: [8, 8]]
  632. normalization (bool): apply normalization in LLR. [default: False]
  633. thresh (str): threshold type. [choices: 'soft' (default), 'hard']
  634. max_iter (int): maximal number of iterations (ADMM outer iterations). [default: 50]
  635. max_cg_iter (int): maximal number of CG iterations. [default: 30]
  636. solver (str): solver. [choices: 'ADMM', None]
  637. ro_extend_fold (int): reconstruct SMS data using the readout-extended-FOV concept.
  638. Please refer to https://doi.org/10.1002/mrm.25897 and sigpy.mri.muse.
  639. device (Device): [choices: sp.Device(0) - GPU, sp.Device(-1) - CPU]
  640. **kwargs: ...
  641. Author:
  642. Zhengguo Tan <[email hidden]>
  643. References:
  644. * Lustig M, Donoho DL, Pauly JM.
  645. Sparse MRI: The application of compressed sensing for rapid MRI.
  646. Magn Reson Med 2007;58:1182-1195.
  647. * Block KT, Uecker M, Frahm J.
  648. Undersampled radial MRI with multiple coils.
  649. Iterative image reconstruction using a total variation constraint.
  650. Magn Reson Med 2007;57:1086-1098.
  651. * Lustig M, Donoho DL, Santos JM, Pauly JM.
  652. Compressed sensing MRI.
  653. IEEE Signal Process Mag 2008;25:72-82.
  654. """
  655. def __init__(self, y, mps, lamda=0,
  656. weights=None, coord=None,
  657. model_water_fat: bool = False,
  658. B0: float = 3.0, TE=None,
  659. basis=None,
  660. phase_shot=None, combine_shot=False,
  661. phase_echo=None, combine_echo=False,
  662. phase_sms=None,
  663. scale=0, regu='TIK', regu_kspace=False,
  664. regu_axes=[-2, -1], x=None,
  665. blk_shape=(8, 8), blk_strides=(8, 8),
  666. normalization=False,
  667. deep_model=None,
  668. thresh='soft', max_iter=50,
  669. ro_extend_fold=1, solver=None,
  670. device=sp.cpu_device, show_pbar=True,
  671. **kwargs):
  672. if y.ndim == 6:
  673. y = y[:, :, None, :, :, :, :]
  674. print('> reshape y to 7 dimensions: ', y.shape)
  675. if weights is not None and weights.ndim == 6:
  676. weights = weights[:, :, None, :, :, :, :]
  677. print('> reshape weights to 7 dimensions: ', weights.shape)
  678. # k-space data in accordance with sigpy/mri/dims.py
  679. Ntime, Nseg, Necho, Ncoil, Nz = y.shape[:-2]
  680. Ny, Nx = mps.shape[-2:]
  681. assert(1 == Nz) # deal with collapsed y even for SMS
  682. if phase_sms is not None:
  683. MB = phase_sms.shape[DIM_Z]
  684. else:
  685. MB = 1
  686. # start to construct image shape
  687. img_shape = [1] + [MB] + [Ny] + [Nx]
  688. if model_water_fat is True:
  689. zm = nlop.calc_fat_modu(np.array(TE) * 1e-3, B0=B0)
  690. zm = sp.to_device(zm, device)
  691. N_zm_echo, N_zm_parm = zm.shape
  692. ishape = [N_zm_parm] + img_shape
  693. else:
  694. if combine_echo is True:
  695. ishape = [1] + img_shape
  696. else:
  697. ishape = [Necho] + img_shape
  698. if combine_shot is True:
  699. ishape = [1] + ishape
  700. else:
  701. ishape = [Nseg] + ishape
  702. if basis is not None:
  703. N_basis_contrast, N_basis_coef = basis.shape
  704. assert(N_basis_contrast == Ntime)
  705. ishape = [N_basis_coef] + ishape
  706. else:
  707. ishape = [Ntime] + ishape
  708. # %% construct MRI forward model
  709. #### case 0. water/fat modeling
  710. if model_water_fat is True:
  711. T1 = sp.linop.Transpose(ishape, [-5, -6, -7, -4, -3, -2, -1])
  712. R1 = sp.linop.Reshape([T1.oshape[0], np.prod(T1.oshape[1:])], T1.oshape)
  713. MM = sp.linop.MatMul(R1.oshape, zm)
  714. R2 = sp.linop.Reshape([N_zm_echo] + list(T1.oshape[1:]), MM.oshape)
  715. T2 = sp.linop.Transpose(R2.oshape, [-5, -6, -7, -4, -3, -2, -1])
  716. WF = T2 * R2 * MM * R1 * T1
  717. else:
  718. WF = sp.linop.Identity(ishape)
  719. #### case 1. subspace modeling
  720. if basis is not None:
  721. sub_ishape = [N_basis_coef] + [np.prod(WF.oshape[1:])]
  722. # TODO: may require more Reshape linops to split between time and echo
  723. sub_oshape = [Ntime] + list(WF.oshape[1:])
  724. B1 = sp.linop.Reshape(sub_ishape, WF.oshape)
  725. B2 = sp.linop.MatMul(B1.oshape, basis)
  726. B3 = sp.linop.Reshape(sub_oshape, B2.oshape)
  727. B = B3 * B2 * B1
  728. else:
  729. B = sp.linop.Identity(WF.oshape)
  730. #### case 2. echo phase modeling
  731. if phase_echo is not None:
  732. assert Necho == phase_echo.shape[DIM_ECHO]
  733. ECO = sp.linop.Multiply(B.oshape, phase_echo)
  734. else:
  735. # assert Necho == 1
  736. ECO = sp.linop.Identity(B.oshape)
  737. #### case 3. shot/segment phase modeling
  738. if phase_shot is not None:
  739. assert Nseg == phase_shot.shape[DIM_SEG]
  740. SEG = sp.linop.Multiply(ECO.oshape, phase_shot)
  741. else:
  742. SEG = sp.linop.Identity(ECO.oshape)
  743. #### parallel imaging modeling
  744. # only one set of coil sensitivity maps for all images
  745. assert(y.shape[DIM_COIL] == mps.shape[DIM_COIL])
  746. S = sp.linop.Multiply(SEG.oshape, mps)
  747. # FFT
  748. if coord is None:
  749. self._check_two_shape(list(y.shape[DIM_Y:]), mps.shape[DIM_Y:])
  750. F = sp.linop.FFT(S.oshape, axes=range(-2, 0))
  751. else:
  752. F = sp.linop.HDNUFFT(S.oshape, coord)
  753. # SMS
  754. if phase_sms is not None:
  755. self._check_two_shape(list(phase_sms.shape), mps.shape[DIM_Z:])
  756. PHI = sp.linop.Multiply(F.oshape, phase_sms)
  757. SUM = sp.linop.Sum(PHI.oshape, axes=(DIM_Z, ), keepdims=True)
  758. M = SUM * PHI
  759. else:
  760. M = sp.linop.Identity(F.oshape)
  761. # compute k-space sampling mask
  762. if weights is None:
  763. weights = _estimate_weights(y, weights, coord, coil_dim=DIM_COIL)
  764. y = sp.to_device(y * weights, device=device)
  765. W = sp.linop.Multiply(M.oshape, weights)
  766. # sum along the echo dimension
  767. if Necho == 1 and phase_echo is not None:
  768. SUM = sp.linop.Sum(W.oshape, axes=(DIM_ECHO, ),
  769. keeydims=True)
  770. else:
  771. SUM = sp.linop.Identity(W.oshape)
  772. #### chain models
  773. A = SUM * W * M * F * S * SEG * ECO * B * WF
  774. print('>>> A oshape: ', A.oshape, ' ishape: ', A.ishape)
  775. # %% scale y
  776. if scale == 0:
  777. device = sp.get_device(y)
  778. xp = device.xp
  779. with device:
  780. x0 = A.H(y)
  781. x1 = np.linalg.norm(x0, axis=0)
  782. x2 = np.linalg.norm(x1, axis=0)
  783. x1 = xp.sort(x2.flatten())
  784. x_med = abs(x1[len(x1)//2])
  785. x_p90 = abs(x1[int(len(x1) * 0.9)])
  786. x_max = abs(x1[-1])
  787. if (x_max - x_p90) < 2 * (x_p90 - x_med):
  788. scale = x_p90
  789. else:
  790. scale = x_max
  791. # print('scale: ' + str(scale))
  792. y /= scale
  793. # %% initialization
  794. if x is not None:
  795. x = sp.to_device(x, device=device)
  796. # %% regularization
  797. trafos, proxg, g, strength = _get_regularization(
  798. A.ishape, regu=regu, lamda=lamda,
  799. regu_kspace=regu_kspace, regu_axes=regu_axes,
  800. blk_shape=blk_shape, blk_strides=blk_strides,
  801. normalization=normalization,
  802. thresh=thresh, deep_model=deep_model,
  803. ro_extend_fold=ro_extend_fold)
  804. if solver == 'ADMM':
  805. show_pbar = False
  806. super().__init__(A, y, x=x, lamda=strength,
  807. G=trafos, proxg=proxg, g=g, scale=scale,
  808. max_iter=max_iter, solver=solver,
  809. show_pbar=show_pbar, **kwargs)
  810. def _check_two_shape(self, ref_shape, dst_shape):
  811. for i1, i2 in zip(ref_shape, dst_shape):
  812. if (i1 != i2):
  813. raise ValueError('shape mismatch for ref {ref}, got {dst}'.format(
  814. ref=ref_shape, dst=dst_shape))
  815. class ModelDiffRecon(sp.app.NonLinearLeastSquares):
  816. r"""Model-based Diffusion Reconstruction.
  817. Consider the problem
  818. .. math::
  819. \min_x \frac{1}{2} \| P F S B x - y \|_2^2 +
  820. \frac{\lambda}{2} R(x)
  821. where P is the sampling operator,
  822. F is the Fourier transform operator,
  823. S is the SENSE operator (multiplication with coil sensitivity maps),
  824. B is the non-linear diffusion model,
  825. x is the diffusion model parameters, [b0, DTI or DKI], and
  826. y is the k-space measurements.
  827. Therefore, The operation B x outputs
  828. non-diffusion-weighted image (b0) and
  829. diffusion-weighted images (DWI).
  830. Args:
  831. y (array): Observation.
  832. image_shape (list): Shape of Solution.
  833. coil (array): Coil sensitivity maps.
  834. coil_dim (int): Dimension of coil sensitivity in y.
  835. coord (array): Sampling trajectory.
  836. x (array): Solution.
  837. x0 (array): Bias for regularization.
  838. dwi_phase (array): Phase of diffusion weighted images.
  839. weights (array): Sampling pattern.
  840. encode_matrix (array): Diffusion encoding matrix (B).
  841. max_iter (int): Maximum number of iterations.
  842. lamda (float): Regularization strength (\rho in ADMM).
  843. redu (float): Reduction factor along iterations.
  844. gn_iter (int): Gauss-Newton iterations.
  845. inner_iter (int): Inner iterations.
  846. inner_tol (float): Inner tolerance.
  847. G (None or Linop): Regularization linear operator.
  848. proxg (None or Prox): Proximal operator for regularization.
  849. device (Device): Use CPU or GPU.
  850. Author:
  851. Zhengguo Tan <[email hidden]>
  852. References:
  853. Welsh C. L., DiBella E. V. R., Adluru G., Hsu E. W. (2013).
  854. Model-based reconstruction of undersampled diffusion tensor k-space data.
  855. Magn. Reson. Med., 70, 429-440.
  856. Knoll F., Raya J. G., Halloran R. O., Baete S., Sigmund E., Bammer R., Block K. T., Otazo R., Sodickson D. K. (2015).
  857. A model-based reconstruction for undersampled radial spin-echo DTI with variational penalties on the diffusion tensor.
  858. Magn. Reson. Med., 28, 353-366.
  859. Dong Z., Dai E., Wang F., Zhang Z., Ma X., Yuan C., Guo H. (2018).
  860. Model-based reconstruction for simultaneous multislice and parallel imaging accelerated multishot DTI.
  861. Med. Phys., 45, 3196-3204.
  862. """
  863. def __init__(self, y, image_shape,
  864. coil=None, coil_dim=-3, coord=None,
  865. x=None, x0=None,
  866. dwi_phase=None, weights=None,
  867. encode_matrix=None,
  868. max_iter=6, lamda=1, redu=2,
  869. gn_iter=6, inner_iter=100, inner_tol=0.01,
  870. G=None, proxg=None,
  871. device=sp.cpu_device,
  872. **kwargs):
  873. y = sp.to_device(y, device=device)
  874. xp = device.xp
  875. with device:
  876. weights = _estimate_weights(y, weights, coord, coil_dim=coil_dim)
  877. A = nlop.Diffusion(image_shape, encode_matrix, coil,
  878. dwi_phase=dwi_phase, weights=weights)
  879. if x is None:
  880. with device:
  881. x_b0 = xp.ones([1] + list(image_shape[1:]), dtype=y.dtype) * 1E-5
  882. x_D = xp.zeros([image_shape[0]-1] + list(image_shape[1:]), dtype=y.dtype)
  883. x = xp.concatenate((x_b0, x_D))
  884. else:
  885. with device:
  886. x = sp.to_device(x, device=device)
  887. if x0 is None:
  888. with device:
  889. x0 = 0.9 * x
  890. else:
  891. with device:
  892. x0 = sp.to_device(x0, device=device)
  893. super().__init__(A, y, x=x, x0=x0,
  894. max_iter=max_iter,
  895. lamda=lamda, redu=redu,
  896. gn_iter=gn_iter,
  897. inner_iter=inner_iter,
  898. inner_tol=inner_tol,
  899. G=G, proxg=proxg,
  900. **kwargs)

app.py at commit b757125, under BSD-3-Clause · at the source

Overview

  1. Institute of Radiology, University Hospital Erlangen, Friedrich‐Alexander‐Universität Erlangen‐Nürnberg, Erlangen, Germany
  2. Michigan Institute for Imaging Technology and Translation (MIITT), Radiology, University of Michigan, Ann Arbor, Michigan, USA
  3. Department Artificial Intelligence in Biomedical Engineering (AIBE), Friedrich‐Alexander‐Universität Erlangen‐Nürnberg, Erlangen, Germany
Journal: Magnetic resonance in medicine, volume 96, issue 5, pages 2359-2369
Dates: received 19 December 2025; accepted 20 June 2026; published online 4 August 2026; in print November 2026
Type: Other · Language: English
License: CC BY
Identifiers: DOI 10.1002/mrm.70496 · PMID 42548198 · PMCID PMC13527252 · OpenAlex W7172408551
Open access: hybrid, a free copy (OpenAlex)
Status: code verified
Categories: structural MRI / diffusion (modality), human (organism), methods / tools (subfield)
Methods: Statistics, fMRI & imaging, Physiology & signal measures
Keywords: deep learning, deep nonlinear subspace, denoising auto‐encoder, diffusion weighted magnetic resonance imaging, joint reconstruction
MeSH: Brain*, Diffusion Magnetic Resonance Imaging*, Image Processing, Computer-Assisted*, Algorithms, Autoencoder, Humans, Nonlinear Dynamics, Signal-To-Noise Ratio (* major topic)
Topic: Advanced Neuroimaging Techniques and Applications (Radiology, Nuclear Medicine and Imaging, Medicine), according to OpenAlex
Funding: Deutsche Forschungsgemeinschaft (513220538, 440719683, 512819079, 500888779); Friedrich-Alexander-Universität Erlangen-Nürnberg (b143dc)
Citations: not cited yet (Europe PMC); 45 references in the paper

Abstract

Purpose: To present a novel, nonlinear subspace modeling and joint k–q‐space reconstruction technique for high‐resolution, multi‐band, multi‐shell diffusion‐weighted imaging (DWI).

Methods: High b‐value (> 1000 s/mm2), high resolution DWI has the drawback of generally low signal‐to‐noise ratios (SNRs). We present an approach that leverages a denoising autoencoder (DAE) to learn a latent subspace from biophysically simulated diffusion‐weighted signals. The decoder of this network is then used in the forward operator of the image reconstruction process. The decoded latent images are scaled by the b0 image, phase is added and processed as regular DWI images with the forward operator for multi‐shot, multicoil, multi‐slice, k–q‐undersampled acquisition schemes. The performance is investigated with a multi‐shell, multi‐direction imaging brain scan and compared to the results of the multiplexed sensitivity‐encoding (MUSE) reconstruction and locally low‐rank (LLR) regularized reconstruction. The results are further validated by a bias and precision analysis of reconstructed fiber directions.

Results: Comparing the reconstructed data using the proposed method shows improved noise suppression compared to MUSE and more details than LLR‐reconstructed images. Specifically, in the higher b‐value domain, the reconstruction results show improved detectability of small structures. This bias and precision analysis showed minimal bias introduction, but higher precision with the proposed method.

Conclusion: Our method combines deep learning, latent signal modeling, joint k–q‐space reconstruction, and biophysical simulation for diffusion data and shows strong noise suppression and a high degree of detail in reconstructed diffusion‐weighted images.

Reproduced under the paper's license (CC BY), from the paper cited above.

Repositories

Its files are read in the Code ↔ Paper reader above, with 5 matches between paragraphs and lines of code.

ZhengguoTan/sigpy

License: BSD-3-Clause
State: the link answers, verified on 27 September 2026
Evidence: files inventoried
Commit: b7571257012512926172df00e66537fc618d90b7, 22 September 2026
Languages: Python (100), Shell (3)
Size: 142 files, 103 scripts
Software Heritage: not archived
Found in: the text, “ENDNOTES”
Holds: README, license file, environment (pyproject.toml, requirements.txt, setup.cfg, setup.py, conda.recipe/conda_build_config.yaml, docs/requirements.txt), tests, continuous integration, documentation
Not found: CITATION.cff
Tools: NumPy (83 files), CuPy (11 files), PyTorch (8 files), SciPy (7 files), Numba (6 files), Matplotlib (3 files), PyWavelets (2 files), h5py (1 file), pydicom (1 file)
Availability: 1 check, the latest on 27 September 2026: the link answers
  • 27 September 2026: the link answers
105 files

JuliusGlaser/LASER

License: none: the authors keep all their rights
State: the link answers, verified on 27 September 2026
Evidence: files inventoried
Commit: dbc143a981c36efb75f4215ae1e62e9e7fe5fc10, 4 February 2026
Languages: Python (36), Jupyter (2)
Size: 85 files, 38 scripts
Software Heritage: not archived
Found in: “Data Availability Statement”
Holds: README, environment (code/pyproject.toml, code/requirements.txt), 2 notebooks
Not found: license file, CITATION.cff, tests, continuous integration, documentation
Tools: NumPy (27 files), h5py (18 files), PyTorch (13 files), Matplotlib (8 files), DIPY (5 files), NiBabel (5 files), CuPy (3 files), MRtrix3 (1 file), Numba (1 file), Pillow (1 file), SciPy (1 file)
Availability: 1 check, the latest on 27 September 2026: the link answers
  • 27 September 2026: the link answers
39 files

The paper's code and data availability statement is in the Data section.

Tracing map

Proposed by the machine: these links were found in the paper and verified at the source, without human review. The map will receive a Zenodo DOI once one of the paper's authors has validated it with their ORCID.

What the map holds:

  • 2 repositories of the authors' code, each at its verified commit, with its license and how the link was found in the paper;
  • 141 scripts, each with its path and the digest of its content;
  • 5 matches between paragraphs of the paper and lines of the code (method lexical-v1);
  • neither the text of the paper nor the code itself.

Its JSON (tracing-map.json) is deposited on Zenodo with its DOI once the map is validated.

Data

No dataset and no data link were found in the paper.

Data Availability Statement

The data that support the findings of this study are available on request from the corresponding author. The data are not publicly available due to privacy or ethical restrictions. Our source code is a publicly available under https://github.com/JuliusGlaser/LASER.

Reproduced under the paper's license (CC BY), from the paper cited above.

Versions

The history of this record: each version stored by the harvester or made by a correction of its authors or of the maintainers of its code, and what changed in its facts. The texts of the paper (its abstract, its availability statements) are not part of it; versions that changed only those are not listed.

Version 3, 28 September 2026

  • Publisher: n/a → Wiley

Version 1, 27 September 2026: the first record

Recorded: type, language, journal, volume, issue, pages, dates, 5 authors, 5 keywords, 8 MeSH terms, 2 funders, 38 references.

Cite

This paper

Glaser, J., Tan, Z., Hofmann, A., Laun, F. B., & Knoll, F. (2026). A Deep Nonlinear Subspace Modeling and Reconstruction for Diffusion-Weighted Imaging Using Denoising Auto-Encoder. Magnetic resonance in medicine, 96(5), 2359-2369. https://doi.org/10.1002/mrm.70496

BibTeX

@article{glaser2026deep,
author = {Glaser, Julius and Tan, Zhengguo and Hofmann, Annika and Laun, Frederik Bernd and Knoll, Florian},
title = {{A Deep Nonlinear Subspace Modeling and Reconstruction for Diffusion-Weighted Imaging Using Denoising Auto-Encoder}},
journal = {Magnetic resonance in medicine},
year = {2026},
month = aug,
volume = {96},
number = {5},
pages = {2359--2369},
publisher = {Wiley},
issn = {0740-3194},
doi = {10.1002/mrm.70496},
url = {https://doi.org/10.1002/mrm.70496},
pmid = {42548198},
pmcid = {PMC13527252}
}

RIS

TY - JOUR
AU - Glaser, Julius
AU - Tan, Zhengguo
AU - Hofmann, Annika
AU - Laun, Frederik Bernd
AU - Knoll, Florian
TI - A Deep Nonlinear Subspace Modeling and Reconstruction for Diffusion-Weighted Imaging Using Denoising Auto-Encoder
T2 - Magnetic resonance in medicine
J2 - Magn Reson Med
PY - 2026
DA - 2026/08/04
VL - 96
IS - 5
SP - 2359
EP - 2369
SN - 0740-3194
PB - Wiley
DO - 10.1002/mrm.70496
UR - https://doi.org/10.1002/mrm.70496
LA - en
ER -

CSL-JSON

{
"id": "10.1002/mrm.70496",
"type": "article-journal",
"title": "A Deep Nonlinear Subspace Modeling and Reconstruction for Diffusion-Weighted Imaging Using Denoising Auto-Encoder",
"container-title": "Magnetic resonance in medicine",
"author": [
{
"family": "Glaser",
"given": "Julius"
},
{
"family": "Tan",
"given": "Zhengguo"
},
{
"family": "Hofmann",
"given": "Annika"
},
{
"family": "Laun",
"given": "Frederik Bernd"
},
{
"family": "Knoll",
"given": "Florian"
}
],
"container-title-short": "Magn Reson Med",
"volume": "96",
"issue": "5",
"page": "2359-2369",
"DOI": "10.1002/mrm.70496",
"PMID": "42548198",
"PMCID": "PMC13527252",
"ISSN": "0740-3194",
"publisher": "Wiley",
"URL": "https://doi.org/10.1002/mrm.70496",
"language": "en",
"issued": {
"date-parts": [
[
2026,
8,
4
]
]
}
}

The tracing map gets a citation of its own once an author has validated it and it has a DOI.

Similar papers

The papers with a page that share the most with this one: the tools found in their code, their categories, datasets, cited references and authors, the rarest counting most.

[1] doi:10.1002/mrm.70336 [code]
Offline Reconstruction of Diffusion MRI Acquisitions for Comparison Between Complex PCA-Based and AI-Based Denoising.
Journal: Magnetic resonance in medicine
In common: DIPY, MRtrix3, NiBabel, 3 other tools, methods / tools, structural MRI / diffusion, 6 references
[2] doi:10.1038/s41592-026-03057-2 [code]
CREsted: modeling genomic and synthetic cell-type-specific enhancers across tissues and species.
Journal: Nature methods
In common: PyWavelets, CuPy, Numba, 6 other tools, methods / tools
[3] doi:10.1038/s41598-026-39162-7 [code]
White matter microstructure differences in obstructive sleep apnea severity groups assessed by diffusion tensor metrics and biophysical modeling.
Journal: Scientific reports
In common: DIPY, MRtrix3, Numba, 3 other tools, structural MRI / diffusion, 2 references
[4] doi:10.1162/imag.a.1341 [code]
Massively parallelized brain tractography using compute clusters, supercomputers, and graphics processing units.
Journal: Imaging neuroscience (Cambridge, Mass.)
In common: DIPY, Numba, NiBabel, 3 other tools, methods / tools, structural MRI / diffusion, 3 references
[5] doi:10.1016/j.isci.2026.116671 [code]
A high-resolution functional network-organized atlas of human superficial white matter from ultra-high-field diffusion MRI.
Journal: iScience
In common: DIPY, MRtrix3, h5py, 5 other tools, methods / tools, structural MRI / diffusion
[6] doi:10.1162/imag.a.1276 [code]
High-resolution whole-brain magnetic resonance spectroscopic imaging in youth at risk for psychosis.
Journal: Imaging neuroscience (Cambridge, Mass.)
In common: CuPy, DIPY, Numba, 5 other tools
[7] doi:10.1371/journal.pone.0349951
Disentangling crossing fibers with advanced dMRI methods reveals bundle-specific degeneration across the visual system in asymmetric glaucoma.
Journal: PloS one
In common: structural MRI / diffusion, 8 references
[8] doi:10.1371/journal.pcbi.1014555 [code]
Body surface potential driven personalisation of electrophysiological digital twins in hypertrophic cardiomyopathy.
Journal: PLoS computational biology
In common: CuPy, pydicom, Pillow, 5 other tools, structural MRI / diffusion
[9] doi:10.1038/s42003-026-10957-8 [code]
Brain defence by the extracellular matrix protein Cochlin.
Journal: Communications biology
In common: CuPy, pydicom, Numba, 5 other tools
[10] doi:10.64898/2026.03.04.709502 [code]
Distributed hierarchical filters partition the Danionella vocal repertoire
Journal: bioRxiv (preprint)
In common: CuPy, pydicom, Numba, 5 other tools

Contribute

The authors of this paper can claim it, correct its record and validate its tracing map, and the maintainers of its code (its owner, or a public member of its organization) correct what it says of their repository; anyone signed in can ask for its removal. Every request goes to OSCR's own machine, which answers it; your account page follows them.

Sign in with ORCID to claim this paper as one of its authors, correct its record or validate its tracing map: when the paper's metadata lists your ORCID iD, you are recognized at once. Maintainers of its code: sign in with GitHub, then claim the repository on your account page.

Request its removal

To ask OSCR to remove this record, the copies of its authors' scripts or its tracing map, use the removal request page: signed in, you say who you are, what to remove and why, then review and confirm the request. Published rules decide every request (how).

Discussion, reproductions, activity

Discussion: questions and error reports about this paper and its code, from signed-in readers and its authors. It opens with sign-in.

Reproductions: reports from readers who ran the authors' code: what they reproduced, with which environment, commit and data. It opens with sign-in.

Activity: what happens around this paper: new versions of its record, its map's validation, discussions and reproductions. It opens with sign-in.