LCOV - code coverage report
Current view: top level - coupling/filtering/filters - NLM.h (source / functions) Coverage Total Hit
Test: coverage.info Lines: 0.0 % 27 0
Test Date: 2026-08-21 15:14:06 Functions: 0.0 % 2 0

            Line data    Source code
       1              : // This file is part of the Mamico project. For conditions of distribution
       2              : // and use, please see the copyright notice in Mamico's main folder
       3              : 
       4              : #pragma once
       5              : 
       6              : #include "coupling/filtering/filters/Datastructures.h"
       7              : #include "coupling/filtering/interfaces/JunctorInterface.h"
       8              : #include <array>
       9              : 
      10              : namespace coupling {
      11              : namespace filtering {
      12              : template <unsigned int dim, coupling::indexing::IndexTrait... scope> class NLM;
      13              : }
      14              : } // namespace coupling
      15              : 
      16              : /**
      17              :  *  Noise reduction algorithm using non-local means (NLM) method
      18              :  *  See 'Fast Non Local Means Denoising for 3D MR Images' by Coupé et al. 2006
      19              :  *   and 'Non-Local Means Denoising' by Buades et al. 2011.
      20              :  *
      21              :  *  @author Piet Jarmatz
      22              :  *
      23              :  */
      24              : template <unsigned int dim, coupling::indexing::IndexTrait... scope> class coupling::filtering::NLM : public coupling::filtering::JunctorInterface<dim, 2, 1> {
      25              : public:
      26              :   using CellIndex_T = coupling::indexing::CellIndex<dim, coupling::indexing::IndexTrait::vector, scope..., coupling::indexing::IndexTrait::md2macro,
      27              :                                                     coupling::indexing::IndexTrait::noGhost>;
      28              : 
      29            0 :   NLM(const std::vector<coupling::datastructures::CouplingCell<dim>*> inputCellVector_unfiltered,
      30              :       const std::vector<coupling::datastructures::CouplingCell<dim>*> inputCellVector_prefiltered,
      31              :       const std::vector<coupling::datastructures::CouplingCell<dim>*> outputCellVector, const std::array<bool, 7> filteredValues, int tws, double sigsq,
      32              :       double sigsq_rel, double hsq, double hsq_rel, int M = 2, int d = 1)
      33              :       : coupling::filtering::JunctorInterface<dim, 2, 1>({inputCellVector_unfiltered, inputCellVector_prefiltered}, {outputCellVector}, filteredValues, "NLM"),
      34            0 :         _timeWindowSize(tws), _M(M), _d(d), _sigsq(sigsq), _sigsq_rel(sigsq_rel), _hsq(hsq), _hsq_rel(hsq_rel), _cycleCounter(0), _t(0),
      35            0 :         _flowfield(CellIndex_T::numberCellsInDomain, tws), _flowfield_prefiltered(CellIndex_T::numberCellsInDomain, tws),
      36            0 :         _patchfield(CellIndex_T::numberCellsInDomain - tarch::la::Vector<dim, unsigned int>(2), tws), _innerCellIndices() {
      37              :     // Initialize flowfield
      38            0 :     for (int t = 0; t < tws; ++t)
      39            0 :       for (auto idx : CellIndex_T()) {
      40            0 :         tarch::la::Vector<dim, unsigned int> idxv(idx.get());
      41            0 :         coupling::filtering::Quantities<dim>& q = _flowfield(idxv, t);
      42            0 :         q[0] = 1;
      43            0 :         for (unsigned int d = 1; d <= dim; ++d)
      44            0 :           q[d] = 0;
      45            0 :         coupling::filtering::Quantities<dim>& qp = _flowfield_prefiltered(idxv, t);
      46            0 :         qp[0] = 1;
      47            0 :         for (unsigned int d = 1; d <= dim; ++d)
      48            0 :           qp[d] = 0;
      49              :       }
      50              : 
      51              :     // Initialize innerCellIndices
      52            0 :     auto domainSize = CellIndex_T::numberCellsInDomain;
      53            0 :     for (auto idx : CellIndex_T()) {
      54            0 :       tarch::la::Vector<dim, unsigned int> idxv(idx.get());
      55            0 :       for (unsigned int d = 0; d < dim; d++)
      56            0 :         if (idxv[d] == 0 || idxv[d] == domainSize[d] - 1)
      57            0 :           goto continue_loop;
      58            0 :       _innerCellIndices.push_back(idx);
      59            0 :     continue_loop:;
      60              :     }
      61              : 
      62              : #ifdef NLM_DEBUG
      63              :     std::cout << "    NLM: Created NLM instance." << std::endl;
      64              :     std::cout << "    WARNING: Regardless of configuration, NLM always filters "
      65              :                  "macroscopic mass and momentum."
      66              :               << std::endl;
      67              : #endif
      68            0 :   }
      69              : 
      70            0 :   virtual ~NLM() {
      71              : #ifdef NLM_DEBUG
      72              :     std::cout << "    NLM: Destroyed NLM instance." << std::endl;
      73              : #endif
      74            0 :   }
      75              : 
      76              :   void operator()();
      77              : 
      78              : private:
      79              :   /**
      80              :    * Stores new values from inputCellVectors into _flowfield and
      81              :    * _flowfield_prefiltered for this timestep _t.
      82              :    */
      83              :   void save_data();
      84              : 
      85              :   /**
      86              :    *  Reconstructs _patchfield(idx,_t) for all inner cell indices idx,
      87              :    *  so that new information from updated flowfield will be included.
      88              :    */
      89              :   void update_patchfield();
      90              : 
      91              :   /**
      92              :    * Main loop of NLM algorithm, computes filtering output for one coupling
      93              :    * cycle.
      94              :    */
      95              :   void denoise();
      96              : 
      97              :   /**
      98              :    * Compute which filtering results we need here.
      99              :    * @param idx_inner Index of this cell on the inner local MD 2 macro domain,
     100              :    * i.e. the domain where the patchfield is defined
     101              :    * @return Relative offsets, of all neighboring boundary cells and this cell
     102              :    * itself
     103              :    */
     104              :   std::vector<tarch::la::Vector<dim, int>> compute_boundary_neighbors(const tarch::la::Vector<dim, unsigned int>&);
     105              : 
     106              :   /**
     107              :    * Must be called to indicate that one coupling cycle is finished and timestep
     108              :    * counters should be incremented.
     109              :    */
     110              :   void increment_time();
     111              : 
     112              :   const unsigned int _timeWindowSize; // number of snapshots / coupling cycles taken into
     113              :                                       // consideration for noise reduction
     114              :                                       // unsigned int _timeModulo; // e.g. 2,4,8 ....
     115              :   const unsigned int _M;              // search volume has size (2M+1)^3
     116              :   const unsigned int _d;              // patches have size (2d+1)^4; this makes at least _d
     117              :                                       // ghost layer necessary
     118              :   double _sigsq, _sigsq_rel;
     119              :   double _hsq, _hsq_rel;
     120              : 
     121              :   unsigned int _cycleCounter; // coupling cycle counter, indicates how many data
     122              :                               // snapshots are available already
     123              :   unsigned int _t;            // active temporal index, iterates cyclic between zero and
     124              :                               // _timeWindowSize
     125              :   coupling::filtering::Flowfield<dim> _flowfield;
     126              :   coupling::filtering::Flowfield<dim> _flowfield_prefiltered;
     127              :   coupling::filtering::Patchfield<dim> _patchfield;
     128              :   std::vector<CellIndex_T> _innerCellIndices;
     129              : 
     130            0 :   inline unsigned int posmod(int i, int n) const { return (i % n + n) % n; }
     131              : };
     132              : 
     133              : // include implementation of header
     134              : #include "NLM.cpph"
        

Generated by: LCOV version 2.0-1