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 * 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
406template <typename T>
407inline 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
424template <typename T>
425inline 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
442template <typename T>
443void 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
473template <typename T>
474void 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
504template <typename T>
505void 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
536template <typename T>
537void 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
568template <typename TScalar, typename TComplex>
569inline 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
577template <typename TComplex, typename TScalar>
578inline 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
586template <typename TComplex, typename TScalar>
587inline 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
595template <typename TComplex, typename TScalar>
596inline 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
604template <typename T>
605void 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
619template <typename T>
620void 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
677inline unsigned int FourierTransformation::shiftCenter(const unsigned int size)
678{
679 return size / 2u;
680}
681
682template <typename T, bool tComplexConjugateA, bool tComplexConjugateB>
683void 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
732template <typename TComplex, bool tComplexConjugateA, bool tComplexConjugateB, typename TIntermediate>
733void 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
847template <typename T>
848void 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:1808
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