core/vnl/algo/vnl_convolve.txx
Go to the documentation of this file.
00001 // This is core/vnl/algo/vnl_convolve.txx
00002 #ifndef vnl_convolve_txx_
00003 #define vnl_convolve_txx_
00004 
00005 #include "vnl_convolve.h"
00006 #include <vnl/algo/vnl_fft_1d.h> // this #includes <vcl_complex.h>
00007 #include <vcl_cassert.h>
00008 #include <vcl_iostream.h> // for warning messages
00009 
00010 template <class T1, class T2, class U>
00011 inline
00012 vnl_vector<U> vnl_convolve_cyclic_using_fft(vnl_vector<T1> const& v1, vnl_vector<T2> const& v2, U*)
00013 {
00014   assert (v1.size() == v2.size());
00015   unsigned int n = v1.size();
00016 
00017   typedef vcl_complex<double> C;
00018   vnl_vector<C> w1(n, C(0)); for (unsigned i=0; i<n; ++i) w1[i]=v1[i];
00019   vnl_vector<C> w2(n, C(0)); for (unsigned i=0; i<n; ++i) w2[i]=v2[i];
00020 
00021   vnl_fft_1d<double> fft(n); fft.fwd_transform(w1); fft.fwd_transform(w2);
00022   for (unsigned int i=0; i<n; ++i) w1[i] *= w2[i];
00023   fft.bwd_transform(w1);
00024 #ifdef DEBUG
00025   vcl_cout << w1 << vcl_endl;
00026 #endif
00027 
00028   vnl_vector<U> r(n);
00029   for (unsigned int i = 0; i<n; ++i)
00030     r[i] = U(vcl_real(w1[i]) / n); // the imaginary part is certainly zero
00031 #ifdef DEBUG
00032   for (unsigned int i = 0; i<n; ++i)
00033     assert(vcl_imag(w1[i]) == 0);
00034 #endif
00035   return r;
00036 }
00037 
00038 template <class T1, class T2, class U>
00039 vnl_vector<U> vnl_convolve_cyclic(vnl_vector<T1> const& v1, vnl_vector<T2> const& v2, U*, bool use_fft)
00040 {
00041   assert (v1.size() == v2.size());
00042   unsigned int n = v1.size();
00043 
00044   // Quick return if possible:
00045   if (n == 0) return vnl_vector<U>(0, U(0));
00046   if (n == 1) return vnl_vector<U>(1, U(v1[0]*v2[0]));
00047 
00048   if (use_fft)
00049     return vnl_convolve_cyclic_using_fft(v1, v2, (U*)0);
00050 
00051   vnl_vector<U> ret(n, (U)0); // all elements already initialized to zero
00052   for (unsigned int k=0; k<n; ++k)
00053   {
00054     for (unsigned int i=0; i<=k; ++i)
00055       ret[k] += U(v1[k-i]) * U(v2[i]);
00056     for (unsigned int i=k+1; i<n; ++i)
00057       ret[k] += U(v1[n+k-i]) * U(v2[i]);
00058   }
00059 
00060   return ret;
00061 }
00062 
00063 inline bool has_only_primefactors_2_3_5(unsigned int n)
00064 {
00065   if (n <= 1) return true;
00066   while (n%2 == 0) n /= 2;
00067   while (n%3 == 0) n /= 3;
00068   while (n%5 == 0) n /= 5;
00069   return n==1;
00070 }
00071 
00072 template <class T1, class T2, class U>
00073 inline
00074 vnl_vector<U> vnl_convolve_using_fft(vnl_vector<T1> const& v1, vnl_vector<T2> const& v2, U*, int n)
00075 {
00076   if (n+1 < int(v1.size() + v2.size())) n = v1.size() + v2.size() - 1;
00077 
00078   // Make sure n has only prime factors 2, 3 and 5; if necessary, increase n.
00079   while (!has_only_primefactors_2_3_5(n)) ++n;
00080 
00081   // pad with zeros, so the cyclic convolution is a convolution:
00082   vnl_vector<U> w1(n, U(0)); for (unsigned i=0; i<v1.size(); ++i) w1[i]=U(v1[i]);
00083   vnl_vector<U> w2(n, U(0)); for (unsigned i=0; i<v2.size(); ++i) w2[i]=U(v2[i]);
00084   // convolve, using n-points FFT:
00085   w1 = vnl_convolve_cyclic_using_fft(w1, w2, (U*)0);
00086   // return w1, but possibly drop the last few (zero) entries:
00087   return vnl_vector<U>(v1.size()+v2.size()-1, v1.size()+v2.size()-1, w1.data_block());
00088 }
00089 
00090 template <class T>
00091 vnl_vector<T> vnl_convolve(vnl_vector<T> const& v1, vnl_vector<T> const& v2, int use_fft)
00092 {
00093   // Quick return if possible:
00094   if (v1.size() == 0 || v2.size() == 0)
00095     return vnl_vector<T>(0);
00096   if (v1.size() == 1) return v2*v1[0];
00097   if (v2.size() == 1) return v1*v2[0];
00098 
00099   if (use_fft != 0)
00100     return vnl_convolve_using_fft(v1, v2, (T*)0, use_fft);
00101 
00102   unsigned int n = v1.size() + v2.size() - 1;
00103   vnl_vector<T> ret(n, (T)0); // all elements already initialized to zero
00104   for (unsigned int k=0; k<v1.size(); ++k)
00105     for (unsigned int i=0; i<=k && i<v2.size(); ++i)
00106       ret[k] += v1[k-i] * v2[i];
00107   for (unsigned int k=v1.size(); k<n; ++k)
00108     for (unsigned int i=k+1-v1.size(); i<=k && i<v2.size(); ++i)
00109       ret[k] += v1[k-i] * v2[i];
00110 
00111   return ret;
00112 }
00113 
00114 template <class T1, class T2, class U>
00115 vnl_vector<U> vnl_convolve(vnl_vector<T1> const& v1, vnl_vector<T2> const& v2, U*, int use_fft)
00116 {
00117   // Quick return if possible:
00118   if (v1.size() == 0 || v2.size() == 0)
00119     return vnl_vector<U>(0);
00120 
00121   if (use_fft != 0)
00122     return vnl_convolve_using_fft(v1, v2, (U*)0, use_fft);
00123 
00124   unsigned int n = v1.size() + v2.size() - 1;
00125   vnl_vector<U> ret(n, (U)0); // all elements already initialized to zero
00126   for (unsigned int k=0; k<v1.size(); ++k)
00127     for (unsigned int i=0; i<=k && i<v2.size(); ++i)
00128       ret[k] += U(v1[k-i]) * U(v2[i]);
00129   for (unsigned int k=v1.size(); k<n; ++k)
00130     for (unsigned int i=k+1-v1.size(); i<=k && i<v2.size(); ++i)
00131       ret[k] += U(v1[k-i]) * U(v2[i]);
00132 
00133   return ret;
00134 }
00135 
00136 #undef VNL_CONVOLVE_INSTANTIATE
00137 #define VNL_CONVOLVE_INSTANTIATE_2(T,U) \
00138 template vnl_vector<U > vnl_convolve(vnl_vector<T > const&, vnl_vector<U > const&, U*, int); \
00139 template vnl_vector<U > vnl_convolve_cyclic(vnl_vector<T > const&, vnl_vector<U > const&, U*, bool)
00140 
00141 #define VNL_CONVOLVE_INSTANTIATE(T,U) \
00142 VNL_CONVOLVE_INSTANTIATE_2(T,U); \
00143 template vnl_vector<T > vnl_convolve(vnl_vector<T > const&, vnl_vector<T > const&, int)
00144 
00145 #endif // vnl_convolve_txx_