vnl_convolve.hxx
Go to the documentation of this file.
1 // This is core/vnl/algo/vnl_convolve.hxx
2 #ifndef vnl_convolve_hxx_
3 #define vnl_convolve_hxx_
4 
5 #include <iostream>
6 #include "vnl_convolve.h"
7 #include <vnl/algo/vnl_fft_1d.h> // this #includes <std::complex.h>
8 #include <cassert>
9 #ifdef _MSC_VER
10 # include <vcl_msvc_warnings.h>
11 #endif
12 
13 template <class T1, class T2, class U>
14 inline
16 {
17  assert (v1.size() == v2.size());
18  unsigned int n = v1.size();
19 
20  typedef std::complex<double> C;
21  vnl_vector<C> w1(n, C(0)); for (unsigned i=0; i<n; ++i) w1[i]=v1[i];
22  vnl_vector<C> w2(n, C(0)); for (unsigned i=0; i<n; ++i) w2[i]=v2[i];
23 
24  vnl_fft_1d<double> fft(n); fft.fwd_transform(w1); fft.fwd_transform(w2);
25  for (unsigned int i=0; i<n; ++i) w1[i] *= w2[i];
26  fft.bwd_transform(w1);
27 #ifdef DEBUG
28  std::cout << w1 << std::endl;
29 #endif
30 
31  vnl_vector<U> r(n);
32  for (unsigned int i = 0; i<n; ++i)
33  r[i] = U(std::real(w1[i]) / n); // the imaginary part is certainly zero
34 #ifdef DEBUG
35  for (unsigned int i = 0; i<n; ++i)
36  assert(std::imag(w1[i]) == 0);
37 #endif
38  return r;
39 }
40 
41 template <class T1, class T2, class U>
42 vnl_vector<U> vnl_convolve_cyclic(vnl_vector<T1> const& v1, vnl_vector<T2> const& v2, U*, bool use_fft)
43 {
44  assert (v1.size() == v2.size());
45  unsigned int n = v1.size();
46 
47  // Quick return if possible:
48  if (n == 0) return vnl_vector<U>(0, U(0));
49  if (n == 1) return vnl_vector<U>(1, U(v1[0]*v2[0]));
50 
51  if (use_fft)
52  return vnl_convolve_cyclic_using_fft(v1, v2, (U*)nullptr);
53 
54  vnl_vector<U> ret(n, (U)0); // all elements already initialized to zero
55  for (unsigned int k=0; k<n; ++k)
56  {
57  for (unsigned int i=0; i<=k; ++i)
58  ret[k] += U(v1[k-i]) * U(v2[i]);
59  for (unsigned int i=k+1; i<n; ++i)
60  ret[k] += U(v1[n+k-i]) * U(v2[i]);
61  }
62 
63  return ret;
64 }
65 
66 inline bool has_only_primefactors_2_3_5(unsigned int n)
67 {
68  if (n <= 1) return true;
69  while (n%2 == 0) n /= 2;
70  while (n%3 == 0) n /= 3;
71  while (n%5 == 0) n /= 5;
72  return n==1;
73 }
74 
75 template <class T1, class T2, class U>
76 inline
78 {
79  if (n+1 < int(v1.size() + v2.size())) n = v1.size() + v2.size() - 1;
80 
81  // Make sure n has only prime factors 2, 3 and 5; if necessary, increase n.
82  while (!has_only_primefactors_2_3_5(n)) ++n;
83 
84  // pad with zeros, so the cyclic convolution is a convolution:
85  vnl_vector<U> w1(n, U(0)); for (unsigned i=0; i<v1.size(); ++i) w1[i]=U(v1[i]);
86  vnl_vector<U> w2(n, U(0)); for (unsigned i=0; i<v2.size(); ++i) w2[i]=U(v2[i]);
87  // convolve, using n-points FFT:
88  w1 = vnl_convolve_cyclic_using_fft(w1, w2, (U*)nullptr);
89  // return w1, but possibly drop the last few (zero) entries:
90  return vnl_vector<U>(v1.size()+v2.size()-1, v1.size()+v2.size()-1, w1.data_block());
91 }
92 
93 template <class T>
94 vnl_vector<T> vnl_convolve(vnl_vector<T> const& v1, vnl_vector<T> const& v2, int use_fft)
95 {
96  // Quick return if possible:
97  if (v1.size() == 0 || v2.size() == 0)
98  return vnl_vector<T>(0);
99  if (v1.size() == 1) return v2*v1[0];
100  if (v2.size() == 1) return v1*v2[0];
101 
102  if (use_fft != 0)
103  return vnl_convolve_using_fft(v1, v2, (T*)nullptr, use_fft);
104 
105  unsigned int n = v1.size() + v2.size() - 1;
106  vnl_vector<T> ret(n, (T)0); // all elements already initialized to zero
107  for (unsigned int k=0; k<v1.size(); ++k)
108  for (unsigned int i=0; i<=k && i<v2.size(); ++i)
109  ret[k] += v1[k-i] * v2[i];
110  for (unsigned int k=v1.size(); k<n; ++k)
111  for (unsigned int i=k+1-v1.size(); i<=k && i<v2.size(); ++i)
112  ret[k] += v1[k-i] * v2[i];
113 
114  return ret;
115 }
116 
117 template <class T1, class T2, class U>
118 vnl_vector<U> vnl_convolve(vnl_vector<T1> const& v1, vnl_vector<T2> const& v2, U*, int use_fft)
119 {
120  // Quick return if possible:
121  if (v1.size() == 0 || v2.size() == 0)
122  return vnl_vector<U>(0);
123 
124  if (use_fft != 0)
125  return vnl_convolve_using_fft(v1, v2, (U*)nullptr, use_fft);
126 
127  unsigned int n = v1.size() + v2.size() - 1;
128  vnl_vector<U> ret(n, (U)0); // all elements already initialized to zero
129  for (unsigned int k=0; k<v1.size(); ++k)
130  for (unsigned int i=0; i<=k && i<v2.size(); ++i)
131  ret[k] += U(v1[k-i]) * U(v2[i]);
132  for (unsigned int k=v1.size(); k<n; ++k)
133  for (unsigned int i=k+1-v1.size(); i<=k && i<v2.size(); ++i)
134  ret[k] += U(v1[k-i]) * U(v2[i]);
135 
136  return ret;
137 }
138 
139 #undef VNL_CONVOLVE_INSTANTIATE
140 #define VNL_CONVOLVE_INSTANTIATE_2(T,U) \
141 template vnl_vector<U > vnl_convolve(vnl_vector<T > const&, vnl_vector<U > const&, U*, int); \
142 template vnl_vector<U > vnl_convolve_cyclic(vnl_vector<T > const&, vnl_vector<U > const&, U*, bool)
143 
144 #define VNL_CONVOLVE_INSTANTIATE(T,U) \
145 VNL_CONVOLVE_INSTANTIATE_2(T,U); \
146 template vnl_vector<T > vnl_convolve(vnl_vector<T > const&, vnl_vector<T > const&, int)
147 
148 #endif // vnl_convolve_hxx_
vnl_vector< U > vnl_convolve_cyclic_using_fft(vnl_vector< T1 > const &v1, vnl_vector< T2 > const &v2, U *)
bool has_only_primefactors_2_3_5(unsigned int n)
size_t size() const
Return the length, number of elements, dimension of this vector.
Definition: vnl_vector.h:126
T const * data_block() const
Access the contiguous block storing the elements in the vector. O(1).
Definition: vnl_vector.h:230
vnl_vector< U > vnl_convolve_using_fft(vnl_vector< T1 > const &v1, vnl_vector< T2 > const &v2, U *, int n)
In-place 1D fast Fourier transform.
Definition: vnl_fft_1d.h:24
VNL_EXPORT vnl_vector< T > vnl_convolve(vnl_vector< T > const &v1, vnl_vector< T > const &v2, int use_fft=0)
Convolve two vnl_vector<T>'s, with the same base type T.
void bwd_transform(std::vector< std::complex< T > > &signal)
backward (inverse) FFT.
Definition: vnl_fft_1d.h:61
Mathematical vector class, templated by type of element.
Definition: vnl_fwd.h:16
Templated 1D and 2D convolution.
void fwd_transform(std::vector< std::complex< T > > &signal)
forward FFT.
Definition: vnl_fft_1d.h:49
VNL_EXPORT vnl_vector< U > vnl_convolve_cyclic(vnl_vector< T1 > const &v1, vnl_vector< T2 > const &v2, U *, bool use_fft=false)
Cyclically convolve two vnl_vector<T>'s of the same length.
In-place 1D fast Fourier transform.