8#ifndef META_OCEAN_MATH_FOURIER_TRANSFORMATION_H
9#define META_OCEAN_MATH_FOURIER_TRANSFORMATION_H
49 static void spatialToFrequency2(
const std::complex<T>* spatial,
const unsigned int width,
const unsigned int height, std::complex<T>* frequency,
Worker* worker =
nullptr);
63 static void frequencyToSpatial2(
const std::complex<T>* frequency,
const unsigned int width,
const unsigned int height, std::complex<T>* spatial,
Worker* worker =
nullptr);
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);
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);
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);
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);
127 static bool dft0(
const Frame& source,
Frame& target,
int flags,
int nonzero_rows);
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);
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);
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);
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);
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);
215 template <
typename TScalar,
typename TComplex>
216 static inline void scalarToComplex(
const TScalar* source, std::complex<TComplex>* target,
const size_t number);
226 template <
typename TComplex,
typename TScalar>
227 static inline void realToScalar(
const std::complex<TComplex>* source, TScalar* target,
const size_t number);
237 template <
typename TComplex,
typename TScalar>
238 static inline void imaginaryToScalar(
const std::complex<TComplex>* source, TScalar* target,
const size_t number);
249 template <
typename TComplex,
typename TScalar>
250 static inline void complexToMagnitude(
const std::complex<TComplex>* source, TScalar* target,
const size_t number);
260 template <
typename T>
261 static void shiftHalfDimension2(
const T* source,
unsigned int width,
const unsigned int height, T* target);
270 template <
typename T>
271 static void shiftHalfDimension2(T* data,
unsigned int width,
const unsigned int height);
278 static inline unsigned int shiftCenter(
const unsigned int size);
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);
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);
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);
412 ocean_assert(spatial && frequency);
413 std::vector< std::complex<T> > frequencyHorizontal(width * height);
422 spatialToFrequencyHorizontalSubset2<T>(spatial, width, height, frequencyHorizontal.data(), 0u, height);
423 spatialToFrequencyVerticalSubset2<T>(frequencyHorizontal.data(), width, height, frequency, 0u, width);
430 ocean_assert(frequency && spatial);
431 std::vector< std::complex<T> > spatialHorizontal(width * height);
440 frequencyToSpatialHorizontalSubset2<T>(frequency, width, height, spatialHorizontal.data(), 0u, height);
441 frequencyToSpatialVerticalSubset2<T>(spatialHorizontal.data(), width, height, spatial, 0u, width);
448 ocean_assert(spatial && frequencyHorizontal);
449 ocean_assert_and_suppress_unused(firstRow + numberRows <= height, height);
450 ocean_assert(width != 0u);
454 std::complex<T> value;
456 for (
unsigned int r = firstRow; r < firstRow + numberRows; ++r)
458 const std::complex<T>*
const signal = spatial + r * width;
459 std::complex<T>*
const spectrum = frequencyHorizontal + r * width;
461 for (
unsigned int k = 0u; k < width; ++k)
465 for (
unsigned int n = 0u; n < width; ++n)
467 const T angle = pi2_width_1 * T(n * k);
479 ocean_assert(spatial && frequencyVertical);
480 ocean_assert(firstColumn + numberColumns <= width);
481 ocean_assert(height != 0u);
485 std::complex<T> value;
487 for (
unsigned int c = firstColumn; c < firstColumn + numberColumns; ++c)
489 const std::complex<T>*
const signal = spatial + c;
490 std::complex<T>*
const spectrum = frequencyVertical + c;
492 for (
unsigned int k = 0u; k < height; ++k)
496 for (
unsigned int n = 0u; n < height; ++n)
498 const T angle = pi2_height_1 * T(n * k);
502 spectrum[k * width] = value;
510 ocean_assert(frequency && spatialHorizontal);
511 ocean_assert_and_suppress_unused(firstRow + numberRows <= height, height);
512 ocean_assert(width != 0u);
515 const T normalization = T(1) / T(width);
517 std::complex<T> value;
519 for (
unsigned int r = firstRow; r < firstRow + numberRows; ++r)
521 const std::complex<T>*
const spectrum = frequency + r * width;
522 std::complex<T>*
const signal = spatialHorizontal + r * width;
524 for (
unsigned int n = 0; n < width; ++n)
528 for (
unsigned int k = 0; k < width; ++k)
530 const T angle = pi2_width_1 * T(k * n);
534 signal[n] = value * normalization;
542 ocean_assert(frequency && spatialVertical);
543 ocean_assert(firstColumn + numberColumns <= width);
544 ocean_assert(height != 0u);
547 const T normalization = T(1) / T(height);
549 std::complex<T> value;
551 for (
unsigned int c = firstColumn; c < firstColumn + numberColumns; ++c)
553 const std::complex<T>*
const spectrum = frequency + c;
554 std::complex<T>*
const signal = spatialVertical + c;
556 for (
unsigned int n = 0u; n < height; ++n)
560 for (
unsigned int k = 0; k < height; ++k)
562 const T angle = pi2_height_1 * T(k * n);
566 signal[n * width] = value * normalization;
571template <
typename TScalar,
typename TComplex>
574 ocean_assert(source && target);
576 for (
size_t n = 0; n < number; ++n)
578 target[n] =
Complex(source[n], 0);
582template <
typename TComplex,
typename TScalar>
585 ocean_assert(source && target);
587 for (
size_t n = 0; n < number; ++n)
589 target[n] = source[n].real();
593template <
typename TComplex,
typename TScalar>
596 ocean_assert(source && target);
598 for (
size_t n = 0; n < number; ++n)
600 target[n] = source[n].imag();
604template <
typename TComplex,
typename TScalar>
607 ocean_assert(source && target);
609 for (
size_t n = 0; n < number; ++n)
611 target[n] = std::abs(source[n]);
618 ocean_assert(source && target);
619 ocean_assert(width % 2u == 0u);
620 ocean_assert(height % 2u == 0u);
622 const unsigned int width2 = width / 2u;
623 const unsigned int height2 = height / 2u;
625 for (
unsigned int y = 0u; y < height; ++y)
627 for (
unsigned int x = 0u; x < width; ++x)
629 target[((y + height2) % height) * width + ((x + width2) % width)] = *source++;
640 if (width % 2u == 0u && height % 2u == 0u)
642 const unsigned int width_2 = width / 2u;
643 const unsigned int height_2 = height / 2u;
645 for (
unsigned int y = 0u; y < height_2; ++y)
647 for (
unsigned int x = 0u; x < width_2; ++x)
650 std::swap(data[y * width + x], data[(y + height_2) * width + x + width_2]);
653 std::swap(data[(y + height_2) * width + x], data[y * width + x + width_2]);
659 Memory tmpMemory = Memory::create<T>(width * height);
660 T* tmp = tmpMemory.
data<T>();
662 ocean_assert(tmp !=
nullptr);
664 memcpy(tmp, data, width * height *
sizeof(T));
666 const unsigned int width_2 = width / 2u;
667 const unsigned int height_2 = height / 2u;
669 const unsigned int extraX = width % 2u;
670 const unsigned int extraY = height % 2u;
672 for (
unsigned int y = 0u; y < height_2 + extraY; ++y)
675 memcpy(data + (y + height_2) * width + width_2, tmp + y * width, (width_2 + extraX) *
sizeof(T));
678 memcpy(data + (y + height_2) * width, tmp + y * width + width_2 + extraX, width_2 *
sizeof(T));
681 for (
unsigned int y = 0u; y < height_2; ++y)
684 memcpy(data + y * width, tmp + (y + height_2 + extraY) * width + width_2 + extraX, width_2 *
sizeof(T));
688 memcpy(data + y * width + width_2, tmp + (y + height_2 + extraY) * width, (width_2 + extraX) *
sizeof(T));
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)
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!");
706 ocean_assert(complexSourceA !=
nullptr && complexSourceB !=
nullptr && complexTarget !=
nullptr);
707 ocean_assert(width != 0u && height != 0u);
709 const unsigned int complexSourceAStrideElements = width * 2u + horizontalPaddingSourceAElements;
710 const unsigned int complexSourceBStrideElements = width * 2u + horizontalPaddingSourceBElements;
711 const unsigned int complexTargetStrideElements = width * 2u + horizontalPaddingTargetElements;
713 for (
unsigned int y = 0u; y < height; ++y)
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);
719 if constexpr (tComplexConjugateA && tComplexConjugateB)
721 for (
unsigned int x = 0u; x < width; ++x)
723 targetRow[x] = std::conj(sourceARow[x]) * std::conj(sourceBRow[x]);
726 else if constexpr (tComplexConjugateA && !tComplexConjugateB)
728 for (
unsigned int x = 0u; x < width; ++x)
730 targetRow[x] = std::conj(sourceARow[x]) * sourceBRow[x];
733 else if constexpr (!tComplexConjugateA && tComplexConjugateB)
735 for (
unsigned int x = 0u; x < width; ++x)
737 targetRow[x] = sourceARow[x] * std::conj(sourceBRow[x]);
742 for (
unsigned int x = 0u; x < width; ++x)
744 targetRow[x] = sourceARow[x] * sourceBRow[x];
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)
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!");
756 ocean_assert(sourceA && sourceB && target);
757 ocean_assert(width != 0u && height != 0u);
759 const size_t sourceAStrideElements = width + horizontalPaddingSourceAElements;
760 const size_t sourceBStrideElements = width + horizontalPaddingSourceBElements;
761 const size_t targetStrideElements = width + horizontalPaddingTargetElements;
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;
769 target[0] = (TComplex)((TIntermediate)sourceA[0] * (TIntermediate)sourceB[0]);
771 for (
unsigned int row = 1u; row < lastRowIndex; row += 2u)
773 const TIntermediate realA = (TIntermediate)sourceA[row * sourceAStrideElements];
774 const TIntermediate imaginaryA = (TIntermediate)(tComplexConjugateA ? -sourceA[(row + 1u) * sourceAStrideElements] : sourceA[(row + 1u) * sourceAStrideElements]);
776 const TIntermediate realB = (TIntermediate)sourceB[row * sourceBStrideElements];
777 const TIntermediate imaginaryB = (TIntermediate)(tComplexConjugateB ? -sourceB[(row + 1u) * sourceBStrideElements] : sourceB[(row + 1u) * sourceBStrideElements]);
779 target[row * targetStrideElements] = (TComplex)((realA * realB) - (imaginaryA * imaginaryB));
780 target[(row + 1u) * targetStrideElements] = (TComplex)((imaginaryA * realB) + (realA * imaginaryB));
786 target[lastRowIndex * targetStrideElements] = (TComplex)((TIntermediate)sourceA[lastRowIndex * sourceAStrideElements] * (TIntermediate)sourceB[lastRowIndex * sourceBStrideElements]);
792 target[lastColumnIndex] = (TComplex)((TIntermediate)sourceA[lastColumnIndex] * (TIntermediate)sourceB[lastColumnIndex]);
794 for (
unsigned int row = 1u; row < lastRowIndex; row += 2u)
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]);
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]);
802 target[row * targetStrideElements + lastColumnIndex] = (TComplex)((realA * realB) - (imaginaryA * imaginaryB));
803 target[(row + 1u) * targetStrideElements + lastColumnIndex] = (TComplex)((imaginaryA * realB) + (realA * imaginaryB));
809 target[lastRowIndex * targetStrideElements + lastColumnIndex] = (TComplex)((TIntermediate)sourceA[lastRowIndex * sourceAStrideElements + lastColumnIndex] * (TIntermediate)sourceB[lastRowIndex * sourceBStrideElements + lastColumnIndex]);
814 const unsigned int columnEnd = width - (isWidthEven ? 1u : 0u);
816 for (
unsigned int row = 0u; row < height; ++row)
818 for (
unsigned int column = 1u; column < columnEnd; column += 2u)
820 const TIntermediate realA = (TIntermediate)sourceA[column];
821 const TIntermediate imaginaryA = (TIntermediate)(tComplexConjugateA ? -sourceA[column + 1u] : sourceA[column + 1u]);
823 const TIntermediate realB = (TIntermediate)sourceB[column];
824 const TIntermediate imaginaryB = (TIntermediate)(tComplexConjugateB ? -sourceB[column + 1u] : sourceB[column + 1u]);
826 target[column] = (TComplex)((realA * realB) - (imaginaryA * imaginaryB));
827 target[column + 1u] = (TComplex)((imaginaryA * realB) + (realA * imaginaryB));
830 sourceA += sourceAStrideElements;
831 sourceB += sourceBStrideElements;
832 target += targetStrideElements;
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)
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!");
842 ocean_assert(complexSourceA !=
nullptr && complexSourceB !=
nullptr && complexTarget !=
nullptr);
843 ocean_assert(width != 0u && height != 0u);
845 const unsigned int complexSourceAStrideElements = width * 2u + horizontalPaddingSourceAElements;
846 const unsigned int complexSourceBStrideElements = width * 2u + horizontalPaddingSourceBElements;
847 const unsigned int complexTargetStrideElements = width * 2u + horizontalPaddingTargetElements;
852 for (
unsigned int y = 0u; y < height; ++y)
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);
858 for (
unsigned int x = 0u; x < width; ++x)
860 const T denominator = sourceBRow[x].real() * sourceBRow[x].real() + sourceBRow[x].imag() * sourceBRow[x].imag();
863 const T invDenominator = T(1.0) / denominator;
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);
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 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