diff --git a/dlib/matrix.h b/dlib/matrix.h index 600485367..bb5926e71 100644 --- a/dlib/matrix.h +++ b/dlib/matrix.h @@ -12,6 +12,7 @@ #include "matrix/symmetric_matrix_cache.h" #include "matrix/matrix_conv.h" #include "matrix/matrix_read_from_istream.h" +#include "matrix/matrix_fft.h" #ifdef DLIB_USE_BLAS #include "matrix/matrix_blas_bindings.h" diff --git a/dlib/matrix/matrix_fft.h b/dlib/matrix/matrix_fft.h new file mode 100644 index 000000000..eae4e4092 --- /dev/null +++ b/dlib/matrix/matrix_fft.h @@ -0,0 +1,258 @@ +// Copyright (C) 2013 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#ifndef DLIB_FFt_H__ +#define DLIB_FFt_H__ + +#include "matrix_fft_abstract.h" +#include "matrix_utilities.h" +#include "../hash.h" +#include "../algs.h" + +#ifdef DLIB_USE_FFTW +#include +#endif // DLIB_USE_FFTW + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + namespace impl + { + inline unsigned long reverse_bits ( + unsigned long val, + unsigned long num + ) + { + unsigned long temp = 0; + for (unsigned long i = 0; i < num; ++i) + { + temp <<= 1; + temp |= val&0x1; + val >>= 1; + } + return temp; + } + + template + void permute ( + const matrix,NR,NC,MM,L>& data, + matrix,NR,NC,MM,L>& outdata + ) + { + outdata.set_size(data.size()); + if (data.size() == 0) + return; + + const unsigned long num = static_cast(std::log(data.size())/std::log(2.0) + 0.5); + for (unsigned long i = 0; i < (unsigned long)data.size(); ++i) + { + outdata(impl::reverse_bits(i,num)) = data(i); + } + } + + } + +// ---------------------------------------------------------------------------------------- + + inline bool is_power_of_two ( + const unsigned long& value + ) + { + if (value == 0) + return true; + else + return count_bits(value) == 1; + } + +// ---------------------------------------------------------------------------------------- + + template + matrix,NR,NC,MM,L> fft ( + const matrix,NR,NC,MM,L>& data + ) + { + if (data.size() == 0) + return data; + + // make sure requires clause is not broken + DLIB_CASSERT(is_vector(data) && is_power_of_two(data.size()), + "\t void ifft(data)" + << "\n\t data must be a vector with a size that is a power of two." + << "\n\t is_vector(data): " << is_vector(data) + << "\n\t data.size(): " << data.size() + ); + + matrix,NR,NC,MM,L> outdata(data); + + const long half = outdata.size()/2; + + typedef std::complex ct; + matrix twiddle_factors(half); + + // compute the complex root of unity w + const T temp = -2.0*pi/outdata.size(); + ct w = ct(std::cos(temp),std::sin(temp)); + + ct w_pow = 1; + + // compute the twiddle factors + for (long j = 0; j < twiddle_factors.size(); ++j) + { + twiddle_factors(j) = w_pow; + w_pow *= w; + } + + + // now compute the decimation in frequency. This first + // outer loop loops log2(outdata.size()) number of times + long skip = 1; + for (long step = half; step != 0; step >>= 1) + { + // do blocks of butterflies in this loop + for (long j = 0; j < outdata.size(); j += step*2) + { + // do step butterflies + for (long k = 0; k < step; ++k) + { + const long a_idx = j+k; + const long b_idx = j+k+step; + const ct a = outdata(a_idx) + outdata(b_idx); + const ct b = (outdata(a_idx) - outdata(b_idx))*twiddle_factors(k*skip); + outdata(a_idx) = a; + outdata(b_idx) = b; + } + } + skip *= 2; + } + + matrix,NR,NC,MM,L> outperm; + impl::permute(outdata, outperm); + return outperm; + } + +// ---------------------------------------------------------------------------------------- + + template + matrix,NR,NC,MM,L> ifft ( + const matrix,NR,NC,MM,L>& data + ) + { + if (data.size() == 0) + return data; + + // make sure requires clause is not broken + DLIB_CASSERT(is_vector(data) && is_power_of_two(data.size()), + "\t void ifft(data)" + << "\n\t data must be a vector with a size that is a power of two." + << "\n\t is_vector(data): " << is_vector(data) + << "\n\t data.size(): " << data.size() + ); + + + matrix,NR,NC,MM,L> outdata; + impl::permute(data,outdata); + + const long half = outdata.size()/2; + + typedef std::complex ct; + matrix twiddle_factors(half); + + // compute the complex root of unity w + const T temp = 2.0*pi/outdata.size(); + ct w = ct(std::cos(temp),std::sin(temp)); + + ct w_pow = 1; + + // compute the twiddle factors + for (long j = 0; j < twiddle_factors.size(); ++j) + { + twiddle_factors(j) = w_pow; + w_pow *= w; + } + + // now compute the inverse decimation in frequency. This first + // outer loop loops log2(outdata.size()) number of times + long skip = half; + for (long step = 1; step <= half; step <<= 1) + { + // do blocks of butterflies in this loop + for (long j = 0; j < outdata.size(); j += step*2) + { + // do step butterflies + for (long k = 0; k < step; ++k) + { + const long a_idx = j+k; + const long b_idx = j+k+step; + outdata(b_idx) *= twiddle_factors(k*skip); + const ct a = outdata(a_idx) + outdata(b_idx); + const ct b = outdata(a_idx) - outdata(b_idx); + outdata(a_idx) = a; + outdata(b_idx) = b; + } + } + skip /= 2; + } + + outdata /= outdata.size(); + return outdata; + } + +// ---------------------------------------------------------------------------------------- + +#ifdef DLIB_USE_FFTW + + inline matrix,0,1> fft( + const matrix,0,1>& data + ) + { + // make sure requires clause is not broken + DLIB_CASSERT(is_vector(data) && is_power_of_two(data.size()), + "\t void fft(data)" + << "\n\t data must be a vector with a size that is a power of two." + << "\n\t is_vector(data): " << is_vector(data) + << "\n\t data.size(): " << data.size() + ); + + matrix,0,1> m2(data.size()); + fftw_complex *in, *out; + fftw_plan p; + in = (fftw_complex*)&data(0); + out = (fftw_complex*)&m2(0); + p = fftw_plan_dft_1d(data.size(), in, out, FFTW_FORWARD, FFTW_ESTIMATE); + fftw_execute(p); + fftw_destroy_plan(p); + return m2; + } + + inline matrix,0,1> ifft( + const matrix,0,1>& data + ) + { + // make sure requires clause is not broken + DLIB_CASSERT(is_vector(data) && is_power_of_two(data.size()), + "\t void ifft(data)" + << "\n\t data must be a vector with a size that is a power of two." + << "\n\t is_vector(data): " << is_vector(data) + << "\n\t data.size(): " << data.size() + ); + + matrix,0,1> m2(data.size()); + fftw_complex *in, *out; + fftw_plan p; + in = (fftw_complex*)&data(0); + out = (fftw_complex*)&m2(0); + p = fftw_plan_dft_1d(data.size(), in, out, FFTW_BACKWARD, FFTW_ESTIMATE); + fftw_execute(p); + fftw_destroy_plan(p); + return m2/data.size(); + } + +#endif // DLIB_USE_FFTW + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_FFt_H__ + diff --git a/dlib/matrix/matrix_fft_abstract.h b/dlib/matrix/matrix_fft_abstract.h new file mode 100644 index 000000000..f65b0bc1f --- /dev/null +++ b/dlib/matrix/matrix_fft_abstract.h @@ -0,0 +1,85 @@ +// Copyright (C) 2013 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. +#undef DLIB_FFt_ABSTRACT_H__ +#ifdef DLIB_FFt_ABSTRACT_H__ + +#include "matrix_abstract.h" +#include "../algs.h" + +namespace dlib +{ + +// ---------------------------------------------------------------------------------------- + + bool is_power_of_two ( + const unsigned long& value + ); + /*! + ensures + - returns true if value contains a power of two and false otherwise. As a + special case, we also consider 0 to be a power of two. + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + long NR, + long NC, + typename MM, + typename L + > + matrix,NR,NC,MM,L> fft ( + const matrix,NR,NC,MM,L>& data + ); + /*! + requires + - is_vector(data) == true + - is_power_of_two(data.size()) == true + ensures + - Computes the discrete Fourier transform of the given data vector and + returns it. In particular, we return a matrix D such that: + - D.nr() == data.nr() + - D.nc() == data.nc() + - D(0) == the DC term of the Fourier transform. + - starting with D(0), D contains progressively higher frequency components + of the input data. + - ifft(D) == D + - if DLIB_USE_FFTW is #defined then this function will use the very fast fftw + library when given double precision matrices instead of dlib's default fft + implementation. + !*/ + +// ---------------------------------------------------------------------------------------- + + template < + typename T, + long NR, + long NC, + typename MM, + typename L + > + matrix,NR,NC,MM,L> ifft ( + const matrix,NR,NC,MM,L>& data + ); + /*! + requires + - is_vector(data) == true + - is_power_of_two(data.size()) == true + ensures + - Computes the inverse discrete Fourier transform of the given data vector and + returns it. In particular, we return a matrix D such that: + - D.nr() == data.nr() + - D.nc() == data.nc() + - fft(D) == data + - if DLIB_USE_FFTW is #defined then this function will use the very fast fftw + library when given double precision matrices instead of dlib's default fft + implementation. + !*/ + +// ---------------------------------------------------------------------------------------- + +} + +#endif // DLIB_FFt_ABSTRACT_H__ + diff --git a/dlib/test/CMakeLists.txt b/dlib/test/CMakeLists.txt index f609c2a39..ed75d05b0 100644 --- a/dlib/test/CMakeLists.txt +++ b/dlib/test/CMakeLists.txt @@ -44,6 +44,7 @@ set (tests entropy_coder.cpp entropy_encoder_model.cpp example_args.cpp + fft.cpp filtering.cpp find_max_factor_graph_nmplp.cpp find_max_factor_graph_viterbi.cpp diff --git a/dlib/test/fft.cpp b/dlib/test/fft.cpp new file mode 100644 index 000000000..9fea24f2a --- /dev/null +++ b/dlib/test/fft.cpp @@ -0,0 +1,207 @@ +// Copyright (C) 2013 Davis E. King (davis@dlib.net) +// License: Boost Software License See LICENSE.txt for the full license. + + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tester.h" + +namespace +{ + + using namespace test; + using namespace dlib; + using namespace std; + + logger dlog("test.fft"); + +// ---------------------------------------------------------------------------------------- + + matrix > rand_complex(long num) + { + static dlib::rand rnd; + matrix > m(num,1); + + for (long i = 0; i < m.size(); ++i) + { + m(i) = complex(rnd.get_random_gaussian()*10, rnd.get_random_gaussian()*10); + } + return m; + } + + const std::string get_decoded_string(); + void test_against_saved_good_ffts() + { + print_spinner(); + istringstream sin(get_decoded_string()); + matrix,0,1> m1, m2; + matrix,0,1> fm1, fm2; + while (sin.peek() != EOF) + { + deserialize(m1,sin); + deserialize(m2,sin); + + fm1 = matrix_cast >(m1); + fm2 = matrix_cast >(m2); + + DLIB_TEST(max(norm(fft(m1)-m2)) < 1e-16); + DLIB_TEST(max(norm(m1-ifft(m2))) < 1e-16); + + DLIB_TEST(max(norm(fft(fm1)-fm2)) < 1e-7); + DLIB_TEST(max(norm(fm1-ifft(fm2))) < 1e-7); + } + } + +// ---------------------------------------------------------------------------------------- + + void test_random_ffts() + { + print_spinner(); + for (int iter = 0; iter < 10; ++iter) + { + for (int size = 1; size <= 64; size *= 2) + { + const matrix,0,1> m1 = rand_complex(size); + const matrix,0,1> fm1 = matrix_cast >(rand_complex(size)); + + DLIB_TEST(max(norm(ifft(fft(m1))-m1)) < 1e-16); + DLIB_TEST(max(norm(ifft(fft(fm1))-fm1)) < 1e-7); + } + } + } + +// ---------------------------------------------------------------------------------------- + + class test_fft : public tester + { + public: + test_fft ( + ) : + tester ("test_fft", + "Runs tests on the fft routines.") + {} + + void perform_test ( + ) + { + test_against_saved_good_ffts(); + test_random_ffts(); + } + } a; + +// ---------------------------------------------------------------------------------------- + + // This function returns the contents of the file 'fft_test_data.dat' + const std::string get_decoded_string() + { + dlib::base64 base64_coder; + dlib::compress_stream::kernel_1ea compressor; + std::ostringstream sout; + std::istringstream sin; + + // The base64 encoded data from the file 'fft_test_data.dat' we want to decode and return. + sout << "gO1l2wKz8OsyeYMPYcGx6QdBG65vnrB+omgAJ7Bnsuk9vkTw/Y9Y/UZEFXhVf6qnq92QHPLV16Fo"; + sout << "a+IUHNTjoPAfBOTyfb8QRcTj9SaWpxA65+UCJ+5L6x/TEyPKDtB23S0KRpRSdfxBSW9/rnUrkIv7"; + sout << "6i6LWcxKzdsw2WGsRCX1k3t0adQW49m/yb8LV9Loqs7/phzY7HkJ4D2PLtpc6Wyk1qG/h6KQ7nkF"; + sout << "GFkHIoh+xKXhHpqWaSofx8H8m/++H++g0VSPqfQ1ktFz+K8UtiGoyR2GqpP+br47YLXG3WqVU5Km"; + sout << "Di3+IjQoBH2m4jykD926aRvdRrgUH4gZunokl+U6shv20Zm0NL8j4A46/2f++YPGCVBNJJmcJdI7"; + sout << "9RlPL9SFbJ8rnH5bbLvZ2pKZmmbeZN78yzLUhdGwn4DGpf/Zo1fU2YPUjVKkwY6olW4w3tiBl05a"; + sout << "cS1HwBeQjnajqsXNyudbrBkM1Z9XiwM+J5iMsu5ldaJ8iLn30W2Te2RnZhJRHO8MgL7Fn1j0n0Qb"; + sout << "8dB+6aQYv0l/5LQkr5SX6YSRYX5b5rnqhi8IzJKms6dzoyBm97IGTm8pRxtLXcmsk1MvJcHF2gl2"; + sout << "CslQazsl5iIS6fMxEodmlMdwdfIpp/6MqmeIydSHwdyJJZnNPl2p5X+Il5egmwdaSoDQNphPfTaQ"; + sout << "R0Xh3xqsZKgHLKxB14Rsf/R7Eu9ZASTByX3UrEHsSzLSUo9/G+tS3n1iC30Liusksh2Wkt+/QtDy"; + sout << "A1ZX31H5OlSFwCYC/TYitwyl4U9k7WhHBDoT7MdmVTYQEK1dK48nwOhnZa9prE8n3dD40CCe25q3"; + sout << "Qo4VVYc5tBWu1TfTbshvkmHAcp3Gyw/caqq6jdq5Z2BD1b67i/bY66xhmowOFS8xeA7v6tKdkvpp"; + sout << "Rk8FegzVdB72wpw3872T4K+eplMDcCPGkwIieF5pZStWxhGsNOC0p2wvpFvTpQgfNOGUvRt69hsd"; + sout << "xaUEYlWZcY3sfsiOwPGgBUEEv6b+8W7+8Ddj8Nx4wG+bdWozphfz7THbmOeaDM63imIEHmJbZ47I"; + sout << "QgoyzFD5WoWtZ1wMEv4LL+a63B3FzBcvPvdPaa2QEmyiK9yN7GEePs2Fv2A3ymhGw5NeR1dOzAjz"; + sout << "lEQW01p8opk/dpyLO18zj8d+Hn4EnJkKD0p1u+XuLRda8AnRu/WmSOOpyG5EUrUoEyuvbECLbY9X"; + sout << "3AMgzkbxltmZlkyOOwfCGM0yumGYKdz0aGKdyid7ddLMTpQ908dCNLyRgTybdZG9137PQirgX5+O"; + sout << "08T/+L4EIyyrslOYxpUaLm2ASnSUgiivoIJvfnu8IeH2W9fPupY89ioXIYuwZU8f9FDCA9z7peQw"; + sout << "9H6l4PDdDrB7nwQhncpV9FYLkHQLbSgE1VD+eL6Y2k48pI2zUndcoHEZW72NcmK6E8fDvfgbKkYD"; + sout << "m02RiGuj4tvEEsIVuVa29Q0JGO+37n7Mlz7+RMcUMo1pLnh+jibas6R+1LCy7b4ubiKMFB1gvjut"; + sout << "gjMABy1dJxSOdb9xUa0K/Alwwu3MxdkrbTxwqkn0C2JnVV7z9S2I+PWcfZKzcpg8Itzh/ON6I/DE"; + sout << "EGK3s39XhLI2xPg3PE9R9QMaisqxb3FeP1NkBXrLQtuQfrSk+KZk6ArQWVgtem799fxgipQsa5RH"; + sout << "z2Dq9t+pJzNGUnWg5PWzaAY3lWMscn+BIRhsZfDJ3QBtS9Vmib8r2dtYwXi/Q+FhnAHFfcXbhDC3"; + sout << "GHn16aP2PY1sw8KMtfPRAcqY8Ylbr9EQXjWoIYUs0YyX2Ks8ZgibunTPFz/Wu98RVYswMtjubFaJ"; + sout << "jb0pK9S6qoe/w10CAAHqoAfca7uMOxw9trZZmjCf5vF4leH/nDgsNjesYn21rE6rLhSbg8vaZXo5"; + sout << "I/e1uhZlRz4ZNnMlZSnL70Jt0IjuR0YNphCsGZjmvvZ4ihxrcLrHvAcSTJuqW5EARtvjyQWqBKSP"; + sout << "5XhlkrI73Ejvy+Lhv6n6O7+VrfWa/tGRuvvAToS1wPOP1T2oniDXsNlD0QbMnCao+dTWgkTDiNTk"; + sout << "sFxsoN8YjwHqYUAp+hfnu1Vh2ovyemAUmo87vuG7at6f8MgFSuZffmBkGuijKNDDy7OrHoh7+5/+"; + sout << "aOkcvp0pW3ONZ4l6peRNvzaW5DEBTvcZGvRwVCHWII1eGpzeJKaHWvDfLqjaPkFrG5pR7SGCY/9L"; + sout << "73W2U0JCe2h7VjWbCM7hdvJEgYi/mEarVQpt+0P834es6Rm9rsMCbgbrWl7uv35+LVMTHU29Oxln"; + sout << "bDzBUJQs5KIA81IWR3R7D+HuJvpMkAYMF73c1owI7K74SBOsTq1ayC81aNlK7YwOOjZyBqwsQ5sy"; + sout << "zZi0k9AcKRGmTC323o7Tp/n/gkAU3NObTnqPEJitjGloXqrhPvorixBhHXSZy+wgL5R+04KiF1uU"; + sout << "LEFOzJ0zKUMstTB+fgC7D6ZnVEtUq3HEYnmaRRwEhRSgMTLXE8VvnOdo802pMVN5GMCkH299rJm5"; + sout << "Ina8mTwlC9JrNuYHot5KK/Gny4KPyUeS51cifByPwroemwBHe9EmKCkcEJPoDpG3QMaV36aopyJl"; + sout << "GwhZxaZSqbut9XSWr0IMxHUkFeslRB+n/7Vx+xWpDNjQ7JA5S/B0ZW+YBQPcjA3sRQTey25JD4Jy"; + sout << "RsULxNY5e3mjn59fI8OpBOYfNPTt2Jzppm1GDpym0LHuz7KZ6xk6QAyogk+HMjC/5RcQA7zJWDRM"; + sout << "dXC4CXUjrBxVzmm/YHXv76LrsaFdzJgn+/qzlM6IvIgicMhcJl+hA1swTkgcw6JRalJiDqnvapKP"; + sout << "V+T+/X5PSNMswgZURHQJ2l0PkMrUT909pBOC9t4GCsK8k4rYS2o0I0UYfcpm4jMRU5X34zlT8Qv+"; + sout << "GV3mA0oGq1U2dJwArlPX3gI5sZ2Jsw7Qa5edvQNG5GoRb2j2Muo4AkZXXjbx0KEa5leLIhVL4BAE"; + sout << "2GTdbL7T8hUGY3QlRQGwSVAytjUfXg4jCyn9w6ZbxUOu5MDBuCEtrhRSJNKuBLInK3Bh+fr2FshC"; + sout << "T1eDtIFE2EDEaSbLj4NCNWpTFdKMXZ9CQg2VtoVOIJfgKzqAjjcWX8kqWpMFlQgtdTfIqN7gnFit"; + sout << "do/FO0OzLghevyexHdl+Ze+MjITKOF0mTPPMkcIYcINIR1za6q3rLDZg03+GouzYhL8lwM3WAnkg"; + sout << "Qg+NM6reQATKFK3ieOxacZYnIwOR/ZMM/lO/rHY/ZbdAnJHbMBWwRtK1vDi+o+ZgS7EgsDpsmz/l"; + sout << "PguXPK0Ws51OUhIJJ5YDBv+nVPJabxOYV3dU0z49xFpxNTW9pTISo8mKZvLp2D765kExGJ9YKoAx"; + sout << "Hfi6WEg3pFS9YQLNhOZjE4bQThugIWXhi+2OPgqUIUoV5ctSnP5Lv+xhbkZfjnQQQQffrrU4peSz"; + sout << "6CuNEVLuNuG/mc3WEDZwf1HxYv3u9pr7A79QG0EROf23zPzaf5biE9e9xH+ruPApRHM58H2RpxXU"; + sout << "RlkYnfoAUqyvT3Lhhk6ngv8Axhi4otvz7sRiXQmZO7mtzWzsCTkCJoziwRKlD6P6LYnbm4fRYP1M"; + sout << "MvOuW3NhsQNrsDtgMuvqiVQpRzg157ES1i1qnTjJxTD5emK1RljuQEetbGksyetctWdWiEd8ZfSh"; + sout << "DHBJC2FLucmkMt0LHsVPnk4ni055uMRdKPRKjTE2MjpEsxR52xiWR3MtwXiEhH9fZnUl1IdBl3PG"; + sout << "TfLiZ286m4ePm6JOgNM1chtZir+q8pr4ghk/xycWvHmgkqT9dQcFP8iEtlVLCS22/2mS79cTev2r"; + sout << "yE90otp9vibcTnpORzrnLrMhhpmYRTxRjRaHGhwdJYluARJFBBVTMEenK2ubdLOJ8skZjLzPv1dt"; + sout << "9IrO1sNUwrMpEie8PG7D7DzQ7//jdlC/HUZaGKrwj5aMUULi+ZYiBLYoeL4N8ozAK1u3KtXLKlRE"; + sout << "3Akys4Py8+CmrY5qaaDOXZvwl3FF3skmGhx5KValRXrbndqr3Cks0hXglHgNonZh795galZwu0Jp"; + sout << "ww/mTQLCV0djTdEfjXBUnP49zyGXWWsEsl2jfqEAfBDcT4+mMzAUtBSwwPJYXXAJQz45R32MThNb"; + sout << "k21X+rw63QJe0zIbOJepHz3jaedMkj8GKNYBjqzibNqfYelunBUqW0bpi81HYdN5OFY/3GNKgygG"; + sout << "4R5HJaP+x9e1HxehpI/4pKFC+TAIb29uSV5GtkNTb1fYLm0kjeCZNA5GKtf42gBY52N6STl+lcI0"; + sout << "gD+jJ/ogknne3sRtEJEtCFFe1c50oikyJamQbeUO1PcDUBt8Phl1rI/p4PTP+H686usJVhSDY+b5"; + sout << "9CdS6F7XSSDiXlpFl+Esex30fRZ8zAQsTo9oN0sSZUUJKcyVk0dCqw2mHWPpyM6hYKQ3ij1nYjYl"; + sout << "3PzRfFMlu+dgStcBn70jvlEv5pOWXb2OqrN9nJtb29n8jrB2K2nlbcYoPPiQ3yXk+Wpom82LoT5W"; + sout << "F9NeNwwAB4EDWtB96OU6noW8NHJj7NiADQJGvQpk/3JzIzeBJQCxULYJMRJdBKf61+24F791reHa"; + sout << "qrH+rLUrrv05dIPDTUvGW5LQLTTFFa59OmMIu7WJE7Ln6gMIwDw3FXnGFzaWnHlHL/9jJ0zM1FQL"; + sout << "kfK4wTd++GbeI0gsnXWFK0N0kV/FiHm++J4udWwIXZxH7qZCHtwlT/5oGDVujtAtOPag+txUrjVc"; + sout << "G4iLeiPbV/2Vfc2D1oV5/yyXDDii9qrLH6SOOfgvdiJZr7X3uMUIDGO75x5wBDSxr9t3I2CrX2dM"; + sout << "M6kD7U1+bf5QVRbkh3Us4NAhFVnLNEcrm0x9Yx0wRmxPKgJeGGbWi7/BHi8ShIFllizuxuMyfypC"; + sout << "hhzSlxxbYAQwtcC3cHEnyYZAO7HC6hyke+HQJfxAmKyfguGtzEzsiG18XJVruwz7IoOpZS/O71zy"; + sout << "Nv+T8trOhy59ZUAgIsCAAQJYEBWl/T/qFtkE+tITbVRKtHjbxHSeN12OnHFRoKguJYaakTo4qLs0"; + sout << "fr4E4nZUMfjdF7oI7YutegY9TkiJ9ujLJw4pfY1XRtPrRukEl8orypWXq0gErnYO/RVtK3XImrDp"; + sout << "LY5sXH5pNzkqVH9VCl6lh9sg2HWjNwv9bDcDlIhvTL19Mx9yUtx/iQtG/OKy22tW6ByahPNnMNtA"; + sout << "tBVB38RLf6eJr68mhn10Qg68cXxVL7/zEIZd9rUaCo8xCzeFblDNErKfG02JJ6fbQ6M6ZdNez7Q0"; + sout << "x2IYbz2DEk0wHmR7OtA/oTFMvJlyMt+dDWTEpHnvqkbe+veENpxn2WWy3UsumkvhhtzzmLxyD6Sh"; + sout << "mMbMPwgUjvMG51JfRrgMfJzT49z0sebSfzvid/9QV4lNkR7s9nfUJEwAued4S4klRy3LiFdQhjQR"; + sout << "FOZZNqUge8vxVOzVCfS+xsjvnGrd7azt7LJg6wPXFgPfeE2bRlx+8AoRFG7SUpudmm/bkNw+uNgS"; + sout << "YRdaH8p16RyNoMlSfi/7BNDhtKwrl202pVuCqhFey0mPYehYee2HhLZs6ph+HKMYy8lZ/ac1Q17d"; + sout << "1tcI4WH0Hz0B/3GWl8xWfoq2OO40EIjuCPNhk70MpiytWXggJrKoKPu52GOqTU8+jZ6F+u6U2muZ"; + sout << "6QZLYXDwPaNz/lq5U4ACw767DkhUHd1/h0g6r/RwtLKxdrzYldQto99TAMmHc+z9aIciTv7kl/Gs"; + sout << "WA58nI8aODhwjIkOGaExdlR1k/3JR2tAAj5vRzYlJeakhAA82pA+8xMPZr3HRlQx4DlEjH1spAA="; + + // Put the data into the istream sin + sin.str(sout.str()); + sout.str(""); + + // Decode the base64 text into its compressed binary form + base64_coder.decode(sin,sout); + sin.clear(); + sin.str(sout.str()); + sout.str(""); + + // Decompress the data into its original form + compressor.decompress(sin,sout); + + // Return the decoded and decompressed data + return sout.str(); + } + +} + + + diff --git a/dlib/test/makefile b/dlib/test/makefile index 10da60d1e..4b080c37a 100644 --- a/dlib/test/makefile +++ b/dlib/test/makefile @@ -59,6 +59,7 @@ SRC += ekm_and_lisf.cpp SRC += empirical_kernel_map.cpp SRC += entropy_coder.cpp SRC += entropy_encoder_model.cpp +SRC += fft.cpp SRC += filtering.cpp SRC += find_max_factor_graph_nmplp.cpp SRC += find_max_factor_graph_viterbi.cpp