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);
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);
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);
406 template <
typename T>
409 ocean_assert(spatial && frequency);
410 std::vector< std::complex<T> > frequencyHorizontal(width * height);
419 spatialToFrequencyHorizontalSubset2<T>(spatial, width, height, frequencyHorizontal.data(), 0u, height);
420 spatialToFrequencyVerticalSubset2<T>(frequencyHorizontal.data(), width, height, frequency, 0u, width);
424 template <
typename T>
427 ocean_assert(frequency && spatial);
428 std::vector< std::complex<T> > spatialHorizontal(width * height);
437 frequencyToSpatialHorizontalSubset2<T>(frequency, width, height, spatialHorizontal.data(), 0u, height);
438 frequencyToSpatialVerticalSubset2<T>(spatialHorizontal.data(), width, height, spatial, 0u, width);
442 template <
typename T>
445 ocean_assert(spatial && frequencyHorizontal);
446 ocean_assert_and_suppress_unused(firstRow + numberRows <= height, height);
447 ocean_assert(width != 0u);
451 std::complex<T> value;
453 for (
unsigned int r = firstRow; r < firstRow + numberRows; ++r)
455 const std::complex<T>*
const signal = spatial + r * width;
456 std::complex<T>*
const spectrum = frequencyHorizontal + r * width;
458 for (
unsigned int k = 0u; k < width; ++k)
462 for (
unsigned int n = 0u; n < width; ++n)
464 const T angle = pi2_width_1 * T(n * k);
473 template <
typename T>
476 ocean_assert(spatial && frequencyVertical);
477 ocean_assert(firstColumn + numberColumns <= width);
478 ocean_assert(height != 0u);
482 std::complex<T> value;
484 for (
unsigned int c = firstColumn; c < firstColumn + numberColumns; ++c)
486 const std::complex<T>*
const signal = spatial + c;
487 std::complex<T>*
const spectrum = frequencyVertical + c;
489 for (
unsigned int k = 0u; k < height; ++k)
493 for (
unsigned int n = 0u; n < height; ++n)
495 const T angle = pi2_height_1 * T(n * k);
499 spectrum[k * width] = value;
504 template <
typename T>
507 ocean_assert(frequency && spatialHorizontal);
508 ocean_assert_and_suppress_unused(firstRow + numberRows <= height, height);
509 ocean_assert(width != 0u);
512 const T normalization = T(1) / T(width);
514 std::complex<T> value;
516 for (
unsigned int r = firstRow; r < firstRow + numberRows; ++r)
518 const std::complex<T>*
const spectrum = frequency + r * width;
519 std::complex<T>*
const signal = spatialHorizontal + r * width;
521 for (
unsigned int n = 0; n < width; ++n)
525 for (
unsigned int k = 0; k < width; ++k)
527 const T angle = pi2_width_1 * T(k * n);
531 signal[n] = value * normalization;
536 template <
typename T>
539 ocean_assert(frequency && spatialVertical);
540 ocean_assert(firstColumn + numberColumns <= width);
541 ocean_assert(height != 0u);
544 const T normalization = T(1) / T(height);
546 std::complex<T> value;
548 for (
unsigned int c = firstColumn; c < firstColumn + numberColumns; ++c)
550 const std::complex<T>*
const spectrum = frequency + c;
551 std::complex<T>*
const signal = spatialVertical + c;
553 for (
unsigned int n = 0u; n < height; ++n)
557 for (
unsigned int k = 0; k < height; ++k)
559 const T angle = pi2_height_1 * T(k * n);
563 signal[n * width] = value * normalization;
568 template <
typename TScalar,
typename TComplex>
571 ocean_assert(source && target);
573 for (
size_t n = 0; n < number; ++n)
574 target[n] =
Complex(source[n], 0);
577 template <
typename TComplex,
typename TScalar>
580 ocean_assert(source && target);
582 for (
size_t n = 0; n < number; ++n)
583 target[n] = source[n].real();
586 template <
typename TComplex,
typename TScalar>
589 ocean_assert(source && target);
591 for (
size_t n = 0; n < number; ++n)
592 target[n] = source[n].imag();
595 template <
typename TComplex,
typename TScalar>
598 ocean_assert(source && target);
600 for (
size_t n = 0; n < number; ++n)
601 target[n] = std::abs(source[n]);
604 template <
typename T>
607 ocean_assert(source && target);
608 ocean_assert(width % 2u == 0u);
609 ocean_assert(height % 2u == 0u);
611 const unsigned int width2 = width / 2u;
612 const unsigned int height2 = height / 2u;
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++;
619 template <
typename T>
625 if (width % 2u == 0u && height % 2u == 0u)
627 const unsigned int width_2 = width / 2u;
628 const unsigned int height_2 = height / 2u;
630 for (
unsigned int y = 0u; y < height_2; ++y)
631 for (
unsigned int x = 0u; x < width_2; ++x)
634 std::swap(data[y * width + x], data[(y + height_2) * width + x + width_2]);
637 std::swap(data[(y + height_2) * width + x], data[y * width + x + width_2]);
642 Memory tmpMemory = Memory::create<T>(width * height);
643 T* tmp = tmpMemory.
data<T>();
645 ocean_assert(tmp !=
nullptr);
647 memcpy(tmp, data, width * height *
sizeof(T));
649 const unsigned int width_2 = width / 2u;
650 const unsigned int height_2 = height / 2u;
652 const unsigned int extraX = width % 2u;
653 const unsigned int extraY = height % 2u;
655 for (
unsigned int y = 0u; y < height_2 + extraY; ++y)
658 memcpy(data + (y + height_2) * width + width_2, tmp + y * width, (width_2 + extraX) *
sizeof(T));
661 memcpy(data + (y + height_2) * width, tmp + y * width + width_2 + extraX, width_2 *
sizeof(T));
664 for (
unsigned int y = 0u; y < height_2; ++y)
667 memcpy(data + y * width, tmp + (y + height_2 + extraY) * width + width_2 + extraX, width_2 *
sizeof(T));
670 memcpy(data + y * width + width_2 + extraX, tmp + (y + height_2 + extraY) * width, (width_2 + extraX) *
sizeof(T));
682 template <
typename T,
bool tComplexConjugateA,
bool tComplexConjugateB>
683 void FourierTransformation::elementwiseMultiplication2(
const T* complexSourceA,
const T* complexSourceB, T* complexTarget,
const unsigned int width,
const unsigned int height,
const unsigned int horizontalPaddingSourceAElements,
const unsigned int horizontalPaddingSourceBElements,
const unsigned int horizontalPaddingTargetElements)
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!");
688 ocean_assert(complexSourceA !=
nullptr && complexSourceB !=
nullptr && complexTarget !=
nullptr);
689 ocean_assert(width != 0u && height != 0u);
691 const unsigned int complexSourceAStrideElements = width * 2u + horizontalPaddingSourceAElements;
692 const unsigned int complexSourceBStrideElements = width * 2u + horizontalPaddingSourceBElements;
693 const unsigned int complexTargetStrideElements = width * 2u + horizontalPaddingTargetElements;
695 for (
unsigned int y = 0u; y < height; ++y)
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);
701 if constexpr (tComplexConjugateA && tComplexConjugateB)
703 for (
unsigned int x = 0u; x < width; ++x)
705 targetRow[x] = std::conj(sourceARow[x]) * std::conj(sourceBRow[x]);
708 else if constexpr (tComplexConjugateA && !tComplexConjugateB)
710 for (
unsigned int x = 0u; x < width; ++x)
712 targetRow[x] = std::conj(sourceARow[x]) * sourceBRow[x];
715 else if constexpr (!tComplexConjugateA && tComplexConjugateB)
717 for (
unsigned int x = 0u; x < width; ++x)
719 targetRow[x] = sourceARow[x] * std::conj(sourceBRow[x]);
724 for (
unsigned int x = 0u; x < width; ++x)
726 targetRow[x] = sourceARow[x] * sourceBRow[x];
732 template <
typename TComplex,
bool tComplexConjugateA,
bool tComplexConjugateB,
typename TIntermediate>
733 void FourierTransformation::elementwiseMultiplicationCCS(
const TComplex* sourceA,
const TComplex* sourceB, TComplex* target,
const unsigned int width,
const unsigned int height,
const unsigned int horizontalPaddingSourceAElements,
const unsigned int horizontalPaddingSourceBElements,
const unsigned int horizontalPaddingTargetElements)
735 ocean_assert(sourceA && sourceB && target);
736 ocean_assert(width != 0u && height != 0u);
738 const size_t sourceAStrideElements = width + horizontalPaddingSourceAElements;
739 const size_t sourceBStrideElements = width + horizontalPaddingSourceBElements;
740 const size_t targetStrideElements = width + horizontalPaddingTargetElements;
742 const bool isOneDimensionalData = width == 1u || height == 1u;
744 if (isOneDimensionalData)
747 target[0] = (TComplex)((TIntermediate)sourceA[0] * (TIntermediate)sourceB[0]);
750 const unsigned int elementsCount = std::max(width, height);
751 const unsigned int lastElement = elementsCount - 1u;
753 for (
unsigned int j = 1u; j < elementsCount; j += 2)
755 const TIntermediate realA = (TIntermediate)sourceA[j];
756 const TIntermediate imaginaryA = (TIntermediate)(tComplexConjugateA ? -sourceA[j + 1u] : sourceA[j + 1u]);
758 const TIntermediate realB = (TIntermediate)sourceB[j];
759 const TIntermediate imaginaryB = (TIntermediate)(tComplexConjugateB ? -sourceB[j + 1u] : sourceB[j + 1u]);
761 target[j] = (TComplex)((realA * realB) - (imaginaryA * imaginaryB));
762 target[j + 1u] = (TComplex)((imaginaryA * realB) + (realA * imaginaryB));
766 if (elementsCount % 2u == 0u)
768 target[lastElement] = (TComplex)((TIntermediate)sourceA[lastElement] * (TIntermediate)sourceB[lastElement]);
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;
779 target[0] = (TComplex)((TIntermediate)sourceA[0] * (TIntermediate)sourceB[0]);
781 for (
unsigned int row = 1u; row < lastRowIndex; row += 2u)
783 const TIntermediate realA = (TIntermediate)sourceA[row * sourceAStrideElements];
784 const TIntermediate imaginaryA = (TIntermediate)(tComplexConjugateA ? -sourceA[(row + 1u) * sourceAStrideElements] : sourceA[(row + 1u) * sourceAStrideElements]);
786 const TIntermediate realB = (TIntermediate)sourceB[row * sourceBStrideElements];
787 const TIntermediate imaginaryB = (TIntermediate)(tComplexConjugateB ? -sourceB[(row + 1u) * sourceBStrideElements] : sourceB[(row + 1u) * sourceBStrideElements]);
789 target[row * targetStrideElements] = (TComplex)((realA * realB) - (imaginaryA * imaginaryB));
790 target[(row + 1u) * targetStrideElements] = (TComplex)((imaginaryA * realB) + (realA * imaginaryB));
796 target[lastRowIndex * targetStrideElements] = (TComplex)((TIntermediate)sourceA[lastRowIndex * sourceAStrideElements] * (TIntermediate)sourceB[lastRowIndex * sourceBStrideElements]);
802 target[lastColumnIndex] = sourceA[lastColumnIndex] * sourceB[lastColumnIndex];
804 for (
unsigned int row = 1u; row < lastRowIndex; row += 2u)
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]);
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]);
812 target[row * targetStrideElements + lastColumnIndex] = (TComplex)((realA * realB) - (imaginaryA * imaginaryB));
813 target[(row + 1u) * targetStrideElements + lastColumnIndex] = (TComplex)((imaginaryA * realB) + (realA * imaginaryB));
819 target[lastRowIndex * targetStrideElements + lastColumnIndex] = (TComplex)((TIntermediate)sourceA[lastRowIndex * sourceAStrideElements + lastColumnIndex] * (TIntermediate)sourceB[lastRowIndex * sourceBStrideElements + lastColumnIndex]);
824 const unsigned int columnEnd = width - (isWidthEven ? 1u : 0u);
826 for (
unsigned int row = 0u; row < height; ++row)
828 for (
unsigned int column = 1u; column < columnEnd; column += 2u)
830 const TIntermediate realA = (TIntermediate)sourceA[column];
831 const TIntermediate imaginaryA = (TIntermediate)(tComplexConjugateA ? -sourceA[column + 1u] : sourceA[column + 1u]);
833 const TIntermediate realB = (TIntermediate)sourceB[column];
834 const TIntermediate imaginaryB = (TIntermediate)(tComplexConjugateB ? -sourceB[column + 1u] : sourceB[column + 1u]);
836 target[column] = (TComplex)((realA * realB) - (imaginaryA * imaginaryB));
837 target[column + 1u] = (TComplex)((imaginaryA * realB) + (realA * imaginaryB));
840 sourceA += sourceAStrideElements;
841 sourceB += sourceBStrideElements;
842 target += targetStrideElements;
847 template <
typename T>
848 void FourierTransformation::elementwiseDivision2(
const T* complexSourceA,
const T* complexSourceB, T* complexTarget,
const unsigned int width,
const unsigned int height,
const unsigned int horizontalPaddingSourceAElements,
const unsigned int horizontalPaddingSourceBElements,
const unsigned int horizontalPaddingTargetElements)
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!");
853 ocean_assert(complexSourceA !=
nullptr && complexSourceB !=
nullptr && complexTarget !=
nullptr);
854 ocean_assert(width != 0u && height != 0u);
856 const unsigned int complexSourceAStrideElements = width * 2u + horizontalPaddingSourceAElements;
857 const unsigned int complexSourceBStrideElements = width * 2u + horizontalPaddingSourceBElements;
858 const unsigned int complexTargetStrideElements = width * 2u + horizontalPaddingTargetElements;
863 for (
unsigned int y = 0u; y < height; ++y)
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);
869 for (
unsigned int x = 0u; x < width; ++x)
871 const T denominator = sourceBRow[x].real() * sourceBRow[x].real() + sourceBRow[x].imag() * sourceBRow[x].imag();
874 const T invDenominator = T(1.0) / denominator;
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);
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 implements Ocean's image class.
Definition: Frame.h:1792
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