21 Convolve::Convolve() : m_mode(FFTW_UNDEFINED)
 
   24     const size_t FFTW_FACTORS[] = {13, 11, 7, 5, 3, 2};
 
   25     m_implemented_factors.assign(FFTW_FACTORS,
 
   26                                  FFTW_FACTORS + 
sizeof(FFTW_FACTORS) / 
sizeof(FFTW_FACTORS[0]));
 
   29 Convolve::Workspace::Workspace()
 
   30     : h_src(0), w_src(0), h_kernel(0), w_kernel(0), w_fftw(0), h_fftw(0), in_src(0), out_src(0),
 
   31       in_kernel(0), out_kernel(0), dst_fft(0), h_dst(0), w_dst(0),
 
   33       h_offset(0), w_offset(0), p_forw_src(nullptr), p_forw_kernel(nullptr), p_back(nullptr)
 
   37 Convolve::Workspace::~Workspace()
 
   42 void Convolve::Workspace::clear()
 
   53         fftw_free((fftw_complex*)out_src);
 
   61         fftw_free((fftw_complex*)out_kernel);
 
   74     if (p_forw_src != 
nullptr)
 
   75         fftw_destroy_plan(p_forw_src);
 
   76     if (p_forw_kernel != 
nullptr)
 
   77         fftw_destroy_plan(p_forw_kernel);
 
   78     if (p_back != 
nullptr)
 
   79         fftw_destroy_plan(p_back);
 
   90     if (m_mode == FFTW_UNDEFINED)
 
   93     int h_src = (int)source.size();
 
   94     int w_src = (int)(source.size() ? source[0].size() : 0);
 
   95     int h_kernel = (int)kernel.size();
 
   96     int w_kernel = (kernel.size() ? (int)kernel[0].size() : 0);
 
   99     init(h_src, w_src, h_kernel, w_kernel);
 
  101     fftw_circular_convolution(source, kernel);
 
  105     result.resize(ws.h_dst);
 
  106     for (
int i = 0; i < ws.h_dst; i++) {
 
  107         result[i].resize(ws.w_dst, 0);
 
  108         for (
int j = 0; j < ws.w_dst; j++) {
 
  110             if (m_mode == FFTW_CIRCULAR_SAME_SHIFTED) {
 
  111                 result[i][j] = ws.dst_fft[((i + int(ws.h_kernel / 2.0)) % ws.h_fftw) * ws.w_fftw
 
  112                                           + (j + int(ws.w_kernel / 2.0)) % ws.w_fftw];
 
  114                 result[i][j] = ws.dst_fft[(i + ws.h_offset) * ws.w_fftw + j + ws.w_offset];
 
  127     source2d.push_back(source);
 
  128     kernel2d.push_back(kernel);
 
  132     if (result2d.size() != 1)
 
  134     result = result2d[0];
 
  142     if (!h_src || !w_src || !h_kernel || !w_kernel) {
 
  143         std::ostringstream os;
 
  144         os << 
"Convolve::init() -> Panic! Wrong dimensions " << h_src << 
" " << w_src << 
" " 
  145            << h_kernel << 
" " << w_kernel << std::endl;
 
  152     ws.h_kernel = h_kernel;
 
  153     ws.w_kernel = w_kernel;
 
  155     case FFTW_LINEAR_FULL:
 
  157         ws.h_fftw = find_closest_factor(h_src + h_kernel - 1);
 
  158         ws.w_fftw = find_closest_factor(w_src + w_kernel - 1);
 
  159         ws.h_dst = h_src + h_kernel - 1;
 
  160         ws.w_dst = w_src + w_kernel - 1;
 
  165     case FFTW_LINEAR_SAME_UNPADDED:
 
  167         ws.h_fftw = h_src + int(h_kernel / 2.0);
 
  168         ws.w_fftw = w_src + int(w_kernel / 2.0);
 
  173         ws.h_offset = int(ws.h_kernel / 2.0);
 
  174         ws.w_offset = int(ws.w_kernel / 2.0);
 
  176     case FFTW_LINEAR_SAME:
 
  178         ws.h_fftw = find_closest_factor(h_src + 
int(h_kernel / 2.0));
 
  179         ws.w_fftw = find_closest_factor(w_src + 
int(w_kernel / 2.0));
 
  184         ws.h_offset = int(ws.h_kernel / 2.0);
 
  185         ws.w_offset = int(ws.w_kernel / 2.0);
 
  187     case FFTW_LINEAR_VALID:
 
  189         if (ws.h_kernel > ws.h_src || ws.w_kernel > ws.w_src) {
 
  194             std::cout << 
"The 'valid' convolution results in an empty matrix" << std::endl;
 
  195             throw std::runtime_error(
"The 'valid' convolution results in an empty matrix");
 
  197             ws.h_fftw = find_closest_factor(h_src);
 
  198             ws.w_fftw = find_closest_factor(w_src);
 
  199             ws.h_dst = h_src - h_kernel + 1;
 
  200             ws.w_dst = w_src - w_kernel + 1;
 
  203         ws.h_offset = ws.h_kernel - 1;
 
  204         ws.w_offset = ws.w_kernel - 1;
 
  206     case FFTW_CIRCULAR_SAME:
 
  207     case FFTW_CIRCULAR_SAME_SHIFTED:
 
  222             << 
"Unrecognized convolution mode, possible modes are " 
  223             << 
"FFTW_LINEAR_FULL, FFTW_LINEAR_SAME, FFTW_LINEAR_SAME_UNPADDED, FFTW_LINEAR_VALID, " 
  224             << 
"FFTW_CIRCULAR_SAME, FFTW_CIRCULAR_SHIFTED " << std::endl;
 
  228     ws.in_src = 
new double[ws.h_fftw * ws.w_fftw];
 
  229     ws.out_src = (
double*)fftw_malloc(
sizeof(fftw_complex) * ws.h_fftw * (ws.w_fftw / 2 + 1));
 
  230     ws.in_kernel = 
new double[ws.h_fftw * ws.w_fftw];
 
  231     ws.out_kernel = (
double*)fftw_malloc(
sizeof(fftw_complex) * ws.h_fftw * (ws.w_fftw / 2 + 1));
 
  233     ws.dst_fft = 
new double[ws.h_fftw * ws.w_fftw];
 
  237     ws.p_forw_src = fftw_plan_dft_r2c_2d(ws.h_fftw, ws.w_fftw, ws.in_src, (fftw_complex*)ws.out_src,
 
  239     if (ws.p_forw_src == 
nullptr)
 
  241             "Convolve::init() -> Error! Can't initialise p_forw_src plan.");
 
  243     ws.p_forw_kernel = fftw_plan_dft_r2c_2d(ws.h_fftw, ws.w_fftw, ws.in_kernel,
 
  244                                             (fftw_complex*)ws.out_kernel, FFTW_ESTIMATE);
 
  245     if (ws.p_forw_kernel == 
nullptr)
 
  247             "Convolve::init() -> Error! Can't initialise p_forw_kernel plan.");
 
  250     ws.p_back = fftw_plan_dft_c2r_2d(ws.h_fftw, ws.w_fftw, (fftw_complex*)ws.out_kernel, ws.dst_fft,
 
  252     if (ws.p_back == 
nullptr)
 
  254             "Convolve::init() -> Error! Can't initialise p_back plan.");
 
  261 void Convolve::fftw_circular_convolution(
const double2d_t& src, 
const double2d_t& kernel)
 
  263     if (ws.h_fftw <= 0 || ws.w_fftw <= 0)
 
  265             "Convolve::fftw_convolve() -> Panic! Initialisation is missed.");
 
  267     double *ptr, *ptr_end, *ptr2;
 
  270     for (ptr = ws.in_src, ptr_end = ws.in_src + ws.h_fftw * ws.w_fftw; ptr != ptr_end; ++ptr)
 
  272     for (ptr = ws.in_kernel, ptr_end = ws.in_kernel + ws.h_fftw * ws.w_fftw; ptr != ptr_end; ++ptr)
 
  277     for (
int i = 0; i < ws.h_src; ++i)
 
  278         for (
int j = 0; j < ws.w_src; ++j, ++ptr)
 
  279             ws.in_src[(i % ws.h_fftw) * ws.w_fftw + (j % ws.w_fftw)] += src[i][j];
 
  282     for (
int i = 0; i < ws.h_kernel; ++i)
 
  283         for (
int j = 0; j < ws.w_kernel; ++j, ++ptr)
 
  284             ws.in_kernel[(i % ws.h_fftw) * ws.w_fftw + (j % ws.w_fftw)] += kernel[i][j];
 
  287     fftw_execute(ws.p_forw_src);
 
  288     fftw_execute(ws.p_forw_kernel);
 
  292     double re_s, im_s, re_k, im_k;
 
  293     for (ptr = ws.out_src, ptr2 = ws.out_kernel,
 
  294         ptr_end = ws.out_src + 2 * ws.h_fftw * (ws.w_fftw / 2 + 1);
 
  295          ptr != ptr_end; ++ptr, ++ptr2) {
 
  300         *(ptr2 - 1) = re_s * re_k - im_s * im_k;
 
  301         *ptr2 = re_s * im_k + im_s * re_k;
 
  306     fftw_execute(ws.p_back);
 
  308     for (ptr = ws.dst_fft, ptr_end = ws.dst_fft + ws.w_fftw * ws.h_fftw; ptr != ptr_end; ++ptr)
 
  309         *ptr /= double(ws.h_fftw * ws.w_fftw);
 
  317 int Convolve::find_closest_factor(
int n)
 
  323         while (!is_optimal(j))
 
  332 bool Convolve::is_optimal(
int n)
 
  337     for (
size_t i = 0; i < m_implemented_factors.size(); i++) {
 
  338         while ((ntest % m_implemented_factors[i]) == 0) {
 
  339             ntest = ntest / m_implemented_factors[i];
 
Defines class MathFunctions::Convolve.
 
Defines many exception classes in namespace Exceptionss.
 
std::vector< double1d_t > double2d_t
definition of 2d vector of double
 
std::vector< double > double1d_t
definition of 1d vector of double
 
void init(int h_src, int w_src, int h_kernel, int w_kernel)
prepare arrays for 2D convolution of given vectors
 
void setMode(EConvolutionMode mode)
Sets convolution mode.
 
void fftconvolve(const double1d_t &source, const double1d_t &kernel, double1d_t &result)
convolution in 1D