Skip to content

Add example notebook demonstrating TV vs TGV (denoising + radial MRI)#894

Open
trung-vt wants to merge 1 commit intoPTB-MR:mainfrom
trung-vt:tgv_example_notebook
Open

Add example notebook demonstrating TV vs TGV (denoising + radial MRI)#894
trung-vt wants to merge 1 commit intoPTB-MR:mainfrom
trung-vt:tgv_example_notebook

Conversation

@trung-vt
Copy link
Copy Markdown

@trung-vt trung-vt commented Sep 9, 2025

Add example notebook demonstrating TV vs TGV (denoising + radial MRI)

No API changes; documentation/education-oriented.

Motivation: Demonstrate how mrpro tools can be used to implement TGV minimization and symmetrized gradient for arbitrary dimensions.

As discussed with @koflera, this PR adds an example Jupyter notebook examples/notebooks/tgv_tv_comparison.ipynb that showcases Total Generalised Variation (TGV) side-by-side with Total Variation (TV) on two small problems:

  1. Image denoising (additive noise on a simple 2D image)
  2. Radial undersampled MRI reconstruction (Fourier operator + radial mask)

TV and TGV are run with comparable settings. TGV is shown to reduce staircasing relative to TV while preserving details.

Implementation notes

  • The notebook downloads 2 jpeg images and one .mat file from Zenodo.
  • Automatically uses cuda if available.
  • Other than downloading, most of the runtime is for running TV and TGV for the two examples, 256 iterations per run.
  • Parameters are chosen for clarity rather than exhaustive tuning.

@fzimmermann89
Copy link
Copy Markdown
Member

Thank you for this great contribution! This is, in my opinion, a better approach than the other PR. Unfortunately, I will need some time to go through it in detail.

After skimming through it, I have a couple of general questions and remarks:

  • Would it make sense to include the symmetric gradient operator as an Operator in our library, similar to the finite difference operator? It could still use the same logic, but this might be something to put into mrpro proper (as in your previous PR).

  • We are an MR group, so I might be a bit picky about MR stuff: You do Cartesian MRI with a pseudo-radial undersampling pattern. Radial MRI would typically use a NUFFT and not have spokes lined up on the Cartesian grid. My suggestion would be to either just do 1D random Cartesian undersampling, i.e., a mask where lines are randomly removed in one direction, or an actual radial trajectory. This would remove the radial_mask code from this example.

  • Data formats: I think it might be nicer to either a) save the data as a reshaped PyTorch tensor already on Zenodo, or, even better, use an ISMRMD file with a proper header, undersampling information, etc. This would remove some of this "boilerplate" from the example notebook. Do you think you have the capacity to try your code on one of the datasets we use in the other examples? There are examples using radial acquisitions, where the FourierOp detects that a non-uniform Fourier operator should be used, and examples using Cartesian data.

  • Would you be okay with removing the image denoising example and focusing only on the MR example for the example notebook?

  • If not, can image loading using PIL and torchvision be simplified by only using torchvision's decode_image?

  • For the comparative TV reconstruction, you could even use the existing TV reconstruction in mrpro.algorithms. We already have a notebook explaining the background behind TV reconstruction, so here I think it would be good to focus on the TGV reconstruction by removing as much as possible of the "non-interesting," i.e., non-TGV code.

I think this would make this example even more educational. If you don't have the bandwidth to do this, we could also postpone some of these suggestions, and I can try to help you at some point (or maybe @koflera can continue to help).

Cheers,
Felix

@github-actions
Copy link
Copy Markdown
Contributor

Coverage

Coverage Report
FileStmtsMissCoverMissing
src/mrpro
   _version.py6267%7–8
src/mrpro/algorithms/csm
   inati.py25196%43
src/mrpro/algorithms/dcf
   dcf_voronoi.py55493%15, 55–56, 89
src/mrpro/algorithms/optimizers
   adam.py30680%108, 125–129
   cg.py52198%139
   pdhg.py81396%178–179, 185
   pgd.py53492%107, 152–155
src/mrpro/algorithms/reconstruction
   DirectReconstruction.py28679%62, 65, 70, 77–79
   IterativeSENSEReconstruction.py13192%79
   Reconstruction.py501374%54–56, 80–87, 109, 112
   RegularizedIterativeSENSEReconstruction.py512649%104–108, 122–161
src/mrpro/data
   AcqInfo.py165796%49, 56, 134–135, 137, 243, 367
   CsmData.py43295%233–235
   Dataclass.py3122692%59, 320, 336, 402, 460–462, 475, 570, 590–591, 593, 608–609, 611, 658–659, 664–665, 852–853, 878, 885, 890–891, 893
   DcfData.py33197%62
   EncodingLimits.py97397%37, 127, 130
   IData.py138696%125, 185, 231, 244, 249, 293
   IHeader.py130795%69–72, 255, 259, 263, 267
   KData.py2282489%122–123, 138, 145, 156–167, 178, 186, 197, 236, 258–260, 304–305, 377, 543, 545, 617
   KHeader.py1761393%115–121, 148, 196, 203–204, 231–238
   KNoise.py22195%44
   KTrajectory.py95397%163, 165, 185
   QData.py32197%43
   Rotation.py7354294%104, 202, 339, 437, 481, 499, 586, 588, 597, 631, 633, 696, 773, 778, 781, 796, 813, 818, 894, 1082, 1087, 1090, 1114, 1118, 1142, 1262, 1264, 1272–1273, 1337, 1419, 1623, 1630–1632, 1691, 1787, 1939, 1974, 1978, 2154, 2175
   SpatialDimension.py1501987%34, 103, 146, 158, 278–280, 293–295, 329, 347, 360, 373, 386, 399, 408–409, 437
src/mrpro/data/traj_calculators
   KTrajectoryCalculator.py26292%84, 95
   KTrajectoryCartesian.py31487%129–132, 136
   KTrajectoryIsmrmrd.py19195%57
   KTrajectorySpiral2D.py571377%63–66, 69, 71, 73, 75, 77, 105, 107, 134–136
src/mrpro/operators
   AveragingOp.py36294%72, 113
   CartesianSamplingOp.py112496%152, 191, 266, 387
   ConjugateGradientOp.py89792%62, 64, 100, 106, 228, 230, 233
   ConstraintsOp.py85495%78, 80, 250, 255
   EndomorphOperator.py28293%71, 77
   FiniteDifferenceOp.py29293%40, 126
   FourierOp.py101694%186–187, 206, 251, 315, 320
   Functional.py70297%116, 118
   GridSamplingOp.py1651591%72–73, 82–83, 90–91, 94, 96, 98, 282, 290–291, 303, 309–310
   LinearOperator.py202697%217, 255, 296, 305, 313, 330
   LinearOperatorMatrix.py1741989%98, 135, 168, 177, 182, 191–194, 207–210, 218–219, 224–225, 237, 346, 376, 403
   MultiIdentityOp.py16288%58, 63
   NonUniformFastFourierOp.py1951095%68, 95, 217, 219, 257, 259, 336, 393, 467, 472
   Operator.py88397%82, 115, 125
   PatchOp.py49394%93, 129, 144
   ProximableFunctionalSeparableSum.py44393%117, 208, 219
   SliceProjectionOp.py1781094%45, 62, 64, 70, 154, 180, 216, 253, 290, 330
   WaveletOp.py121596%168, 186, 230, 235, 258
   ZeroPadOp.py18194%30
src/mrpro/operators/functionals
   SSIM.py73790%60–80, 82, 86, 114, 147
src/mrpro/operators/models
   EPG.py2124479%31–32, 105–120, 168–172, 192–195, 216–221, 284, 289, 305–307, 327–328, 333, 357, 362, 387, 392, 508, 609, 636
src/mrpro/phantoms
   EllipsePhantom.py43295%66, 131
   brainweb.py2974087%276, 290–294, 349–359, 398, 454–457, 479–480, 485–486, 488–489, 493, 501, 508–509, 550, 621, 624–625, 644, 653–656, 667, 669, 700–701, 715, 723
   fastmri.py1061091%50–51, 59, 65, 162, 169–171, 174–175, 189
   m4raw.py74495%58–59, 74, 76
   mdcnn.py71790%58, 62–63, 70, 82, 88, 135
src/mrpro/utils
   RandomGenerator.py1561590%23–24, 36, 38, 188, 212, 428, 446, 528, 799, 829–832, 895, 898
   filters.py62297%44, 49
   indexing.py177199%321
   pad_or_crop.py32681%27, 31, 62, 65, 68, 71
   reshape.py139994%112, 308, 420–422, 443, 445, 452, 467
   slice_profiles.py49688%21, 37, 119–122, 155
   split_idx.py10280%43, 47
   summarize.py57788%40–41, 70–73, 77, 81
   unit_conversion.py721579%34, 44, 51, 53, 62, 69, 71, 78, 80, 89, 100, 121, 123, 144, 146
TOTAL763652593% 

Tests Skipped Failures Errors Time
2964 0 💤 0 ❌ 0 🔥 2m 2s ⏱️

@github-actions
Copy link
Copy Markdown
Contributor

📚 Documentation

📁 Download as zip
🔍 View online

@trung-vt
Copy link
Copy Markdown
Author

Hi Felix, thank you for the review! Would #904 be a more suitable addition? There is a new SymmetrizedGradientOp class. The example notebook now follows closely the TV reconstruction example: it downloads the ISMRMD file from Zenodo, applies NUFFT for radial MRI, and removes the image denoising example.

Best wishes,
Trung

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants