/* * Copyright (c) 2018, Alliance for Open Media. All rights reserved. * * This source code is subject to the terms of the BSD 2 Clause License and * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License * was not distributed with this source code in the LICENSE file, you can * obtain it at www.aomedia.org/license/software. If the Alliance for Open * Media Patent License 1.0 was not distributed with this source code in the * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
*/
// Simple 1D FFT implementation template <typename InputType> void fft(const InputType *data, std::complex<float> *result, int n) { if (n == 1) {
result[0] = data[0]; return;
}
std::vector<InputType> temp(n); for (int k = 0; k < n / 2; ++k) {
temp[k] = data[2 * k];
temp[n / 2 + k] = data[2 * k + 1];
}
fft(&temp[0], result, n / 2);
fft(&temp[n / 2], result + n / 2, n / 2); for (int k = 0; k < n / 2; ++k) {
std::complex<float> w = std::complex<float>((float)cos(2. * PI * k / n),
(float)-sin(2. * PI * k / n));
std::complex<float> a = result[k];
std::complex<float> b = result[n / 2 + k];
result[k] = a + w * b;
result[n / 2 + k] = a - w * b;
}
}
void transpose(std::vector<std::complex<float> > *data, int n) { for (int y = 0; y < n; ++y) { for (int x = y + 1; x < n; ++x) {
std::swap((*data)[y * n + x], (*data)[x * n + y]);
}
}
}
// Simple 2D FFT implementation template <class InputType>
std::vector<std::complex<float> > fft2d(const InputType *input, int n) {
std::vector<std::complex<float> > rowfft(n * n);
std::vector<std::complex<float> > result(n * n); for (int y = 0; y < n; ++y) {
fft(input + y * n, &rowfft[y * n], n);
}
transpose(&rowfft, n); for (int y = 0; y < n; ++y) {
fft(&rowfft[y * n], &result[y * n], n);
}
transpose(&result, n); return result;
}
class IFFT2DTest : public ::testing::TestWithParam<IFFTTestArg> { protected: void SetUp() override { int n = GetParam().n;
input_ = (float *)aom_memalign(32, sizeof(*input_) * n * n * 2);
temp_ = (float *)aom_memalign(32, sizeof(*temp_) * n * n * 2);
output_ = (float *)aom_memalign(32, sizeof(*output_) * n * n);
ASSERT_NE(input_, nullptr);
ASSERT_NE(temp_, nullptr);
ASSERT_NE(output_, nullptr);
memset(input_, 0, sizeof(*input_) * n * n * 2);
memset(temp_, 0, sizeof(*temp_) * n * n * 2);
memset(output_, 0, sizeof(*output_) * n * n);
} void TearDown() override {
aom_free(input_);
aom_free(temp_);
aom_free(output_);
} float *input_; float *temp_; float *output_;
};
TEST_P(IFFT2DTest, Correctness) { int n = GetParam().n;
ASSERT_GE(n, 2);
std::vector<float> expected(n * n);
std::vector<float> actual(n * n); // Do forward transform then invert to make sure we get back expected for (int y = 0; y < n; ++y) { for (int x = 0; x < n; ++x) {
expected[y * n + x] = 1;
std::vector<std::complex<float> > input_c = fft2d(&expected[0], n); for (int i = 0; i < n * n; ++i) {
input_[2 * i + 0] = input_c[i].real();
input_[2 * i + 1] = input_c[i].imag();
}
GetParam().ifft(&input_[0], &temp_[0], &output_[0]);
for (int yy = 0; yy < n; ++yy) { for (int xx = 0; xx < n; ++xx) {
EXPECT_NEAR(expected[yy * n + xx], output_[yy * n + xx] / (n * n),
1e-5);
}
}
expected[y * n + x] = 0;
}
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.