contrib/brl/bbas/bsta/bsta_gauss.cxx
Go to the documentation of this file.
00001 #include "bsta_gauss.h"
00002 //:
00003 // \file
00004 #include <vcl_cmath.h> // for exp()
00005 
00006 double bsta_gauss::bsta_gaussian(const double x, const double sigma)
00007 {
00008   double x_on_sigma = x / sigma;
00009   return (double)vcl_exp(- x_on_sigma * x_on_sigma / 2);
00010 }
00011 
00012 //: generate a 1-d Gaussian kernel  fuzz=0.02 is a good value
00013 void bsta_gauss::bsta_1d_gaussian_kernel(const double sigma,
00014                                     const double fuzz,
00015                                     int& radius,
00016                                     vcl_vector<double>& kernel)
00017 {
00018   for (radius = 0; bsta_gaussian(double(radius), sigma) > fuzz; radius++)
00019   {;}                                         // find radius
00020 
00021   kernel.resize(2*radius + 1);
00022   if (!radius)
00023   {
00024     kernel[0]=1;
00025     return;
00026   }
00027   for (int i=0; i<=radius; ++i)
00028     kernel[radius+i] = kernel[radius-i] = bsta_gaussian(double(i), sigma);
00029   double sum = 0;
00030   for (int i= 0; i <= 2*radius; ++i)
00031     sum += kernel[i];                           // find integral of weights
00032   for (int i= 0; i <= 2*radius; ++i)
00033     kernel[i] /= sum;                           // normalize by integral
00034 }
00035 
00036 // convolve a 1-d array with a Gaussian kernel.  Handle the borders by
00037 // setting the kernel to zero outside the data array.  Adjust the output
00038 // to obtain unit norm, i.e, normalize by the sum of the weights.
00039 //
00040 void bsta_gauss::bsta_1d_gaussian(const double sigma,
00041                                   vcl_vector<double> const& in_buf,
00042                                   vcl_vector<double>& out_buf)
00043 {
00044   int n = in_buf.size(), r = 0;
00045   if (!n)
00046     return;
00047   out_buf.resize(n);
00048   if (n==1)
00049   {
00050     out_buf[0]=in_buf[0];
00051     return;
00052   }
00053   //the general case
00054   vcl_vector<double> ker;
00055   bsta_1d_gaussian_kernel(sigma, 0.02, r, ker);
00056   for (int i = 0; i<n; i++)
00057   {
00058     double sum = 0;
00059     //case a)
00060     //the full kernel is applied
00061     if (i>r&&((n-1)-i>=r))
00062     {
00063       for (int k = -r; k<=r; k++)
00064         sum += ker[k+r]*in_buf[i+k];
00065       out_buf[i]=sum;
00066       continue;
00067     }
00068     //case b)
00069     // full kernel can't be used
00070     int r_minus = i;
00071     if (r_minus>r)
00072       r_minus=r;
00073     int r_plus = (n-1)-i;
00074     if (r_plus>r)
00075       r_plus=r;
00076     double ker_sum =0;
00077     for (int k = -r_minus; k<=r_plus; k++)
00078     {
00079       ker_sum += ker[k+r];
00080       sum += ker[k+r]*in_buf[i+k];
00081     }
00082     out_buf[i]=sum/ker_sum;
00083   }
00084 }
00085 
00086 //convolve a 2-d array with a Gaussian kernel.  Since the Gaussian is
00087 //separable, first convolve along cols and then along rows
00088 void bsta_gauss::bsta_2d_gaussian(const double sigma,
00089                                   vbl_array_2d<double> const& in_buf,
00090                                   vbl_array_2d<double>& out_buf)
00091 {
00092   int n = in_buf.cols(), m = in_buf.rows();
00093   out_buf.resize(m, n);
00094 
00095   //convolve columns
00096   for (int row = 0; row<m; row++)
00097   {
00098     vcl_vector<double> row_buf(n), temp;
00099     for (int col = 0; col<n; col++)
00100       row_buf[col]=in_buf[row][col];
00101     bsta_1d_gaussian(sigma, row_buf, temp);
00102     for (int col = 0; col<n; col++)
00103       out_buf[row][col]=temp[col];
00104   }
00105   //convolve rows
00106   for (int col = 0; col<n; col++)
00107   {
00108     vcl_vector<double> col_buf(m), temp;
00109     for (int row = 0; row<m; row++)
00110       col_buf[row]=out_buf[row][col];
00111     bsta_1d_gaussian(sigma, col_buf, temp);
00112     for (int row = 0; row<m; row++)
00113       out_buf[row][col]=temp[row];
00114   }
00115 }
00116 void bsta_gauss::bsta_3d_gaussian(const double sigma,
00117                                   vbl_array_3d<double> const& in_buf,
00118                                   vbl_array_3d<double>& out_buf)
00119 {
00120   int ni = in_buf.get_row1_count(),
00121     nj = in_buf.get_row2_count(), nk = in_buf.get_row3_count();
00122   out_buf.resize(ni, nj, nk);
00123   //convolve along i
00124   for (int j = 0; j<nj; j++)
00125     for (int k = 0; k<nk; k++)
00126   {
00127     vcl_vector<double> ibuf(ni), temp;
00128     for (int i = 0; i<ni; i++)
00129       ibuf[i]=in_buf[i][j][k];
00130     bsta_1d_gaussian(sigma, ibuf, temp);
00131     for (int i = 0; i<ni; i++)
00132       out_buf[i][j][k]=temp[i];
00133   }
00134   //convolve along j
00135   for (int i = 0; i<ni; i++)
00136     for (int k = 0; k<nk; k++)
00137   {
00138     vcl_vector<double> jbuf(nj), temp;
00139     for (int j = 0; j<nj; j++)
00140       jbuf[j]=in_buf[i][j][k];
00141     bsta_1d_gaussian(sigma, jbuf, temp);
00142     for (int j = 0; j<nj; j++)
00143       out_buf[i][j][k]=temp[j];
00144   }
00145   //convolve along k
00146   for (int i = 0; i<ni; i++)
00147     for (int j = 0; j<nj; j++)
00148   {
00149     vcl_vector<double> kbuf(nk), temp;
00150     for (int k = 0; k<nk; k++)
00151       kbuf[k]=in_buf[i][j][k];
00152     bsta_1d_gaussian(sigma, kbuf, temp);
00153     for (int k = 0; k<nk; k++)
00154       out_buf[i][j][k]=temp[k];
00155   }
00156 }