Ocean
FourierTransformation.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) Meta Platforms, Inc. and affiliates.
3  *
4  * This source code is licensed under the MIT license found in the
5  * LICENSE file in the root directory of this source tree.
6  */
7 
8 #ifndef META_OCEAN_MATH_FOURIER_TRANSFORMATION_H
9 #define META_OCEAN_MATH_FOURIER_TRANSFORMATION_H
10 
11 #include "ocean/math/Math.h"
12 #include "ocean/math/Complex.h"
13 #include "ocean/math/Numeric.h"
14 
15 #include "ocean/base/Frame.h"
16 #include "ocean/base/Memory.h"
17 #include "ocean/base/Worker.h"
18 
19 namespace Ocean
20 {
21 
22 /**
23  * This class implements Fourier transformation functions.
24  * @ingroup math
25  */
26 class OCEAN_MATH_EXPORT FourierTransformation
27 {
28  public:
29 
30  /**
31  * This class provides the implementation of the Fourier transformation of the Ocean framework.
32  */
34  {
35  public:
36 
37  /**
38  * Applies a forward Fourier transformation for a given 2D spatial signal.
39  * The spatial signal may be composed of several channels (element-wise interleaved).<br>
40  * However only one channel will be transformed to one joined block of frequencies at once.<br>
41  * @param spatial 2D spatial signal that will be transformed
42  * @param width The width of the 2D signal in elements
43  * @param height height of the 2D signal in elements
44  * @param frequency Resulting frequency analysis for the given signal, make sure that the provided buffer is large enough
45  * @param worker Optional worker object to distribute the computation
46  * @tparam T Data type of the spatial and frequency signals
47  */
48  template <typename T>
49  static void spatialToFrequency2(const std::complex<T>* spatial, const unsigned int width, const unsigned int height, std::complex<T>* frequency, Worker* worker = nullptr);
50 
51  /**
52  * Applies a backward Fourier transformation for a given 2D frequency signal.
53  * The spatial signal may be composed of several channels (element-wise interleaved).<br>
54  * However only one joined block of frequencies will be transformed to one channel at once.<br>
55  * @param frequency 2D frequency signal that will be transformed
56  * @param width The width of the 2D signal in elements
57  * @param height height of the 2D signal in elements
58  * @param spatial Resulting spatial frequency for the given signal, make sure that the provided buffer is large enough
59  * @param worker Optional worker object to distribute the computation
60  * @tparam T Data type of the spatial and frequency signals
61  */
62  template <typename T>
63  static void frequencyToSpatial2(const std::complex<T>* frequency, const unsigned int width, const unsigned int height, std::complex<T>* spatial, Worker* worker = nullptr);
64 
65  protected:
66 
67  /**
68  * Applies a horizontal forward Fourier transformation for a subset of a given 2D spatial signal.
69  * @param spatial 2D spatial signal that will be transformed
70  * @param width The width of the 2D signal in elements
71  * @param height height of the 2D signal in elements
72  * @param frequencyHorizontal Resulting horizontal frequency analysis for the given signal, make sure that the provided buffer is large enough
73  * @param firstRow First row to be handled
74  * @param numberRows Number of rows to be handled
75  */
76  template <typename T>
77  static void spatialToFrequencyHorizontalSubset2(const std::complex<T>* spatial, const unsigned int width, const unsigned int height, std::complex<T>* frequencyHorizontal, const unsigned int firstRow, const unsigned int numberRows);
78 
79  /**
80  * Applies a vertical forward Fourier transformation for a subset of a given 2D spatial signal.
81  * @param spatial 2D spatial signal that will be transformed
82  * @param width The width of the 2D signal in elements
83  * @param height height of the 2D signal in elements
84  * @param frequencyVertical Resulting vertical frequency analysis for the given signal, make sure that the provided buffer is large enough
85  * @param firstColumn First column to be handled
86  * @param numberColumns Number of columns to be handled
87  */
88  template <typename T>
89  static void spatialToFrequencyVerticalSubset2(const std::complex<T>* spatial, const unsigned int width, const unsigned int height, std::complex<T>* frequencyVertical, const unsigned int firstColumn, const unsigned int numberColumns);
90 
91  /**
92  * Applies a horizontal backward Fourier transformation for subset of a given 2D frequency signal.
93  * @param frequency 2D frequency signal that will be transformed
94  * @param width The width of the 2D signal in elements
95  * @param height height of the 2D signal in elements
96  * @param spatialHorizontal Resulting spatial frequency for the given signal, make sure that the provided buffer is large enough
97  * @param firstRow First row to be handled
98  * @param numberRows Number of rows to be handled
99  */
100  template <typename T>
101  static void frequencyToSpatialHorizontalSubset2(const std::complex<T>* frequency, const unsigned int width, const unsigned int height, std::complex<T>* spatialHorizontal, const unsigned int firstRow, const unsigned int numberRows);
102 
103  /**
104  * Applies a vertical backward Fourier transformation for a subset of a given 2D frequency signal.
105  * @param frequency 2D frequency signal that will be transformed
106  * @param width The width of the 2D signal in elements
107  * @param height height of the 2D signal in elements
108  * @param spatialVertical Resulting vertical spatial frequency for the given signal, make sure that the provided buffer is large enough
109  * @param firstColumn First column to be handled
110  * @param numberColumns Number of columns to be handled
111  */
112  template <typename T>
113  static void frequencyToSpatialVerticalSubset2(const std::complex<T>* frequency, const unsigned int width, const unsigned int height, std::complex<T>* spatialVertical, const unsigned int firstColumn, const unsigned int numberColumns);
114  };
115 
116  public:
117 
118  /**
119  * Direct Fourier Transformation (OpenCV-compatible interface)
120  * @sa cv::dft()
121  * @param source Input array that could be real or complex. Must be valid.
122  * @param target Output array whose size and type depends on the flags. Size depends on `flags`.
123  * @param flags Transformation flags, representing a combination of the cv::DftFlags
124  * @param nonzero_rows Number of nonzero rows. All rows after that will be ignored.
125  * @return True on success, otherwise false
126  */
127  static bool dft0(const Frame& source, Frame& target, int flags, int nonzero_rows);
128 
129  /**
130  * Direct Fourier Transformation (OpenCV-compatible interface)
131  * @sa cv::dft()
132  * @param source Input array that could be real or complex, must be a valid pointer
133  * @param width The width of the input and output arrays, range: [1, infinity)
134  * @param height The height of the input and output arrays, range: [1, infinity)
135  * @param sourceChannels Number of channels of the input array, range: [1, 2]
136  * @param target Output array, this must be initialized before calling this function, size depends on `flags`, must be a valid pointer
137  * @param targetChannels Number of channels of the output array, depends on `flags`, range: [1, 2]
138  * @param dataType Data type of the input and output (must be the same), valid values: FrameType::DT_SIGNED_FLOAT_32 or FrameType::DT_SIGNED_FLOAT_64
139  * @param flags Transformation flags, representing a combination of the cv::DftFlags
140  * @param nonzero_rows Number of nonzero rows. All rows after that will be ignored
141  * @param sourcePaddingElements Number of padding elements used in the input array, range: [0, infinity)
142  * @param targetPaddingElements Number of padding elements used in the output array, range: [0, infinity)
143  * @return True on success, otherwise false
144  */
145  static bool dft0(const void* source, const unsigned int width, const unsigned int height, const unsigned int sourceChannels, void* target, const unsigned int targetChannels, const Ocean::FrameType::DataType dataType, int flags, int nonzero_rows, const unsigned int sourcePaddingElements = 0u, const unsigned int targetPaddingElements = 0u);
146 
147  /**
148  * Returns the optimal DFT size for a given vector size
149  * @sa cv::getOptimalDFTSize()
150  * @param size The size of the vector
151  * @return Optimal size for the DFT
152  */
153  static int getOptimalDFTSize0(int size);
154 
155  /**
156  * Applies a forward Fourier transformation for a given 2D (real) spatial signal.
157  * @param spatial The real 2D spatial signal that will be transformed, must be valid
158  * @param width The width of the 2D signal in elements, with range [1, infinity)
159  * @param height height of the 2D signal in elements, with range [1, infinity)
160  * @param complexFrequency Resulting complex frequency analysis for the given signal, must be valid
161  * @param spatialPaddingElements The number of padding elements at the end of each row of the spatial signal, in elements with respect to `T` (not `complex<T>`), with range [0, infinity)
162  * @param frequencyPaddingElements The number of padding elements at the end of each row of the frequency analysis, in elements (not `complex<T>`), with range [0, infinity)
163  * @tparam T The element data type of the spatial and frequency signals, either 'float' or 'double'
164  */
165  template <typename T>
166  static void spatialToFrequency2(const T* spatial, const unsigned int width, const unsigned int height, T* complexFrequency, const unsigned int spatialPaddingElements = 0u, const unsigned int frequencyPaddingElements = 0u);
167 
168  /**
169  * Applies a forward Fourier transformation for a given 2D (complex) spatial signal.
170  * @param complexSpatial The complex 2D spatial signal that will be transformed, must be valid
171  * @param width The width of the 2D signal in elements, with range [1, infinity)
172  * @param height height of the 2D signal in elements, with range [1, infinity)
173  * @param complexFrequency Resulting complex frequency analysis for the given signal, must be valid
174  * @param spatialPaddingElements The number of padding elements at the end of each row of the spatial signal, in elements with respect to `T` (not `complex<T>`), with range [0, infinity)
175  * @param frequencyPaddingElements The number of padding elements at the end of each row of the frequency analysis, in elements (not `complex<T>`), with range [0, infinity)
176  * @tparam T Data type of the spatial and frequency signals, either 'float' or 'double'
177  */
178  template <typename T>
179  static void complexSpatialToFrequency2(const T* complexSpatial, const unsigned int width, const unsigned int height, T* complexFrequency, const unsigned int spatialPaddingElements = 0u, const unsigned int frequencyPaddingElements = 0u);
180 
181  /**
182  * Applies a backward Fourier transformation for a given 2D frequency signal.
183  * @param complexFrequency The complex 2D frequency signal that will be transformed, must be valid
184  * @param width The width of the 2D signal in elements, with range [1, infinity)
185  * @param height height of the 2D signal in elements, with range [1, infinity)
186  * @param spatial Resulting (real) spatial frequency for the given signal, make sure that the provided buffer is large enough, must be valid
187  * @param frequencyPaddingElements The number of padding elements at the end of each row of the frequency analysis, in elements (not `complex<T>`), with range [0, infinity)
188  * @param spatialPaddingElements The number of padding elements at the end of each row of the spatial signal, in elements with respect to `T` (not `complex<T>`), with range [0, infinity)
189  * @tparam T Data type of the spatial and frequency signals, either 'float' or 'double'
190  */
191  template <typename T>
192  static void frequencyToSpatial2(const T* complexFrequency, const unsigned int width, const unsigned int height, T* spatial, const unsigned int frequencyPaddingElements = 0u, const unsigned int spatialPaddingElements = 0u);
193 
194  /**
195  * Applies a backward Fourier transformation for a given 2D frequency signal.
196  * @param complexFrequency The complex 2D frequency signal that will be transformed, must be valid
197  * @param width The width of the 2D signal in elements, with range [1, infinity)
198  * @param height height of the 2D signal in elements, with range [1, infinity)
199  * @param complexSpatial Resulting complex spatial frequency for the given signal, make sure that the provided buffer is large enough, must be valid
200  * @param frequencyPaddingElements The number of padding elements at the end of each row of the frequency analysis, in elements (not `complex<T>`), with range [0, infinity)
201  * @param spatialPaddingElements The number of padding elements at the end of each row of the spatial signal, in elements with respect to `T` (not `complex<T>`), with range [0, infinity)
202  * @tparam T Data type of the spatial and frequency signals, either 'float' or 'double'
203  */
204  template <typename T>
205  static void frequencyToComplexSpatial2(const T* complexFrequency, const unsigned int width, const unsigned int height, T* complexSpatial, const unsigned int frequencyPaddingElements = 0u, const unsigned int spatialPaddingElements = 0u);
206 
207  /**
208  * Converts scalar values to complex values.
209  * @param source Scalar source values
210  * @param target Resulting complex values, make sure that the provided memory is large enough
211  * @param number Number of elements that will be converted
212  * @tparam TScalar Data type of the real signal
213  * @tparam TComplex Data type of the complex signal
214  */
215  template <typename TScalar, typename TComplex>
216  static inline void scalarToComplex(const TScalar* source, std::complex<TComplex>* target, const size_t number);
217 
218  /**
219  * Converts the real components of complex values to scalar values.
220  * @param source Complex source values
221  * @param target Resulting scalar values, make sure that the provided memory is large enough
222  * @param number Number of elements that will be converted
223  * @tparam TComplex Data type of the complex signal
224  * @tparam TScalar Data type of the real signal
225  */
226  template <typename TComplex, typename TScalar>
227  static inline void realToScalar(const std::complex<TComplex>* source, TScalar* target, const size_t number);
228 
229  /**
230  * Converts the imaginary components of complex values to scalar values.
231  * @param source Complex source values
232  * @param target Resulting scalar values, make sure that the provided memory is large enough
233  * @param number Number of elements that will be converted
234  * @tparam TComplex Data type of the complex signal
235  * @tparam TScalar Data type of the real signal
236  */
237  template <typename TComplex, typename TScalar>
238  static inline void imaginaryToScalar(const std::complex<TComplex>* source, TScalar* target, const size_t number);
239 
240  /**
241  * Converts complex values to magnitude (or absolute) values.
242  * The magnitude of a complex value is determined by the square root of the squared sum of the real and the imaginary element.<br>
243  * @param source Complex source values
244  * @param target Resulting magnitude values, make sure that the provided memory is large enough
245  * @param number Number of elements that will be converted
246  * @tparam TComplex Data type of the complex signal
247  * @tparam TScalar Data type of the real signal
248  */
249  template <typename TComplex, typename TScalar>
250  static inline void complexToMagnitude(const std::complex<TComplex>* source, TScalar* target, const size_t number);
251 
252  /**
253  * Shifts a given signal by half of the width and the height.
254  * @param source The source signal that will be shifted
255  * @param width The width of the signal in elements, must be even
256  * @param height The height of the signal in elements, must be even
257  * @param target The target signal that will receive the shifted signal
258  * @tparam T Data type of the signal
259  */
260  template <typename T>
261  static void shiftHalfDimension2(const T* source, unsigned int width, const unsigned int height, T* target);
262 
263  /**
264  * Shifts a given signal by half of the width and the height.
265  * @param data Signal that will be shifted
266  * @param width The width of the signal in elements, must be even
267  * @param height The height of the signal in elements, must be even
268  * @tparam T Data type of the signal
269  */
270  template <typename T>
271  static void shiftHalfDimension2(T* data, unsigned int width, const unsigned int height);
272 
273  /**
274  * Returns the center position for shift operations that corresponds with the first Fourier element.
275  * @param size Size of the signal in bins, with range (0, infinity)
276  * @return Corresponding center position of the first bin
277  */
278  static inline unsigned int shiftCenter(const unsigned int size);
279 
280  /**
281  * Elementwise multiplication of two 2D complex Fourier spectrums (one channel spectrums).
282  * @param complexSourceA The pointer of the first complex source spectrum, must be valid
283  * @param complexSourceB The pointer of the second complex source spectrum, must be valid
284  * @param complexTarget The pointer of the target spectrum receiving the elementwise multiplication result, must be valid
285  * @param width The width of the 2D spectrum (the number of complex elements in horizontal direction), with range [1, infinity)
286  * @param height The height of the 2D specturm (the number of complex elements in vertical direction), with range [1, infinity)
287  * @param horizontalPaddingSourceAElements Optional horizontal padding at the end of each row of the first source specturm, in elements with respect to `T` (not `complex<T>`), with range [0, infinity)
288  * @param horizontalPaddingSourceBElements Optional horizontal padding at the end of each row of the second source specturm, in elements with respect to `T` (not `complex<T>`), with range [0, infinity)
289  * @param horizontalPaddingTargetElements Optional horizontal padding at the end of each row of the target specturm, in elements with respect to `T` (not `complex<T>`), with range [0, infinity)
290  * @tparam T The data type of the real and imaginary part of the complex number, e.g., 'float' or 'double'
291  * @tparam tComplexConjugateA True, to multiply the complex conjugated values of the first spectrum; False, to multiply the first spectrum without modification
292  * @tparam tComplexConjugateB True, to multiply the complex conjugated values of the first spectrum; False, to multiply the second spectrum without modification
293  */
294  template <typename T, bool tComplexConjugateA, bool tComplexConjugateB>
295  static void elementwiseMultiplication2(const T* complexSourceA, const T* complexSourceB, T* complexTarget, const unsigned int width, const unsigned int height, const unsigned int horizontalPaddingSourceAElements = 0u, const unsigned int horizontalPaddingSourceBElements = 0u, const unsigned int horizontalPaddingTargetElements = 0u);
296 
297  /**
298  * Multiplication of two 2D complex Fourier spectrums (one channel spectrums) in packed complex conjugate-symmetric format or CCS-packed format.
299  * For 2D one-channel data, the packed conjugate-symmetric format (CCS-packed format) is defined as follows:
300  *
301  * 1. Even width, \f$w = 2L\f$, and even height, \f$h = 2K\f$
302  *
303  * \f[\begin{bmatrix}
304  * R_{0,0} & R_{0,1} & I_{0,1} & R_{0,2} & \cdots & I_{0,L-1} & R_{0,L} \\
305  * R_{1,0} & R_{1,1} & I_{1,1} & R_{1,2} & \cdots & I_{1,L-1} & R_{1,L} \\
306  * I_{1,0} & R_{2,1} & I_{2,1} & R_{2,2} & \cdots & I_{2,L-1} & I_{1,L} \\
307  * R_{2,0} & R_{3,1} & I_{3,1} & R_{3,2} & \cdots & I_{3,L-1} & R_{2,L} \\
308  * \cdots & \cdots & \cdots & \cdots & \cdots & \cdots & \cdots \\
309  * I_{K-1,0} & R_{2K-2,1} & I_{2K-2,1} & R_{2K-2,2} & \cdots & I_{2K-2,L-1} & I_{K-1,L} \\
310  * R_{K,0} & R_{2K-1,1} & I_{2K-1,1} & R_{2K-1,2} & \cdots & I_{2K-1,L-1} & R_{K-1,L} \\
311  * \end{bmatrix}\in\mathbb{R}^{h \times w}\f]
312  *
313  * 2. Even width, \f$w = 2L\f$, and odd height, \f$h = 2K + 1\f$
314  *
315  * \f[\begin{bmatrix}
316  * R_{0,0} & R_{0,1} & I_{0,1} & R_{0,2} & \cdots & I_{0,L-1} & R_{0,L} \\
317  * R_{1,0} & R_{1,1} & I_{1,1} & R_{1,2} & \cdots & I_{1,L-1} & R_{1,L} \\
318  * I_{1,0} & R_{2,1} & I_{2,1} & R_{2,2} & \cdots & I_{2,L-1} & I_{1,L} \\
319  * R_{2,0} & R_{3,1} & I_{3,1} & R_{3,2} & \cdots & I_{3,L-1} & R_{2,L} \\
320  * \cdots & \cdots & \cdots & \cdots & \cdots & \cdots & \cdots \\
321  * I_{K-1,0} & R_{2K-2,1} & I_{2K-2,1} & R_{2K-2,2} & \cdots & I_{2K-2,L-1} & I_{K-1,L} \\
322  * R_{K,0} & R_{2K-1,1} & I_{2K-1,1} & R_{2K-1,2} & \cdots & I_{2K-1,L-1} & R_{K-1,L} \\
323  * I_{K,0} & R_{2K,1} & I_{2K,1} & R_{2K,2} & \cdots & I_{2K,L-1} & I_{K,L} \\
324  * \end{bmatrix}\in\mathbb{R}^{h \times w}\f]
325  *
326  * 3. Odd width, \f$w = 2L + 1\f$, and even height, \f$h = 2K\f$
327  *
328  * \f[\begin{bmatrix}
329  * R_{0,0} & R_{0,1} & I_{0,1} & R_{0,2} & \cdots & I_{0,L-1} & R_{0,L} & I_{0,L} \\
330  * R_{1,0} & R_{1,1} & I_{1,1} & R_{1,2} & \cdots & I_{1,L-1} & R_{1,L} & I_{1,L} \\
331  * I_{1,0} & R_{2,1} & I_{2,1} & R_{2,2} & \cdots & I_{2,L-1} & R_{2,L} & I_{2,L} \\
332  * R_{2,0} & R_{3,1} & I_{3,1} & R_{3,2} & \cdots & I_{3,L-1} & R_{3,L} & I_{3,L} \\
333  * \cdots & \cdots & \cdots & \cdots & \cdots & \cdots & \cdots & \cdots \\
334  * I_{K-1,0} & R_{2K-2,1} & I_{2K-2,1} & R_{2K-2,2} & \cdots & I_{2K-2,L-1} & R_{2K-2,L} & I_{2K-2,L} \\
335  * R_{K,0} & R_{2K-1,1} & I_{2K-1,1} & R_{2K-1,2} & \cdots & I_{2K-1,L-1} & R_{2K-1,L} & I_{2K-1,L} \\
336  * \end{bmatrix}\in\mathbb{R}^{h \times w}\f]
337  *
338  * 4. Odd width, \f$w = 2L + 1\f$, and odd height, \f$h = 2K + 1\f$
339  *
340  * \f[\begin{bmatrix}
341  * R_{0,0} & R_{0,1} & I_{0,1} & R_{0,2} & \cdots & I_{0,L-1} & R_{0,L} & I_{0,L} \\
342  * R_{1,0} & R_{1,1} & I_{1,1} & R_{1,2} & \cdots & I_{1,L-1} & R_{1,L} & I_{1,L} \\
343  * I_{1,0} & R_{2,1} & I_{2,1} & R_{2,2} & \cdots & I_{2,L-1} & R_{2,L} & I_{2,L} \\
344  * R_{2,0} & R_{3,1} & I_{3,1} & R_{3,2} & \cdots & I_{3,L-1} & R_{3,L} & I_{3,L} \\
345  * \cdots & \cdots & \cdots & \cdots & \cdots & \cdots & \cdots & \cdots \\
346  * I_{K-1,0} & R_{2K-2,1} & I_{2K-2,1} & R_{2K-2,2} & \cdots & I_{2K-2,L-1} & R_{2K-2,L} & I_{2K-2,L} \\
347  * R_{K,0} & R_{2K-1,1} & I_{2K-1,1} & R_{2K-1,2} & \cdots & I_{2K-1,L-1} & R_{2K-1,L} & I_{2K-1,L} \\
348  * I_{K,0} & R_{2K,1} & I_{2K,1} & R_{2K,2} & \cdots & I_{2K,L-1} & R_{2K,L} & I_{2K,L} \\
349  * \end{bmatrix}\in\mathbb{R}^{h \times w}\f]
350  *
351  * For 1D one-channel data, the format is defined as:
352  *
353  * 1. Even length, \f$l = \textbf{max}(w, h) = 2L\f$
354  *
355  * \f[\begin{bmatrix}
356  * R_{0} & R_{1} & I_{1} & R_{2} & \cdots & I_{L-1} & R_{L}
357  * \end{bmatrix}\in\mathbb{R}^{l}\f]
358  *
359  * 2. Odd length, \f$l = \textbf{max}(w, h) = 2L + 1\f$
360  *
361  * \f[\begin{bmatrix}
362  * R_{0} & R_{1} & I_{1} & R_{2} & \cdots & I_{L-1} & R_{L} & I_{L}
363  * \end{bmatrix}\in\mathbb{R}^{l}\f]
364  *
365  * The input data is expected to be in the CCS-packed format. The output is guaranteed to be in the CCS-packed format.
366  *
367  * More resources about the complex conjugate-symmetric format:
368  * - https://www.comp.nus.edu.sg/~cs4243/doc/ipl.pdf, page 157
369  * - https://software.intel.com/en-us/mkl-developer-reference-c-dfti-packed-format, DFTI_CCS_FORMAT for One/Two-dimensional Transforms
370  *
371  * @note For 1D and 2D one-channel input this function produces the same result as OpenCV's `cv::multspectums()` (requires that `TIntermediate=double`). For 2D two-channel input refer to the above function `elementwiseMultiplication2()`.
372  * @note For 1D and 2D one-channel data this function can take the output of OpenCV's `cv::dft()`
373  * @param sourceA The pointer of the first source spectrum, must be valid
374  * @param sourceB The pointer of the second source spectrum, must be valid
375  * @param target The pointer of the targt spectrum receiving the elementwise multiplication result, must be valid
376  * @param width The width of the input and output spectra, with range [1, infinity)
377  * @param height The height of the input and output spectra, with range [1, infinity)
378  * @param horizontalPaddingSourceAElements Optional horizontal padding at the end of each row of the first source specturm (number of complex elements), with range [0, infinity)
379  * @param horizontalPaddingSourceBElements Optional horizontal padding at the end of each row of the second source specturm (number of complex elements), with range [0, infinity)
380  * @param horizontalPaddingTargetElements Optional horizontal padding at the end of each row of the target specturm (number of complex elements), with range [0, infinity)
381  * @tparam TComplex Type of the real and imaginary parts of the complex numbers
382  * @tparam tComplexConjugateA If true, the conjugated values of `sourceA` will be used in the multiplication, otherwise they will be used as is
383  * @tparam tComplexConjugateB If true, the conjugated values of `sourceB` will be used in the multiplication, otherwise they will be used as is
384  * @tparam TIntermediate Type that is used internally for the computation. Size of this can be larger than `TComplex` which helps reduce float rounding errors.
385  */
386  template <typename TComplex, bool tComplexConjugateA, bool tComplexConjugateB, typename TIntermediate=double>
387  static void elementwiseMultiplicationCCS(const TComplex* sourceA, const TComplex* sourceB, TComplex* target, const unsigned int width, const unsigned int height, const unsigned int horizontalPaddingSourceAElements = 0u, const unsigned int horizontalPaddingSourceBElements = 0u, const unsigned int horizontalPaddingTargetElements = 0u);
388 
389  /**
390  * Elementwise division of two 2D complex Fourier spectrums (one channel spectrums).
391  * This function allows the definition of padding elements at the end of each row to support sub-specturms.
392  * @param complexSourceA The pointer of the first source spectrum, must be valid
393  * @param complexSourceB The pointer of the second source spectrum, must be valid
394  * @param complexTarget The pointer of the targt spectrum receiving the elementwise multiplication result, must be valid
395  * @param width The width of the 2D spectrum (the number of complex elements in horizontal direction), with range [1, infinity)
396  * @param height The height of the 2D specturm (the number of complex elements in vertical direction), with range [1, infinity)
397  * @param horizontalPaddingSourceAElements Optional horizontal padding at the end of each row of the first source specturm, in elements with respect to `T` (not `complex<T>`), with range [0, infinity)
398  * @param horizontalPaddingSourceBElements Optional horizontal padding at the end of each row of the second source specturm, in elements with respect to `T` (not `complex<T>`), with range [0, infinity)
399  * @param horizontalPaddingTargetElements Optional horizontal padding at the end of each row of the target specturm, in elements with respect to `T` (not `complex<T>`), with range [0, infinity)
400  * @tparam T The data type of the real and imaginary part of the complex number, e.g., 'float' or 'double'
401  */
402  template <typename T>
403  static void elementwiseDivision2(const T* complexSourceA, const T* complexSourceB, T* complexTarget, const unsigned int width, const unsigned int height, const unsigned int horizontalPaddingSourceAElements = 0u, const unsigned int horizontalPaddingSourceBElements = 0u, const unsigned int horizontalPaddingTargetElements = 0u);
404 };
405 
406 template <typename T>
407 inline void FourierTransformation::NaiveImplementation::spatialToFrequency2(const std::complex<T>* spatial, const unsigned int width, const unsigned int height, std::complex<T>* frequency, Worker* worker)
408 {
409  ocean_assert(spatial && frequency);
410  std::vector< std::complex<T> > frequencyHorizontal(width * height);
411 
412  if (worker)
413  {
414  worker->executeFunction(Worker::Function::createStatic(spatialToFrequencyHorizontalSubset2<T>, spatial, width, height, frequencyHorizontal.data(), 0u, 0u), 0u, height);
415  worker->executeFunction(Worker::Function::createStatic(spatialToFrequencyVerticalSubset2<T>, (const std::complex<T>*)frequencyHorizontal.data(), width, height, frequency, 0u, 0u), 0u, width);
416  }
417  else
418  {
419  spatialToFrequencyHorizontalSubset2<T>(spatial, width, height, frequencyHorizontal.data(), 0u, height);
420  spatialToFrequencyVerticalSubset2<T>(frequencyHorizontal.data(), width, height, frequency, 0u, width);
421  }
422 }
423 
424 template <typename T>
425 inline void FourierTransformation::NaiveImplementation::frequencyToSpatial2(const std::complex<T>* frequency, const unsigned int width, const unsigned int height, std::complex<T>* spatial, Worker* worker)
426 {
427  ocean_assert(frequency && spatial);
428  std::vector< std::complex<T> > spatialHorizontal(width * height);
429 
430  if (worker)
431  {
432  worker->executeFunction(Worker::Function::createStatic(frequencyToSpatialHorizontalSubset2<T>, frequency, width, height, spatialHorizontal.data(), 0u, 0u), 0u, height);
433  worker->executeFunction(Worker::Function::createStatic(frequencyToSpatialVerticalSubset2<T>, (const std::complex<T>*)spatialHorizontal.data(), width, height, spatial, 0u, 0u), 0u, width);
434  }
435  else
436  {
437  frequencyToSpatialHorizontalSubset2<T>(frequency, width, height, spatialHorizontal.data(), 0u, height);
438  frequencyToSpatialVerticalSubset2<T>(spatialHorizontal.data(), width, height, spatial, 0u, width);
439  }
440 }
441 
442 template <typename T>
443 void FourierTransformation::NaiveImplementation::spatialToFrequencyHorizontalSubset2(const std::complex<T>* spatial, const unsigned int width, const unsigned int height, std::complex<T>* frequencyHorizontal, const unsigned int firstRow, const unsigned int numberRows)
444 {
445  ocean_assert(spatial && frequencyHorizontal);
446  ocean_assert_and_suppress_unused(firstRow + numberRows <= height, height);
447  ocean_assert(width != 0u);
448 
449  const T pi2_width_1 = NumericT<T>::pi2() / T(width);
450 
451  std::complex<T> value;
452 
453  for (unsigned int r = firstRow; r < firstRow + numberRows; ++r)
454  {
455  const std::complex<T>* const signal = spatial + r * width;
456  std::complex<T>* const spectrum = frequencyHorizontal + r * width;
457 
458  for (unsigned int k = 0u; k < width; ++k)
459  {
460  value = Complex(0, 0);
461 
462  for (unsigned int n = 0u; n < width; ++n)
463  {
464  const T angle = pi2_width_1 * T(n * k);
465  value += signal[n] * std::complex<T>(NumericT<T>::cos(angle), -NumericT<T>::sin(angle));
466  }
467 
468  spectrum[k] = value;
469  }
470  }
471 }
472 
473 template <typename T>
474 void FourierTransformation::NaiveImplementation::spatialToFrequencyVerticalSubset2(const std::complex<T>* spatial, const unsigned int width, const unsigned int height, std::complex<T>* frequencyVertical, const unsigned int firstColumn, const unsigned int numberColumns)
475 {
476  ocean_assert(spatial && frequencyVertical);
477  ocean_assert(firstColumn + numberColumns <= width);
478  ocean_assert(height != 0u);
479 
480  const T pi2_height_1 = NumericT<T>::pi2() / T(height);
481 
482  std::complex<T> value;
483 
484  for (unsigned int c = firstColumn; c < firstColumn + numberColumns; ++c)
485  {
486  const std::complex<T>* const signal = spatial + c;
487  std::complex<T>* const spectrum = frequencyVertical + c;
488 
489  for (unsigned int k = 0u; k < height; ++k)
490  {
491  value = Complex(0, 0);
492 
493  for (unsigned int n = 0u; n < height; ++n)
494  {
495  const T angle = pi2_height_1 * T(n * k);
496  value += signal[n * width] * std::complex<T>(NumericT<T>::cos(angle), -NumericT<T>::sin(angle));
497  }
498 
499  spectrum[k * width] = value;
500  }
501  }
502 }
503 
504 template <typename T>
505 void FourierTransformation::NaiveImplementation::frequencyToSpatialHorizontalSubset2(const std::complex<T>* frequency, const unsigned int width, const unsigned int height, std::complex<T>* spatialHorizontal, const unsigned int firstRow, const unsigned int numberRows)
506 {
507  ocean_assert(frequency && spatialHorizontal);
508  ocean_assert_and_suppress_unused(firstRow + numberRows <= height, height);
509  ocean_assert(width != 0u);
510 
511  const T pi2_width_1 = NumericT<T>::pi2() / T(width);
512  const T normalization = T(1) / T(width);
513 
514  std::complex<T> value;
515 
516  for (unsigned int r = firstRow; r < firstRow + numberRows; ++r)
517  {
518  const std::complex<T>* const spectrum = frequency + r * width;
519  std::complex<T>* const signal = spatialHorizontal + r * width;
520 
521  for (unsigned int n = 0; n < width; ++n)
522  {
523  value = Complex(0, 0);
524 
525  for (unsigned int k = 0; k < width; ++k)
526  {
527  const T angle = pi2_width_1 * T(k * n);
528  value += spectrum[k] * std::complex<T>(NumericT<T>::cos(angle), NumericT<T>::sin(angle));
529  }
530 
531  signal[n] = value * normalization;
532  }
533  }
534 }
535 
536 template <typename T>
537 void FourierTransformation::NaiveImplementation::frequencyToSpatialVerticalSubset2(const std::complex<T>* frequency, const unsigned int width, const unsigned int height, std::complex<T>* spatialVertical, const unsigned int firstColumn, const unsigned int numberColumns)
538 {
539  ocean_assert(frequency && spatialVertical);
540  ocean_assert(firstColumn + numberColumns <= width);
541  ocean_assert(height != 0u);
542 
543  const T pi2_height_1 = NumericT<T>::pi2() / T(height);
544  const T normalization = T(1) / T(height);
545 
546  std::complex<T> value;
547 
548  for (unsigned int c = firstColumn; c < firstColumn + numberColumns; ++c)
549  {
550  const std::complex<T>* const spectrum = frequency + c;
551  std::complex<T>* const signal = spatialVertical + c;
552 
553  for (unsigned int n = 0u; n < height; ++n)
554  {
555  value = Complex(0, 0);
556 
557  for (unsigned int k = 0; k < height; ++k)
558  {
559  const T angle = pi2_height_1 * T(k * n);
560  value += spectrum[k * width] * std::complex<T>(NumericT<T>::cos(angle), NumericT<T>::sin(angle));
561  }
562 
563  signal[n * width] = value * normalization;
564  }
565  }
566 }
567 
568 template <typename TScalar, typename TComplex>
569 inline void FourierTransformation::scalarToComplex(const TScalar* source, std::complex<TComplex>* target, const size_t number)
570 {
571  ocean_assert(source && target);
572 
573  for (size_t n = 0; n < number; ++n)
574  target[n] = Complex(source[n], 0);
575 }
576 
577 template <typename TComplex, typename TScalar>
578 inline void FourierTransformation::realToScalar(const std::complex<TComplex>* source, TScalar* target, const size_t number)
579 {
580  ocean_assert(source && target);
581 
582  for (size_t n = 0; n < number; ++n)
583  target[n] = source[n].real();
584 }
585 
586 template <typename TComplex, typename TScalar>
587 inline void FourierTransformation::imaginaryToScalar(const std::complex<TComplex>* source, TScalar* target, const size_t number)
588 {
589  ocean_assert(source && target);
590 
591  for (size_t n = 0; n < number; ++n)
592  target[n] = source[n].imag();
593 }
594 
595 template <typename TComplex, typename TScalar>
596 inline void FourierTransformation::complexToMagnitude(const std::complex<TComplex>* source, TScalar* target, const size_t number)
597 {
598  ocean_assert(source && target);
599 
600  for (size_t n = 0; n < number; ++n)
601  target[n] = std::abs(source[n]);
602 }
603 
604 template <typename T>
605 void FourierTransformation::shiftHalfDimension2(const T* source, unsigned int width, const unsigned int height, T* target)
606 {
607  ocean_assert(source && target);
608  ocean_assert(width % 2u == 0u);
609  ocean_assert(height % 2u == 0u);
610 
611  const unsigned int width2 = width / 2u;
612  const unsigned int height2 = height / 2u;
613 
614  for (unsigned int y = 0u; y < height; ++y)
615  for (unsigned int x = 0u; x < width; ++x)
616  target[((y + height2) % height) * width + ((x + width2) % width)] = *source++;
617 }
618 
619 template <typename T>
620 void FourierTransformation::shiftHalfDimension2(T* data, unsigned int width, const unsigned int height)
621 {
622  ocean_assert(data);
623 
624  // if the frame dimension is a multiple of two
625  if (width % 2u == 0u && height % 2u == 0u)
626  {
627  const unsigned int width_2 = width / 2u;
628  const unsigned int height_2 = height / 2u;
629 
630  for (unsigned int y = 0u; y < height_2; ++y)
631  for (unsigned int x = 0u; x < width_2; ++x)
632  {
633  // swap top left with bottom right
634  std::swap(data[y * width + x], data[(y + height_2) * width + x + width_2]);
635 
636  // swap bottom left with top right
637  std::swap(data[(y + height_2) * width + x], data[y * width + x + width_2]);
638  }
639  }
640  else
641  {
642  Memory tmpMemory = Memory::create<T>(width * height);
643  T* tmp = tmpMemory.data<T>();
644 
645  ocean_assert(tmp != nullptr);
646 
647  memcpy(tmp, data, width * height * sizeof(T));
648 
649  const unsigned int width_2 = width / 2u;
650  const unsigned int height_2 = height / 2u;
651 
652  const unsigned int extraX = width % 2u;
653  const unsigned int extraY = height % 2u;
654 
655  for (unsigned int y = 0u; y < height_2 + extraY; ++y)
656  {
657  // top left to bottom right
658  memcpy(data + (y + height_2) * width + width_2, tmp + y * width, (width_2 + extraX) * sizeof(T));
659 
660  // top right to bottom left
661  memcpy(data + (y + height_2) * width, tmp + y * width + width_2 + extraX, width_2 * sizeof(T));
662  }
663 
664  for (unsigned int y = 0u; y < height_2; ++y)
665  {
666  // bottom right to top left
667  memcpy(data + y * width, tmp + (y + height_2 + extraY) * width + width_2 + extraX, width_2 * sizeof(T));
668 
669  // bottom left to top right
670  memcpy(data + y * width + width_2 + extraX, tmp + (y + height_2 + extraY) * width, (width_2 + extraX) * sizeof(T));
671  }
672 
673  ocean_assert(data[shiftCenter(height) * width + shiftCenter(width)] == tmp[0]);
674  }
675 }
676 
677 inline unsigned int FourierTransformation::shiftCenter(const unsigned int size)
678 {
679  return size / 2u;
680 }
681 
682 template <typename T, bool tComplexConjugateA, bool tComplexConjugateB>
683 void FourierTransformation::elementwiseMultiplication2(const T* complexSourceA, const T* complexSourceB, T* complexTarget, const unsigned int width, const unsigned int height, const unsigned int horizontalPaddingSourceAElements, const unsigned int horizontalPaddingSourceBElements, const unsigned int horizontalPaddingTargetElements)
684 {
685  static_assert(std::is_same<T, float>::value || std::is_same<T, double>::value, "Invalid data type!");
686  static_assert(sizeof(std::complex<T>) == sizeof(T) * 2, "Invalid data type!");
687 
688  ocean_assert(complexSourceA != nullptr && complexSourceB != nullptr && complexTarget != nullptr);
689  ocean_assert(width != 0u && height != 0u);
690 
691  const unsigned int complexSourceAStrideElements = width * 2u + horizontalPaddingSourceAElements;
692  const unsigned int complexSourceBStrideElements = width * 2u + horizontalPaddingSourceBElements;
693  const unsigned int complexTargetStrideElements = width * 2u + horizontalPaddingTargetElements;
694 
695  for (unsigned int y = 0u; y < height; ++y)
696  {
697  const std::complex<T>* const sourceARow = (const std::complex<T>*)(complexSourceA + y * complexSourceAStrideElements);
698  const std::complex<T>* const sourceBRow = (const std::complex<T>*)(complexSourceB + y * complexSourceBStrideElements);
699  std::complex<T>* const targetRow = (std::complex<T>*)(complexTarget + y * complexTargetStrideElements);
700 
701  if constexpr (tComplexConjugateA && tComplexConjugateB)
702  {
703  for (unsigned int x = 0u; x < width; ++x)
704  {
705  targetRow[x] = std::conj(sourceARow[x]) * std::conj(sourceBRow[x]);
706  }
707  }
708  else if constexpr (tComplexConjugateA && !tComplexConjugateB)
709  {
710  for (unsigned int x = 0u; x < width; ++x)
711  {
712  targetRow[x] = std::conj(sourceARow[x]) * sourceBRow[x];
713  }
714  }
715  else if constexpr (!tComplexConjugateA && tComplexConjugateB)
716  {
717  for (unsigned int x = 0u; x < width; ++x)
718  {
719  targetRow[x] = sourceARow[x] * std::conj(sourceBRow[x]);
720  }
721  }
722  else
723  {
724  for (unsigned int x = 0u; x < width; ++x)
725  {
726  targetRow[x] = sourceARow[x] * sourceBRow[x];
727  }
728  }
729  }
730 }
731 
732 template <typename TComplex, bool tComplexConjugateA, bool tComplexConjugateB, typename TIntermediate>
733 void FourierTransformation::elementwiseMultiplicationCCS(const TComplex* sourceA, const TComplex* sourceB, TComplex* target, const unsigned int width, const unsigned int height, const unsigned int horizontalPaddingSourceAElements, const unsigned int horizontalPaddingSourceBElements, const unsigned int horizontalPaddingTargetElements)
734 {
735  ocean_assert(sourceA && sourceB && target);
736  ocean_assert(width != 0u && height != 0u);
737 
738  const size_t sourceAStrideElements = width + horizontalPaddingSourceAElements;
739  const size_t sourceBStrideElements = width + horizontalPaddingSourceBElements;
740  const size_t targetStrideElements = width + horizontalPaddingTargetElements;
741 
742  const bool isOneDimensionalData = width == 1u || height == 1u;
743 
744  if (isOneDimensionalData)
745  {
746  // First element
747  target[0] = (TComplex)((TIntermediate)sourceA[0] * (TIntermediate)sourceB[0]);
748 
749  // Middle elements
750  const unsigned int elementsCount = std::max(width, height);
751  const unsigned int lastElement = elementsCount - 1u;
752 
753  for (unsigned int j = 1u; j < elementsCount; j += 2)
754  {
755  const TIntermediate realA = (TIntermediate)sourceA[j];
756  const TIntermediate imaginaryA = (TIntermediate)(tComplexConjugateA ? -sourceA[j + 1u] : sourceA[j + 1u]);
757 
758  const TIntermediate realB = (TIntermediate)sourceB[j];
759  const TIntermediate imaginaryB = (TIntermediate)(tComplexConjugateB ? -sourceB[j + 1u] : sourceB[j + 1u]);
760 
761  target[j] = (TComplex)((realA * realB) - (imaginaryA * imaginaryB));
762  target[j + 1u] = (TComplex)((imaginaryA * realB) + (realA * imaginaryB));
763  }
764 
765  // Last element
766  if (elementsCount % 2u == 0u)
767  {
768  target[lastElement] = (TComplex)((TIntermediate)sourceA[lastElement] * (TIntermediate)sourceB[lastElement]);
769  }
770  }
771  else
772  {
773  const unsigned int lastRowIndex = height - 1u;
774  const unsigned int lastColumnIndex = width - 1u;
775  const bool isWidthEven = width % 2u == 0u;
776  const bool isHeightEven = height % 2u == 0u;
777 
778  // Left-most column
779  target[0] = (TComplex)((TIntermediate)sourceA[0] * (TIntermediate)sourceB[0]);
780 
781  for (unsigned int row = 1u; row < lastRowIndex; row += 2u)
782  {
783  const TIntermediate realA = (TIntermediate)sourceA[row * sourceAStrideElements];
784  const TIntermediate imaginaryA = (TIntermediate)(tComplexConjugateA ? -sourceA[(row + 1u) * sourceAStrideElements] : sourceA[(row + 1u) * sourceAStrideElements]);
785 
786  const TIntermediate realB = (TIntermediate)sourceB[row * sourceBStrideElements];
787  const TIntermediate imaginaryB = (TIntermediate)(tComplexConjugateB ? -sourceB[(row + 1u) * sourceBStrideElements] : sourceB[(row + 1u) * sourceBStrideElements]);
788 
789  target[row * targetStrideElements] = (TComplex)((realA * realB) - (imaginaryA * imaginaryB));
790  target[(row + 1u) * targetStrideElements] = (TComplex)((imaginaryA * realB) + (realA * imaginaryB));
791  }
792 
793  // Bottom-left element, if height is even
794  if (isHeightEven)
795  {
796  target[lastRowIndex * targetStrideElements] = (TComplex)((TIntermediate)sourceA[lastRowIndex * sourceAStrideElements] * (TIntermediate)sourceB[lastRowIndex * sourceBStrideElements]);
797  }
798 
799  // Right-most column, if width is even
800  if (isWidthEven)
801  {
802  target[lastColumnIndex] = sourceA[lastColumnIndex] * sourceB[lastColumnIndex];
803 
804  for (unsigned int row = 1u; row < lastRowIndex; row += 2u)
805  {
806  const TIntermediate realA = (TIntermediate)sourceA[row * sourceAStrideElements + lastColumnIndex];
807  const TIntermediate imaginaryA = (TIntermediate)(tComplexConjugateA ? -sourceA[(row + 1u) * sourceAStrideElements + lastColumnIndex] : sourceA[(row + 1u) * sourceAStrideElements + lastColumnIndex]);
808 
809  const TIntermediate realB = (TIntermediate)sourceB[row * sourceBStrideElements + lastColumnIndex];
810  const TIntermediate imaginaryB = (TIntermediate)(tComplexConjugateB ? -sourceB[(row + 1u) * sourceBStrideElements + lastColumnIndex] : sourceB[(row + 1u) * sourceBStrideElements + lastColumnIndex]);
811 
812  target[row * targetStrideElements + lastColumnIndex] = (TComplex)((realA * realB) - (imaginaryA * imaginaryB));
813  target[(row + 1u) * targetStrideElements + lastColumnIndex] = (TComplex)((imaginaryA * realB) + (realA * imaginaryB));
814  }
815 
816  // Bottom-right element, if height is even
817  if (isHeightEven)
818  {
819  target[lastRowIndex * targetStrideElements + lastColumnIndex] = (TComplex)((TIntermediate)sourceA[lastRowIndex * sourceAStrideElements + lastColumnIndex] * (TIntermediate)sourceB[lastRowIndex * sourceBStrideElements + lastColumnIndex]);
820  }
821  }
822 
823  // Middle columns
824  const unsigned int columnEnd = width - (isWidthEven ? 1u : 0u);
825 
826  for (unsigned int row = 0u; row < height; ++row)
827  {
828  for (unsigned int column = 1u; column < columnEnd; column += 2u)
829  {
830  const TIntermediate realA = (TIntermediate)sourceA[column];
831  const TIntermediate imaginaryA = (TIntermediate)(tComplexConjugateA ? -sourceA[column + 1u] : sourceA[column + 1u]);
832 
833  const TIntermediate realB = (TIntermediate)sourceB[column];
834  const TIntermediate imaginaryB = (TIntermediate)(tComplexConjugateB ? -sourceB[column + 1u] : sourceB[column + 1u]);
835 
836  target[column] = (TComplex)((realA * realB) - (imaginaryA * imaginaryB));
837  target[column + 1u] = (TComplex)((imaginaryA * realB) + (realA * imaginaryB));
838  }
839 
840  sourceA += sourceAStrideElements;
841  sourceB += sourceBStrideElements;
842  target += targetStrideElements;
843  }
844  }
845 }
846 
847 template <typename T>
848 void FourierTransformation::elementwiseDivision2(const T* complexSourceA, const T* complexSourceB, T* complexTarget, const unsigned int width, const unsigned int height, const unsigned int horizontalPaddingSourceAElements, const unsigned int horizontalPaddingSourceBElements, const unsigned int horizontalPaddingTargetElements)
849 {
850  static_assert(std::is_same<T, float>::value || std::is_same<T, double>::value, "Invalid data type!");
851  static_assert(sizeof(std::complex<T>) == sizeof(T) * 2, "Invalid data type!");
852 
853  ocean_assert(complexSourceA != nullptr && complexSourceB != nullptr && complexTarget != nullptr);
854  ocean_assert(width != 0u && height != 0u);
855 
856  const unsigned int complexSourceAStrideElements = width * 2u + horizontalPaddingSourceAElements;
857  const unsigned int complexSourceBStrideElements = width * 2u + horizontalPaddingSourceBElements;
858  const unsigned int complexTargetStrideElements = width * 2u + horizontalPaddingTargetElements;
859 
860  // (a + bi) / (c + di)
861  // = [(ac + bd) + i(bc - ad)] / (c^2 + d^2)
862 
863  for (unsigned int y = 0u; y < height; ++y)
864  {
865  const std::complex<T>* const sourceARow = (const std::complex<T>*)(complexSourceA + y * complexSourceAStrideElements);
866  const std::complex<T>* const sourceBRow = (const std::complex<T>*)(complexSourceB + y * complexSourceBStrideElements);
867  std::complex<T>* const targetRow = (std::complex<T>*)(complexTarget + y * complexTargetStrideElements);
868 
869  for (unsigned int x = 0u; x < width; ++x)
870  {
871  const T denominator = sourceBRow[x].real() * sourceBRow[x].real() + sourceBRow[x].imag() * sourceBRow[x].imag();
872  ocean_assert(NumericT<T>::isNotEqualEps(denominator));
873 
874  const T invDenominator = T(1.0) / denominator;
875 
876  targetRow[x] = std::complex<T>((sourceARow[x].real() * sourceBRow[x].real() + sourceARow[x].imag() * sourceBRow[x].imag()) * invDenominator,
877  (sourceARow[x].imag() * sourceBRow[x].real() - sourceARow[x].real() * sourceBRow[x].imag()) * invDenominator);
878  }
879  }
880 }
881 
882 } // namespace Ocean
883 
884 #endif // META_OCEAN_MATH_FOURIER_TRANSFORMATION_H
static Caller< void > createStatic(typename StaticFunctionPointerMaker< void, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass >::Type function)
Creates a new caller container for a static function with no function parameter.
Definition: Caller.h:2876
This class provides the implementation of the Fourier transformation of the Ocean framework.
Definition: FourierTransformation.h:34
static void spatialToFrequencyVerticalSubset2(const std::complex< T > *spatial, const unsigned int width, const unsigned int height, std::complex< T > *frequencyVertical, const unsigned int firstColumn, const unsigned int numberColumns)
Applies a vertical forward Fourier transformation for a subset of a given 2D spatial signal.
Definition: FourierTransformation.h:474
static void frequencyToSpatialHorizontalSubset2(const std::complex< T > *frequency, const unsigned int width, const unsigned int height, std::complex< T > *spatialHorizontal, const unsigned int firstRow, const unsigned int numberRows)
Applies a horizontal backward Fourier transformation for subset of a given 2D frequency signal.
Definition: FourierTransformation.h:505
static void frequencyToSpatial2(const std::complex< T > *frequency, const unsigned int width, const unsigned int height, std::complex< T > *spatial, Worker *worker=nullptr)
Applies a backward Fourier transformation for a given 2D frequency signal.
Definition: FourierTransformation.h:425
static void spatialToFrequencyHorizontalSubset2(const std::complex< T > *spatial, const unsigned int width, const unsigned int height, std::complex< T > *frequencyHorizontal, const unsigned int firstRow, const unsigned int numberRows)
Applies a horizontal forward Fourier transformation for a subset of a given 2D spatial signal.
Definition: FourierTransformation.h:443
static void spatialToFrequency2(const std::complex< T > *spatial, const unsigned int width, const unsigned int height, std::complex< T > *frequency, Worker *worker=nullptr)
Applies a forward Fourier transformation for a given 2D spatial signal.
Definition: FourierTransformation.h:407
static void frequencyToSpatialVerticalSubset2(const std::complex< T > *frequency, const unsigned int width, const unsigned int height, std::complex< T > *spatialVertical, const unsigned int firstColumn, const unsigned int numberColumns)
Applies a vertical backward Fourier transformation for a subset of a given 2D frequency signal.
Definition: FourierTransformation.h:537
This class implements Fourier transformation functions.
Definition: FourierTransformation.h:27
static void scalarToComplex(const TScalar *source, std::complex< TComplex > *target, const size_t number)
Converts scalar values to complex values.
Definition: FourierTransformation.h:569
static void imaginaryToScalar(const std::complex< TComplex > *source, TScalar *target, const size_t number)
Converts the imaginary components of complex values to scalar values.
Definition: FourierTransformation.h:587
static void shiftHalfDimension2(const T *source, unsigned int width, const unsigned int height, T *target)
Shifts a given signal by half of the width and the height.
Definition: FourierTransformation.h:605
static bool dft0(const void *source, const unsigned int width, const unsigned int height, const unsigned int sourceChannels, void *target, const unsigned int targetChannels, const Ocean::FrameType::DataType dataType, int flags, int nonzero_rows, const unsigned int sourcePaddingElements=0u, const unsigned int targetPaddingElements=0u)
Direct Fourier Transformation (OpenCV-compatible interface)
static void complexToMagnitude(const std::complex< TComplex > *source, TScalar *target, const size_t number)
Converts complex values to magnitude (or absolute) values.
Definition: FourierTransformation.h:596
static int getOptimalDFTSize0(int size)
Returns the optimal DFT size for a given vector size.
static void elementwiseMultiplication2(const T *complexSourceA, const T *complexSourceB, T *complexTarget, const unsigned int width, const unsigned int height, const unsigned int horizontalPaddingSourceAElements=0u, const unsigned int horizontalPaddingSourceBElements=0u, const unsigned int horizontalPaddingTargetElements=0u)
Elementwise multiplication of two 2D complex Fourier spectrums (one channel spectrums).
Definition: FourierTransformation.h:683
static bool dft0(const Frame &source, Frame &target, int flags, int nonzero_rows)
Direct Fourier Transformation (OpenCV-compatible interface)
static unsigned int shiftCenter(const unsigned int size)
Returns the center position for shift operations that corresponds with the first Fourier element.
Definition: FourierTransformation.h:677
static void realToScalar(const std::complex< TComplex > *source, TScalar *target, const size_t number)
Converts the real components of complex values to scalar values.
Definition: FourierTransformation.h:578
static void spatialToFrequency2(const T *spatial, const unsigned int width, const unsigned int height, T *complexFrequency, const unsigned int spatialPaddingElements=0u, const unsigned int frequencyPaddingElements=0u)
Applies a forward Fourier transformation for a given 2D (real) spatial signal.
static void frequencyToSpatial2(const T *complexFrequency, const unsigned int width, const unsigned int height, T *spatial, const unsigned int frequencyPaddingElements=0u, const unsigned int spatialPaddingElements=0u)
Applies a backward Fourier transformation for a given 2D frequency signal.
static void frequencyToComplexSpatial2(const T *complexFrequency, const unsigned int width, const unsigned int height, T *complexSpatial, const unsigned int frequencyPaddingElements=0u, const unsigned int spatialPaddingElements=0u)
Applies a backward Fourier transformation for a given 2D frequency signal.
static void elementwiseMultiplicationCCS(const TComplex *sourceA, const TComplex *sourceB, TComplex *target, const unsigned int width, const unsigned int height, const unsigned int horizontalPaddingSourceAElements=0u, const unsigned int horizontalPaddingSourceBElements=0u, const unsigned int horizontalPaddingTargetElements=0u)
Multiplication of two 2D complex Fourier spectrums (one channel spectrums) in packed complex conjugat...
Definition: FourierTransformation.h:733
static void elementwiseDivision2(const T *complexSourceA, const T *complexSourceB, T *complexTarget, const unsigned int width, const unsigned int height, const unsigned int horizontalPaddingSourceAElements=0u, const unsigned int horizontalPaddingSourceBElements=0u, const unsigned int horizontalPaddingTargetElements=0u)
Elementwise division of two 2D complex Fourier spectrums (one channel spectrums).
Definition: FourierTransformation.h:848
static void complexSpatialToFrequency2(const T *complexSpatial, const unsigned int width, const unsigned int height, T *complexFrequency, const unsigned int spatialPaddingElements=0u, const unsigned int frequencyPaddingElements=0u)
Applies a forward Fourier transformation for a given 2D (complex) spatial signal.
This class implements Ocean's image class.
Definition: Frame.h:1760
DataType
Definition of individual channel data type.
Definition: Frame.h:37
This class implements an object able to allocate memory.
Definition: base/Memory.h:22
void * data()
Returns the pointer to the writable memory which is allocated by this object.
Definition: base/Memory.h:303
This class provides basic numeric functionalities.
Definition: Numeric.h:57
static constexpr T pi2()
Returns 2*PI which is equivalent to 360 degree.
Definition: Numeric.h:932
This class implements a worker able to distribute function calls over different threads.
Definition: Worker.h:33
bool executeFunction(const Function &function, const unsigned int first, const unsigned int size, const unsigned int firstIndex=(unsigned int)(-1), const unsigned int sizeIndex=(unsigned int)(-1), const unsigned int minimalIterations=1u, const unsigned int threadIndex=(unsigned int)(-1))
Executes a callback function separable by two function parameters.
std::complex< Scalar > Complex
Definition of a complex number based on the default floating point precision data type.
Definition: Complex.h:34
The namespace covering the entire Ocean framework.
Definition: Accessor.h:15