KJB
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
m_convolve.h
Go to the documentation of this file.
1 
10 /* $Id: m_convolve.h 15035 2013-07-29 23:32:59Z predoehl $ */
11 
12 /* {{{======================================================================= *
13  |
14  | Copyright (c) 1994-2013 by members of the Interdisciplinary Visual
15  | Intelligence Laboratory.
16  |
17  | Personal and educational use of this code is granted, provided that this
18  | header is kept intact, and that the authorship is not misrepresented, that
19  | its use is acknowledged in publications, and relevant papers are cited.
20  |
21  | For other use contact kobus AT sista DOT arizona DOT edu.
22  |
23  | Please note that the code in this file has not necessarily been adequately
24  | tested. Naturally, there is no guarantee of performance, support, or
25  | fitness for any particular task. Nonetheless, I am interested in hearing
26  | about problems that you encounter.
27  |
28  * ====================================================================== }}}*/
29 
30 // vim: tabstop=4 shiftwidth=4 foldmethod=marker
31 
32 #ifndef KJB_CPP_M_CPP_M_CONVOLVE_H
33 #define KJB_CPP_M_CPP_M_CONVOLVE_H
34 
35 #include <m_cpp/m_matrix.h>
36 
37 #ifdef KJB_HAVE_FFTW /* Include the header, if we can. */
38 
39 /*
40  * Their header has a built-in extern-C gadget, so we do not need one here.
41  * However, we would like to wrap their symbols in a namespace.
42  */
43 namespace FFTW {
44 #include <fftw3.h>
45 }
46 
47 #else /* KJB_HAVE_FFTW not defined */
48 #warning "This code requires FFTW version 3 to work properly."
49 const int FFTW_ESTIMATE = 0;
50 const int FFTW_MEASURE = 0;
51 const int FFTW_PATIENT = 0;
52 const int FFTW_EXHAUSTIVE = 0;
53 const int FFTW_DESTROY_INPUT = 0;
54 #endif /* KJB_HAVE_FFTW */
55 
56 
57 #include <utility>
58 #include <boost/scoped_ptr.hpp>
59 #include <boost/shared_ptr.hpp>
60 
61 
66 namespace kjb
67 {
68 
69 #ifdef KJB_HAVE_FFTW /* This block defines a speciality vector for FFTW */
70 
71 
72 // We don't need the end pointer currently, but future changes might demand it.
73 #define KJB_FFTW_VECTOR_NEEDS_END 0
74 
75 
88 template <typename T>
89 class FFTW_vector
90 {
91  T* m_begin;
92 #if KJB_FFTW_VECTOR_NEEDS_END
93  T* m_end;
94 #endif
95  FFTW_vector<T>(const FFTW_vector<T>&); // teaser
96  FFTW_vector<T>& operator=(const FFTW_vector<T>&); // teaser
97 
98 public:
99  FFTW_vector(size_t n = 0)
100  : m_begin(0)
101  {
102  if (n && 0 == (m_begin = (T*) FFTW::fftw_malloc(sizeof(T) * n)))
103  {
104  KJB_THROW(Resource_exhaustion);
105  }
106 #if KJB_FFTW_VECTOR_NEEDS_END
107  m_end = m_begin + n;
108 #endif
109  }
110 
111  ~FFTW_vector()
112  {
113  if (m_begin) FFTW::fftw_free(m_begin);
114  }
115 
116  T* begin()
117  {
118  return m_begin;
119  }
120 
121  const T* begin() const
122  {
123  return m_begin;
124  }
125 
126 #if KJB_FFTW_VECTOR_NEEDS_END
127  T* end()
128  {
129  return m_end;
130  }
131 
132  const T* end() const
133  {
134  return m_end;
135  }
136 #endif
137 
138  void swap(FFTW_vector<T>& v)
139  {
140  using std::swap;
141  swap(m_begin, v.m_begin);
142 #if KJB_FFTW_VECTOR_NEEDS_END
143  swap(m_end, v.m_end);
144 #endif
145  }
146 };
147 
148 
150 typedef FFTW_vector<FFTW::fftw_complex> FFTW_complex_vector;
151 
153 typedef FFTW_vector<double> FFTW_real_vector;
154 
155 
156 
157 #else /* what to do if FFTW library is not available? */
158 typedef void* FFTW_complex_vector;
159 typedef void* FFTW_real_vector;
160 #endif
161 
162 
163 
164 
165 
166 
176 template <class T, class U> class FFTW_Plan2d {};
177 
178 
179 
180 #ifdef KJB_HAVE_FFTW /* This block defines FFTW plan wrappers. */
181 
182 // "forward" FFT plan management
183 template<>
184 class FFTW_Plan2d<double, FFTW::fftw_complex>
185 {
186  FFTW::fftw_plan plan;
187 
189  const FFTW_Plan2d<double, FFTW::fftw_complex>&); // teaser
191  const FFTW_Plan2d<double, FFTW::fftw_complex>&); // teaser
192 public:
194  int n0,
195  int n1,
196  double* in,
197  FFTW::fftw_complex* out,
198  unsigned flags
199  )
200  : plan(FFTW::fftw_plan_dft_r2c_2d(n0, n1, in, out, flags))
201  {
202  if (0 == plan) KJB_THROW(Resource_exhaustion);
203  }
204 
205  ~FFTW_Plan2d<double, FFTW::fftw_complex>()
206  {
207  FFTW::fftw_destroy_plan(plan);
208  }
209 
210  void execute() const
211  {
212  FFTW::fftw_execute(plan);
213  }
214 
215  void new_array_exec(double *in, FFTW::fftw_complex *out) const
216  {
217  FFTW::fftw_execute_dft_r2c(plan, in, out);
218  }
219 };
220 
221 
222 // inverse-FFT plan management
223 template<>
224 class FFTW_Plan2d<FFTW::fftw_complex, double>
225 {
226  FFTW::fftw_plan plan;
227 
228  FFTW_Plan2d<FFTW::fftw_complex, double>(
229  const FFTW_Plan2d<FFTW::fftw_complex, double>&); // teaser
230  FFTW_Plan2d<FFTW::fftw_complex, double>& operator=(
231  const FFTW_Plan2d<FFTW::fftw_complex, double>&); // teaser
232 public:
233  FFTW_Plan2d<FFTW::fftw_complex, double>(
234  int n0,
235  int n1,
236  FFTW::fftw_complex* in,
237  double* out,
238  unsigned flags
239  )
240  : plan(FFTW::fftw_plan_dft_c2r_2d(n0, n1, in, out, flags))
241  {
242  if (0 == plan) KJB_THROW(Resource_exhaustion);
243  }
244 
245  ~FFTW_Plan2d<FFTW::fftw_complex, double>()
246  {
247  FFTW::fftw_destroy_plan(plan);
248  }
249 
250  void execute() const
251  {
252  FFTW::fftw_execute(plan);
253  }
254 
255  void new_array_exec(FFTW::fftw_complex *in, double* out) const
256  {
257  FFTW::fftw_execute_dft_c2r(plan, in, out);
258  }
259 };
260 
261 
263 typedef FFTW_Plan2d<double, FFTW::fftw_complex> FFTW_plan_r2c;
264 
266 typedef FFTW_Plan2d<FFTW::fftw_complex, double> FFTW_plan_c2r;
267 
268 #endif
269 
270 
271 
272 
273 
274 
403 {
404 public:
405  typedef std::pair< boost::shared_ptr<FFTW_real_vector>,
406  boost::shared_ptr<FFTW_complex_vector> > Work_buffer;
407 
409  struct Sizes
410  {
412  Sizes(int, int, int, int);
413 
415  {
416  return m.get_num_rows()==data_rows && m.get_num_cols()==data_cols;
417  }
419  {
420  return m.get_num_rows()<=mask_rows && m.get_num_cols()<=mask_cols;
421  }
422  int Nreal() const
423  {
424  return pad_rows * pad_cols;
425  }
426  int Ncomplex() const
427  {
428  return pad_rows * (pad_cols/2 + 1);
429  }
430  };
431 
432 
434  int data_num_rows,
435  int data_num_cols,
436  int mask_max_rows,
437  int mask_max_cols,
438  int fft_alg_type = FFTW_MEASURE
439  );
440 
442  void set_mask(const Matrix&);
443 
445  void set_gaussian_mask(double sigma);
446 
447  void convolve(const Matrix&, Matrix&) const;
448 
450  void reflect_and_convolve(const Matrix&, Matrix&) const;
451 
453  void execute(const Matrix& i, Matrix& o) const { convolve(i, o); }
454 
455  // not thread safe
457 
458 
459 /* ABOVE THE LINE: NOT THREAD SAFE
460  * -----------------------------------------------------------------
461  * BELOW THE LINE: THREAD SAFE
462  */
463 
464  void convolve(const Matrix&, Matrix&, Work_buffer) const;
465 
467  void reflect_and_convolve(const Matrix&, Matrix&, Work_buffer) const;
468 
470  const Sizes& get_sizes() const
471  {
472  return sizes_;
473  }
474 
476  bool is_mask_set() const
477  {
478  return is_mask_set_;
479  }
480 
481 private:
482 
483 #ifdef KJB_HAVE_FFTW
484  Work_buffer alloc_work_buf_impl_() const;
485 
486  void reset_data_plan_() const;
487 
488  void convolution_by_dft_() const;
489 
490  void convolution_by_dft_(Work_buffer) const;
491 #endif
492 
493 
494  // because this field is const, all its members are automatically const.
495  const Sizes sizes_;
496 
497  const int fft_algorithm_type_;
498 
499  bool is_mask_set_;
500 
501  Work_buffer mask_;
502  mutable Work_buffer data_;
503 
504 
505 #ifdef KJB_HAVE_FFTW /* Define plan members in the real thing. */
506  boost::scoped_ptr<FFTW_plan_r2c> mask_plan_;
507  mutable boost::scoped_ptr<FFTW_plan_r2c> data_plan_;
508  mutable boost::scoped_ptr<FFTW_plan_c2r> data_inv_plan_;
509 #endif
510 
511 };
512 
513 
523 {
524  return b.first.unique() && b.second.unique();
525 }
526 
527 
528 namespace debug
529 {
530 
533  const Matrix&,
534  Matrix*,
535  const Fftw_convolution_2d::Sizes&
536 );
537 
538 } // namespace kjb::debug
539 
540 
541 } // namespace kjb
542 
543 #endif
int mask_cols
Definition: m_convolve.h:411
const int FFTW_PATIENT
Definition: m_convolve.h:51
RAII class to manage an FFTW plan.
Definition: m_convolve.h:176
const int FFTW_EXHAUSTIVE
Definition: m_convolve.h:52
void execute(const Matrix &i, Matrix &o) const
deprecated synonym for convolve method
Definition: m_convolve.h:453
Definition for the Matrix class, a thin wrapper on the KJB Matrix struct and its related functionalit...
int mask_rows
Definition: m_convolve.h:411
int get_num_rows() const
Return the number of rows in the matrix.
Definition: m_matrix.h:543
bool work_buffer_is_unique(const Fftw_convolution_2d::Work_buffer &b)
test whether a Work_buffer object is the last handle to its memory
Definition: m_convolve.h:522
void * FFTW_real_vector
Definition: m_convolve.h:159
void swap(Perspective_camera &cam1, Perspective_camera &cam2)
Swap two cameras.
Definition: perspective_camera.h:599
const int FFTW_MEASURE
Definition: m_convolve.h:50
bool is_matrix_size_same_as_data_size(const Matrix &m) const
Definition: m_convolve.h:414
Fftw_convolution_2d(int data_num_rows, int data_num_cols, int mask_max_rows, int mask_max_cols, int fft_alg_type=FFTW_MEASURE)
Initialize the convolver by specifying data and mask dimensions.
Definition: m_convolve.cpp:442
#define KJB_THROW(ex)
Definition: l_exception.h:46
int pad_rows
Definition: m_convolve.h:411
int data_cols
Definition: m_convolve.h:411
Object thrown if a resource allocation failed (memory, fp, etc.)
Definition: l_exception.h:635
A class for performing 2d convolution using the FFTW library.
Definition: m_convolve.h:402
int Ncomplex() const
Definition: m_convolve.h:426
void set_mask(const Matrix &)
set mask, which must fit with mask size maxima given to ctor
Definition: m_convolve.cpp:661
int get_num_cols() const
Return the number of columns in the matrix.
Definition: m_matrix.h:554
Work_buffer allocate_work_buffer() const
get a handle to a work buffer needed for threadsafe convolution.
Definition: m_convolve.cpp:703
int test_reflect_into_input_buf(const Matrix &in, Matrix *out, const Fftw_convolution_2d::Sizes &s)
test function provides transparency to hidden reflect_into_input_buf
Definition: m_convolve.cpp:728
bool is_mask_set() const
read access of the flag indicating whether the mask has been set
Definition: m_convolve.h:476
void set_gaussian_mask(double sigma)
set mask to a circular gaussian kernel of given sigma (pixels)
Definition: m_convolve.cpp:662
Sizes(int, int, int, int)
Definition: m_convolve.cpp:409
utility aggregate stores all sizes – rarely used by caller
Definition: m_convolve.h:409
void swap(kjb::Gsl_Multimin_fdf &m1, kjb::Gsl_Multimin_fdf &m2)
Swap two wrapped multimin objects.
Definition: gsl_multimin.h:693
const Sizes & get_sizes() const
read access to the sizes specified at ctor time
Definition: m_convolve.h:470
int pad_cols
Definition: m_convolve.h:411
int Nreal() const
Definition: m_convolve.h:422
void * FFTW_complex_vector
Definition: m_convolve.h:158
bool is_matrix_size_within_mask_size(const Matrix &m) const
Definition: m_convolve.h:418
void reflect_and_convolve(const Matrix &, Matrix &) const
convolve with mask, assuming input reflects at its boundaries
Definition: m_convolve.cpp:664
const int FFTW_DESTROY_INPUT
Definition: m_convolve.h:53
int data_rows
Definition: m_convolve.h:411
const int FFTW_ESTIMATE
Definition: m_convolve.h:49
get the indices of edges in each direction for i
Definition: APPgetLargeConnectedEdges.m:48
This class implements matrices, in the linear-algebra sense, with real-valued elements.
Definition: m_matrix.h:94
for m
Definition: APPgetLargeConnectedEdges.m:64
void convolve(const Matrix &, Matrix &) const
Definition: m_convolve.cpp:663
std::pair< boost::shared_ptr< FFTW_real_vector >, boost::shared_ptr< FFTW_complex_vector > > Work_buffer
Definition: m_convolve.h:406