Ocean
Loading...
Searching...
No Matches
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
19namespace Ocean
20{
21
22/**
23 * This class implements Fourier transformation functions.
24 * @ingroup math
25 */
26class 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 * A one-dimensional spectrum can be stored as a single row or as a single column.
366 * In a single row the elements are contiguous and the padding follows behind them, in a single column consecutive elements are one row stride apart.
367 *
368 * The input data is expected to be in the CCS-packed format. The output is guaranteed to be in the CCS-packed format.
369 *
370 * More resources about the complex conjugate-symmetric format:
371 * - https://www.comp.nus.edu.sg/~cs4243/doc/ipl.pdf, page 157
372 * - https://software.intel.com/en-us/mkl-developer-reference-c-dfti-packed-format, DFTI_CCS_FORMAT for One/Two-dimensional Transforms
373 *
374 * @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()`.
375 * @note For 1D and 2D one-channel data this function can take the output of OpenCV's `cv::dft()`
376 * @param sourceA The pointer of the first source spectrum, must be valid
377 * @param sourceB The pointer of the second source spectrum, must be valid
378 * @param target The pointer of the targt spectrum receiving the elementwise multiplication result, must be valid
379 * @param width The width of the input and output spectra, with range [1, infinity)
380 * @param height The height of the input and output spectra, with range [1, infinity)
381 * @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)
382 * @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)
383 * @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)
384 * @tparam TComplex Type of the real and imaginary parts of the complex numbers
385 * @tparam tComplexConjugateA If true, the conjugated values of `sourceA` will be used in the multiplication, otherwise they will be used as is
386 * @tparam tComplexConjugateB If true, the conjugated values of `sourceB` will be used in the multiplication, otherwise they will be used as is
387 * @tparam TIntermediate Type that is used internally for the computation. Size of this can be larger than `TComplex` which helps reduce float rounding errors.
388 */
389 template <typename TComplex, bool tComplexConjugateA, bool tComplexConjugateB, typename TIntermediate=double>
390 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);
391
392 /**
393 * Elementwise division of two 2D complex Fourier spectrums (one channel spectrums).
394 * This function allows the definition of padding elements at the end of each row to support sub-specturms.
395 * @param complexSourceA The pointer of the first source spectrum, must be valid
396 * @param complexSourceB The pointer of the second source spectrum, must be valid
397 * @param complexTarget The pointer of the targt spectrum receiving the elementwise multiplication result, must be valid
398 * @param width The width of the 2D spectrum (the number of complex elements in horizontal direction), with range [1, infinity)
399 * @param height The height of the 2D specturm (the number of complex elements in vertical direction), with range [1, infinity)
400 * @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)
401 * @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)
402 * @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)
403 * @tparam T The data type of the real and imaginary part of the complex number, e.g., 'float' or 'double'
404 */
405 template <typename T>
406 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);
407};
408
409template <typename T>
410inline void FourierTransformation::NaiveImplementation::spatialToFrequency2(const std::complex<T>* spatial, const unsigned int width, const unsigned int height, std::complex<T>* frequency, Worker* worker)
411{
412 ocean_assert(spatial && frequency);
413 std::vector< std::complex<T> > frequencyHorizontal(width * height);
414
415 if (worker)
416 {
417 worker->executeFunction(Worker::Function::createStatic(spatialToFrequencyHorizontalSubset2<T>, spatial, width, height, frequencyHorizontal.data(), 0u, 0u), 0u, height);
418 worker->executeFunction(Worker::Function::createStatic(spatialToFrequencyVerticalSubset2<T>, (const std::complex<T>*)frequencyHorizontal.data(), width, height, frequency, 0u, 0u), 0u, width);
419 }
420 else
421 {
422 spatialToFrequencyHorizontalSubset2<T>(spatial, width, height, frequencyHorizontal.data(), 0u, height);
423 spatialToFrequencyVerticalSubset2<T>(frequencyHorizontal.data(), width, height, frequency, 0u, width);
424 }
425}
426
427template <typename T>
428inline void FourierTransformation::NaiveImplementation::frequencyToSpatial2(const std::complex<T>* frequency, const unsigned int width, const unsigned int height, std::complex<T>* spatial, Worker* worker)
429{
430 ocean_assert(frequency && spatial);
431 std::vector< std::complex<T> > spatialHorizontal(width * height);
432
433 if (worker)
434 {
435 worker->executeFunction(Worker::Function::createStatic(frequencyToSpatialHorizontalSubset2<T>, frequency, width, height, spatialHorizontal.data(), 0u, 0u), 0u, height);
436 worker->executeFunction(Worker::Function::createStatic(frequencyToSpatialVerticalSubset2<T>, (const std::complex<T>*)spatialHorizontal.data(), width, height, spatial, 0u, 0u), 0u, width);
437 }
438 else
439 {
440 frequencyToSpatialHorizontalSubset2<T>(frequency, width, height, spatialHorizontal.data(), 0u, height);
441 frequencyToSpatialVerticalSubset2<T>(spatialHorizontal.data(), width, height, spatial, 0u, width);
442 }
443}
444
445template <typename T>
446void 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)
447{
448 ocean_assert(spatial && frequencyHorizontal);
449 ocean_assert_and_suppress_unused(firstRow + numberRows <= height, height);
450 ocean_assert(width != 0u);
451
452 const T pi2_width_1 = NumericT<T>::pi2() / T(width);
453
454 std::complex<T> value;
455
456 for (unsigned int r = firstRow; r < firstRow + numberRows; ++r)
457 {
458 const std::complex<T>* const signal = spatial + r * width;
459 std::complex<T>* const spectrum = frequencyHorizontal + r * width;
460
461 for (unsigned int k = 0u; k < width; ++k)
462 {
463 value = Complex(0, 0);
464
465 for (unsigned int n = 0u; n < width; ++n)
466 {
467 const T angle = pi2_width_1 * T(n * k);
468 value += signal[n] * std::complex<T>(NumericT<T>::cos(angle), -NumericT<T>::sin(angle));
469 }
470
471 spectrum[k] = value;
472 }
473 }
474}
475
476template <typename T>
477void 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)
478{
479 ocean_assert(spatial && frequencyVertical);
480 ocean_assert(firstColumn + numberColumns <= width);
481 ocean_assert(height != 0u);
482
483 const T pi2_height_1 = NumericT<T>::pi2() / T(height);
484
485 std::complex<T> value;
486
487 for (unsigned int c = firstColumn; c < firstColumn + numberColumns; ++c)
488 {
489 const std::complex<T>* const signal = spatial + c;
490 std::complex<T>* const spectrum = frequencyVertical + c;
491
492 for (unsigned int k = 0u; k < height; ++k)
493 {
494 value = Complex(0, 0);
495
496 for (unsigned int n = 0u; n < height; ++n)
497 {
498 const T angle = pi2_height_1 * T(n * k);
499 value += signal[n * width] * std::complex<T>(NumericT<T>::cos(angle), -NumericT<T>::sin(angle));
500 }
501
502 spectrum[k * width] = value;
503 }
504 }
505}
506
507template <typename T>
508void 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)
509{
510 ocean_assert(frequency && spatialHorizontal);
511 ocean_assert_and_suppress_unused(firstRow + numberRows <= height, height);
512 ocean_assert(width != 0u);
513
514 const T pi2_width_1 = NumericT<T>::pi2() / T(width);
515 const T normalization = T(1) / T(width);
516
517 std::complex<T> value;
518
519 for (unsigned int r = firstRow; r < firstRow + numberRows; ++r)
520 {
521 const std::complex<T>* const spectrum = frequency + r * width;
522 std::complex<T>* const signal = spatialHorizontal + r * width;
523
524 for (unsigned int n = 0; n < width; ++n)
525 {
526 value = Complex(0, 0);
527
528 for (unsigned int k = 0; k < width; ++k)
529 {
530 const T angle = pi2_width_1 * T(k * n);
531 value += spectrum[k] * std::complex<T>(NumericT<T>::cos(angle), NumericT<T>::sin(angle));
532 }
533
534 signal[n] = value * normalization;
535 }
536 }
537}
538
539template <typename T>
540void 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)
541{
542 ocean_assert(frequency && spatialVertical);
543 ocean_assert(firstColumn + numberColumns <= width);
544 ocean_assert(height != 0u);
545
546 const T pi2_height_1 = NumericT<T>::pi2() / T(height);
547 const T normalization = T(1) / T(height);
548
549 std::complex<T> value;
550
551 for (unsigned int c = firstColumn; c < firstColumn + numberColumns; ++c)
552 {
553 const std::complex<T>* const spectrum = frequency + c;
554 std::complex<T>* const signal = spatialVertical + c;
555
556 for (unsigned int n = 0u; n < height; ++n)
557 {
558 value = Complex(0, 0);
559
560 for (unsigned int k = 0; k < height; ++k)
561 {
562 const T angle = pi2_height_1 * T(k * n);
563 value += spectrum[k * width] * std::complex<T>(NumericT<T>::cos(angle), NumericT<T>::sin(angle));
564 }
565
566 signal[n * width] = value * normalization;
567 }
568 }
569}
570
571template <typename TScalar, typename TComplex>
572inline void FourierTransformation::scalarToComplex(const TScalar* source, std::complex<TComplex>* target, const size_t number)
573{
574 ocean_assert(source && target);
575
576 for (size_t n = 0; n < number; ++n)
577 {
578 target[n] = Complex(source[n], 0);
579 }
580}
581
582template <typename TComplex, typename TScalar>
583inline void FourierTransformation::realToScalar(const std::complex<TComplex>* source, TScalar* target, const size_t number)
584{
585 ocean_assert(source && target);
586
587 for (size_t n = 0; n < number; ++n)
588 {
589 target[n] = source[n].real();
590 }
591}
592
593template <typename TComplex, typename TScalar>
594inline void FourierTransformation::imaginaryToScalar(const std::complex<TComplex>* source, TScalar* target, const size_t number)
595{
596 ocean_assert(source && target);
597
598 for (size_t n = 0; n < number; ++n)
599 {
600 target[n] = source[n].imag();
601 }
602}
603
604template <typename TComplex, typename TScalar>
605inline void FourierTransformation::complexToMagnitude(const std::complex<TComplex>* source, TScalar* target, const size_t number)
606{
607 ocean_assert(source && target);
608
609 for (size_t n = 0; n < number; ++n)
610 {
611 target[n] = std::abs(source[n]);
612 }
613}
614
615template <typename T>
616void FourierTransformation::shiftHalfDimension2(const T* source, unsigned int width, const unsigned int height, T* target)
617{
618 ocean_assert(source && target);
619 ocean_assert(width % 2u == 0u);
620 ocean_assert(height % 2u == 0u);
621
622 const unsigned int width2 = width / 2u;
623 const unsigned int height2 = height / 2u;
624
625 for (unsigned int y = 0u; y < height; ++y)
626 {
627 for (unsigned int x = 0u; x < width; ++x)
628 {
629 target[((y + height2) % height) * width + ((x + width2) % width)] = *source++;
630 }
631 }
632}
633
634template <typename T>
635void FourierTransformation::shiftHalfDimension2(T* data, unsigned int width, const unsigned int height)
636{
637 ocean_assert(data);
638
639 // if the frame dimension is a multiple of two
640 if (width % 2u == 0u && height % 2u == 0u)
641 {
642 const unsigned int width_2 = width / 2u;
643 const unsigned int height_2 = height / 2u;
644
645 for (unsigned int y = 0u; y < height_2; ++y)
646 {
647 for (unsigned int x = 0u; x < width_2; ++x)
648 {
649 // swap top left with bottom right
650 std::swap(data[y * width + x], data[(y + height_2) * width + x + width_2]);
651
652 // swap bottom left with top right
653 std::swap(data[(y + height_2) * width + x], data[y * width + x + width_2]);
654 }
655 }
656 }
657 else
658 {
659 Memory tmpMemory = Memory::create<T>(width * height);
660 T* tmp = tmpMemory.data<T>();
661
662 ocean_assert(tmp != nullptr);
663
664 memcpy(tmp, data, width * height * sizeof(T));
665
666 const unsigned int width_2 = width / 2u;
667 const unsigned int height_2 = height / 2u;
668
669 const unsigned int extraX = width % 2u;
670 const unsigned int extraY = height % 2u;
671
672 for (unsigned int y = 0u; y < height_2 + extraY; ++y)
673 {
674 // top left to bottom right
675 memcpy(data + (y + height_2) * width + width_2, tmp + y * width, (width_2 + extraX) * sizeof(T));
676
677 // top right to bottom left
678 memcpy(data + (y + height_2) * width, tmp + y * width + width_2 + extraX, width_2 * sizeof(T));
679 }
680
681 for (unsigned int y = 0u; y < height_2; ++y)
682 {
683 // bottom right to top left
684 memcpy(data + y * width, tmp + (y + height_2 + extraY) * width + width_2 + extraX, width_2 * sizeof(T));
685
686 // bottom left to top right
687 // the destination column is 'width_2' and not 'width_2 + extraX', the target of a shift by 'width_2' is the second half of the row which starts there
688 memcpy(data + y * width + width_2, tmp + (y + height_2 + extraY) * width, (width_2 + extraX) * sizeof(T));
689 }
690
691 ocean_assert(data[shiftCenter(height) * width + shiftCenter(width)] == tmp[0]);
692 }
693}
694
695inline unsigned int FourierTransformation::shiftCenter(const unsigned int size)
696{
697 return size / 2u;
698}
699
700template <typename T, bool tComplexConjugateA, bool tComplexConjugateB>
701void 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)
702{
703 static_assert(std::is_same<T, float>::value || std::is_same<T, double>::value, "Invalid data type!");
704 static_assert(sizeof(std::complex<T>) == sizeof(T) * 2, "Invalid data type!");
705
706 ocean_assert(complexSourceA != nullptr && complexSourceB != nullptr && complexTarget != nullptr);
707 ocean_assert(width != 0u && height != 0u);
708
709 const unsigned int complexSourceAStrideElements = width * 2u + horizontalPaddingSourceAElements;
710 const unsigned int complexSourceBStrideElements = width * 2u + horizontalPaddingSourceBElements;
711 const unsigned int complexTargetStrideElements = width * 2u + horizontalPaddingTargetElements;
712
713 for (unsigned int y = 0u; y < height; ++y)
714 {
715 const std::complex<T>* const sourceARow = (const std::complex<T>*)(complexSourceA + y * complexSourceAStrideElements);
716 const std::complex<T>* const sourceBRow = (const std::complex<T>*)(complexSourceB + y * complexSourceBStrideElements);
717 std::complex<T>* const targetRow = (std::complex<T>*)(complexTarget + y * complexTargetStrideElements);
718
719 if constexpr (tComplexConjugateA && tComplexConjugateB)
720 {
721 for (unsigned int x = 0u; x < width; ++x)
722 {
723 targetRow[x] = std::conj(sourceARow[x]) * std::conj(sourceBRow[x]);
724 }
725 }
726 else if constexpr (tComplexConjugateA && !tComplexConjugateB)
727 {
728 for (unsigned int x = 0u; x < width; ++x)
729 {
730 targetRow[x] = std::conj(sourceARow[x]) * sourceBRow[x];
731 }
732 }
733 else if constexpr (!tComplexConjugateA && tComplexConjugateB)
734 {
735 for (unsigned int x = 0u; x < width; ++x)
736 {
737 targetRow[x] = sourceARow[x] * std::conj(sourceBRow[x]);
738 }
739 }
740 else
741 {
742 for (unsigned int x = 0u; x < width; ++x)
743 {
744 targetRow[x] = sourceARow[x] * sourceBRow[x];
745 }
746 }
747 }
748}
749
750template <typename TComplex, bool tComplexConjugateA, bool tComplexConjugateB, typename TIntermediate>
751void 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)
752{
753 static_assert(std::is_same<TComplex, float>::value || std::is_same<TComplex, double>::value, "Invalid data type!");
754 static_assert(std::is_same<TIntermediate, float>::value || std::is_same<TIntermediate, double>::value, "Invalid data type!");
755
756 ocean_assert(sourceA && sourceB && target);
757 ocean_assert(width != 0u && height != 0u);
758
759 const size_t sourceAStrideElements = width + horizontalPaddingSourceAElements;
760 const size_t sourceBStrideElements = width + horizontalPaddingSourceBElements;
761 const size_t targetStrideElements = width + horizontalPaddingTargetElements;
762
763 const unsigned int lastRowIndex = height - 1u;
764 const unsigned int lastColumnIndex = width - 1u;
765 const bool isWidthEven = width % 2u == 0u;
766 const bool isHeightEven = height % 2u == 0u;
767
768 // Left-most column
769 target[0] = (TComplex)((TIntermediate)sourceA[0] * (TIntermediate)sourceB[0]);
770
771 for (unsigned int row = 1u; row < lastRowIndex; row += 2u)
772 {
773 const TIntermediate realA = (TIntermediate)sourceA[row * sourceAStrideElements];
774 const TIntermediate imaginaryA = (TIntermediate)(tComplexConjugateA ? -sourceA[(row + 1u) * sourceAStrideElements] : sourceA[(row + 1u) * sourceAStrideElements]);
775
776 const TIntermediate realB = (TIntermediate)sourceB[row * sourceBStrideElements];
777 const TIntermediate imaginaryB = (TIntermediate)(tComplexConjugateB ? -sourceB[(row + 1u) * sourceBStrideElements] : sourceB[(row + 1u) * sourceBStrideElements]);
778
779 target[row * targetStrideElements] = (TComplex)((realA * realB) - (imaginaryA * imaginaryB));
780 target[(row + 1u) * targetStrideElements] = (TComplex)((imaginaryA * realB) + (realA * imaginaryB));
781 }
782
783 // Bottom-left element, if height is even
784 if (isHeightEven)
785 {
786 target[lastRowIndex * targetStrideElements] = (TComplex)((TIntermediate)sourceA[lastRowIndex * sourceAStrideElements] * (TIntermediate)sourceB[lastRowIndex * sourceBStrideElements]);
787 }
788
789 // Right-most column, if width is even
790 if (isWidthEven)
791 {
792 target[lastColumnIndex] = (TComplex)((TIntermediate)sourceA[lastColumnIndex] * (TIntermediate)sourceB[lastColumnIndex]);
793
794 for (unsigned int row = 1u; row < lastRowIndex; row += 2u)
795 {
796 const TIntermediate realA = (TIntermediate)sourceA[row * sourceAStrideElements + lastColumnIndex];
797 const TIntermediate imaginaryA = (TIntermediate)(tComplexConjugateA ? -sourceA[(row + 1u) * sourceAStrideElements + lastColumnIndex] : sourceA[(row + 1u) * sourceAStrideElements + lastColumnIndex]);
798
799 const TIntermediate realB = (TIntermediate)sourceB[row * sourceBStrideElements + lastColumnIndex];
800 const TIntermediate imaginaryB = (TIntermediate)(tComplexConjugateB ? -sourceB[(row + 1u) * sourceBStrideElements + lastColumnIndex] : sourceB[(row + 1u) * sourceBStrideElements + lastColumnIndex]);
801
802 target[row * targetStrideElements + lastColumnIndex] = (TComplex)((realA * realB) - (imaginaryA * imaginaryB));
803 target[(row + 1u) * targetStrideElements + lastColumnIndex] = (TComplex)((imaginaryA * realB) + (realA * imaginaryB));
804 }
805
806 // Bottom-right element, if height is even
807 if (isHeightEven)
808 {
809 target[lastRowIndex * targetStrideElements + lastColumnIndex] = (TComplex)((TIntermediate)sourceA[lastRowIndex * sourceAStrideElements + lastColumnIndex] * (TIntermediate)sourceB[lastRowIndex * sourceBStrideElements + lastColumnIndex]);
810 }
811 }
812
813 // Middle columns
814 const unsigned int columnEnd = width - (isWidthEven ? 1u : 0u);
815
816 for (unsigned int row = 0u; row < height; ++row)
817 {
818 for (unsigned int column = 1u; column < columnEnd; column += 2u)
819 {
820 const TIntermediate realA = (TIntermediate)sourceA[column];
821 const TIntermediate imaginaryA = (TIntermediate)(tComplexConjugateA ? -sourceA[column + 1u] : sourceA[column + 1u]);
822
823 const TIntermediate realB = (TIntermediate)sourceB[column];
824 const TIntermediate imaginaryB = (TIntermediate)(tComplexConjugateB ? -sourceB[column + 1u] : sourceB[column + 1u]);
825
826 target[column] = (TComplex)((realA * realB) - (imaginaryA * imaginaryB));
827 target[column + 1u] = (TComplex)((imaginaryA * realB) + (realA * imaginaryB));
828 }
829
830 sourceA += sourceAStrideElements;
831 sourceB += sourceBStrideElements;
832 target += targetStrideElements;
833 }
834}
835
836template <typename T>
837void 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)
838{
839 static_assert(std::is_same<T, float>::value || std::is_same<T, double>::value, "Invalid data type!");
840 static_assert(sizeof(std::complex<T>) == sizeof(T) * 2, "Invalid data type!");
841
842 ocean_assert(complexSourceA != nullptr && complexSourceB != nullptr && complexTarget != nullptr);
843 ocean_assert(width != 0u && height != 0u);
844
845 const unsigned int complexSourceAStrideElements = width * 2u + horizontalPaddingSourceAElements;
846 const unsigned int complexSourceBStrideElements = width * 2u + horizontalPaddingSourceBElements;
847 const unsigned int complexTargetStrideElements = width * 2u + horizontalPaddingTargetElements;
848
849 // (a + bi) / (c + di)
850 // = [(ac + bd) + i(bc - ad)] / (c^2 + d^2)
851
852 for (unsigned int y = 0u; y < height; ++y)
853 {
854 const std::complex<T>* const sourceARow = (const std::complex<T>*)(complexSourceA + y * complexSourceAStrideElements);
855 const std::complex<T>* const sourceBRow = (const std::complex<T>*)(complexSourceB + y * complexSourceBStrideElements);
856 std::complex<T>* const targetRow = (std::complex<T>*)(complexTarget + y * complexTargetStrideElements);
857
858 for (unsigned int x = 0u; x < width; ++x)
859 {
860 const T denominator = sourceBRow[x].real() * sourceBRow[x].real() + sourceBRow[x].imag() * sourceBRow[x].imag();
861 ocean_assert(NumericT<T>::isNotEqualEps(denominator));
862
863 const T invDenominator = T(1.0) / denominator;
864
865 targetRow[x] = std::complex<T>((sourceARow[x].real() * sourceBRow[x].real() + sourceARow[x].imag() * sourceBRow[x].imag()) * invDenominator,
866 (sourceARow[x].imag() * sourceBRow[x].real() - sourceARow[x].real() * sourceBRow[x].imag()) * invDenominator);
867 }
868 }
869}
870
871} // namespace Ocean
872
873#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:2877
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:477
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:508
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:428
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:446
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:410
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:540
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:572
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:594
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:616
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:605
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:701
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:695
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:583
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:751
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:837
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:1969
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