Line data Source code
1 : #pragma once 2 : 3 : #include "LinearOperator.h" 4 : 5 : namespace elsa 6 : { 7 : /** 8 : * @brief Class representing a (regular) Cone-Adapted Discrete Shearlet Transform 9 : * 10 : * @author Andi Braimllari - initial code 11 : * 12 : * @tparam data_t data type for the domain and range of the problem, defaulting to real_t 13 : * 14 : * ShearletTransform represents a band-limited (compact support in Fourier domain) 15 : * representation system. It oversamples a 2D signal of (W, H) to (W, H, L). Most of the 16 : * computation is taken for the spectra, which is stored after the first run. It only 17 : * handles signals with one channel, e.g. grayscale images. Increasing the number of scales 18 : * will increase precision. 19 : * 20 : * Note that this class only handles the 2D scenario. 21 : * 22 : * References: 23 : * https://www.math.uh.edu/~dlabate/SHBookIntro.pdf 24 : * https://www.math.uh.edu/~dlabate/Athens.pdf 25 : * https://arxiv.org/pdf/1202.1773.pdf 26 : */ 27 : template <typename ret_t = real_t, typename data_t = real_t> 28 : class ShearletTransform : public LinearOperator<ret_t> 29 : { 30 : public: 31 : /** 32 : * @brief Constructor for a (regular) cone-adapted discrete shearlet transform. 33 : * 34 : * @param[in] spatialDimensions the width and height of the input image 35 : */ 36 : ShearletTransform(IndexVector_t spatialDimensions); 37 : 38 : /** 39 : * @brief Constructor for a (regular) cone-adapted discrete shearlet transform. 40 : * 41 : * @param[in] width the width of the input image 42 : * @param[in] height the height of the input image 43 : */ 44 : ShearletTransform(index_t width, index_t height); 45 : 46 : /** 47 : * @brief Constructor for a (regular) cone-adapted discrete shearlet transform. 48 : * 49 : * @param[in] width the width of the input image 50 : * @param[in] height the height of the input image 51 : * @param[in] numOfScales the number of scales 52 : */ 53 : ShearletTransform(index_t width, index_t height, index_t numOfScales); 54 : 55 : /** 56 : * @brief Constructor for a (regular) cone-adapted discrete shearlet transform. 57 : * 58 : * @param[in] width the width of the input image 59 : * @param[in] height the height of the input image 60 : * @param[in] numOfScales the number of scales 61 : * @param[in] spectra the spectra 62 : */ 63 : ShearletTransform(index_t width, index_t height, index_t numOfScales, 64 : std::optional<DataContainer<data_t>> spectra); 65 : 66 : /// default destructor 67 14 : ~ShearletTransform() override = default; 68 : 69 : /// method for computing the spectra, should only be called once as subsequent calls 70 : /// will generate the same spectra 71 : void computeSpectra() const; 72 : 73 : /// method indicating if the spectra has already been computed 74 : bool isSpectraComputed() const; 75 : 76 : /// return the spectra 77 : auto getSpectra() const -> DataContainer<data_t>; 78 : 79 : /// return the width 80 : auto getWidth() const -> index_t; 81 : 82 : /// return the height 83 : auto getHeight() const -> index_t; 84 : 85 : /// return the oversampling factor 86 : auto getNumOfLayers() const -> index_t; 87 : 88 : // TODO ideally this ought to be implemented somewhere else, perhaps in a more general 89 : // manner, but that might take quite some time, can this make it to master in the 90 : // meantime? 91 : DataContainer<elsa::complex<data_t>> 92 : sumByLastAxis(DataContainer<elsa::complex<data_t>> container) const; 93 : 94 : protected: 95 : void applyImpl(const DataContainer<ret_t>& x, DataContainer<ret_t>& Ax) const override; 96 : 97 : void applyAdjointImpl(const DataContainer<ret_t>& y, 98 : DataContainer<ret_t>& Aty) const override; 99 : 100 : /// implement the polymorphic clone operation 101 : ShearletTransform<ret_t, data_t>* cloneImpl() const override; 102 : 103 : /// implement the polymorphic comparison operation 104 : bool isEqual(const LinearOperator<ret_t>& other) const override; 105 : 106 : private: 107 : /// variable to store the spectra 108 : mutable std::optional<DataContainer<data_t>> _spectra = std::nullopt; 109 : 110 : /// variables to store the spatial extents 111 : index_t _width; 112 : index_t _height; 113 : 114 : /// variable to store the number of scales 115 : index_t _numOfScales; 116 : 117 : static index_t calculateNumOfScales(index_t width, index_t height); 118 : 119 : /// variable to store the oversampling factor 120 : index_t _numOfLayers; 121 : 122 : static index_t calculateNumOfLayers(index_t width, index_t height); 123 : 124 : static index_t calculateNumOfLayers(index_t numOfScales); 125 : 126 : void _computeSpectraAtLowFreq() const; 127 : 128 : void _computeSpectraAtConicRegions(index_t j, index_t k, index_t hSliceIndex, 129 : index_t vSliceIndex) const; 130 : 131 : void _computeSpectraAtSeamLines(index_t j, index_t k, index_t hxvSliceIndex) const; 132 : 133 : /** 134 : * Fractions of the input data shape, needed internally in many functions. 135 : */ 136 : struct shape_fractions { 137 : index_t negativeHalfWidth; 138 : index_t halfWidth; 139 : index_t negativeHalfHeight; 140 : index_t halfHeight; 141 : }; 142 : 143 : /** 144 : * helper function to calculate input data fractions. 145 : */ 146 : auto getShapeFractions() const -> shape_fractions; 147 : }; 148 : } // namespace elsa