contrib/tbl/vipl/vipl_gaussian_convolution.txx
Go to the documentation of this file.
00001 #ifndef vipl_gaussian_convolution_txx_
00002 #define vipl_gaussian_convolution_txx_
00003 
00004 #include "vipl_gaussian_convolution.h"
00005 #include <vcl_cmath.h> // for vcl_sqrt(), vcl_exp(), vcl_log()
00006 
00007 template <class ImgIn,class ImgOut,class DataIn,class DataOut,class PixelItr>
00008 bool vipl_gaussian_convolution <ImgIn,ImgOut,DataIn,DataOut,PixelItr> :: section_applyop()
00009 {
00010   const ImgIn &in = this->in_data(0);
00011   ImgOut &out = *this->out_data_ptr();
00012   int size = masksize();
00013 
00014   // Make temporary buffer to hold result of first (horizontal) convolution
00015   int width  = vipl_filter<ImgIn,ImgOut,DataIn,DataOut,2,PixelItr>::stop(this->X_Axis())
00016              - vipl_filter<ImgIn,ImgOut,DataIn,DataOut,2,PixelItr>::start(this->X_Axis());
00017   int height = vipl_filter<ImgIn,ImgOut,DataIn,DataOut,2,PixelItr>::stop(this->Y_Axis())
00018              - vipl_filter<ImgIn,ImgOut,DataIn,DataOut,2,PixelItr>::start(this->Y_Axis());
00019   double* buf = new double[width*height];
00020   if (!buf) return false; // memory allocation failed
00021 
00022   // 1-D mask was generated in preop(), we just use it here:
00023 
00024   // horizontal convolution:
00025   int starty = vipl_filter<ImgIn,ImgOut,DataIn,DataOut,2,PixelItr>::start(this->Y_Axis());
00026   int stopy = vipl_filter<ImgIn,ImgOut,DataIn,DataOut,2,PixelItr>::stop(this->Y_Axis());
00027   for (int j = starty; j < stopy; ++j)
00028   {
00029     int buf_j = j - starty;
00030     int startx = vipl_filter<ImgIn,ImgOut,DataIn,DataOut,2,PixelItr>::start(this->X_Axis(),j);
00031     int stopx = vipl_filter<ImgIn,ImgOut,DataIn,DataOut,2,PixelItr>::stop(this->X_Axis(),j);
00032     for (int i = startx; i < stopx; ++i) {
00033       int buf_i = i - startx;
00034       double result = mask()[0] * fgetpixel(in, i, j, DataIn(0));
00035       for (int x=1; x<size; ++x)
00036         result += mask()[x] * (getpixel(in, i+x, j, DataIn(0)) + getpixel(in, i-x, j, DataIn(0)));
00037       buf[buf_i+width*buf_j] = result;
00038     }
00039   }
00040   // vertical convolution:
00041   for (int j = starty; j < stopy; ++j)
00042   {
00043     int buf_j = j - starty;
00044     int startx = vipl_filter<ImgIn,ImgOut,DataIn,DataOut,2,PixelItr>::start(this->X_Axis(),j);
00045     int stopx = vipl_filter<ImgIn,ImgOut,DataIn,DataOut,2,PixelItr>::stop(this->X_Axis(),j);
00046     for (int i = startx; i < stopx; ++i) {
00047       int buf_i = i - startx;
00048       double result = mask()[0] * buf[buf_i+width*buf_j];
00049       for (int y=1; y<size; ++y) {
00050         if (buf_j+y < height) result += mask()[y] * buf[buf_i+width*(buf_j+y)];
00051         if (buf_j >= y) result += mask()[y] * buf[buf_i+width*(buf_j-y)];
00052       }
00053       fsetpixel(out, i, j, DataOut(result));
00054     }
00055   }
00056   delete[] buf;
00057   return true;
00058 }
00059 
00060 // it is important that the mask be computed in preop, if it was done in
00061 // section_applyop then on a large image it would be computed many times.
00062 template <class ImgIn,class ImgOut,class DataIn,class DataOut,class PixelItr>
00063 bool vipl_gaussian_convolution <ImgIn,ImgOut,DataIn,DataOut,PixelItr> :: preop()
00064 {
00065   // create 1-D mask:
00066   double lc = -2 * vcl_log(cutoff()); // cutoff guaranteed > 0
00067   int radius = (lc<=0) ? 0 : 1 + int(vcl_sqrt(lc)*sigma()); // sigma guaranteed >= 0
00068   int size = radius + 1; // only need half mask, because it is symmetric
00069   ref_masksize() = size;
00070   delete[] ref_mask(); ref_mask() = new double[size];
00071   double s = -0.5/sigma()/sigma();
00072   double halfnorm = vcl_exp(0.25*s) + 1.0;
00073   for (int y=1; y<8; ++y) halfnorm += 2*vcl_exp(y*y*0.0625*0.0625*s);
00074   ref_mask()[0] = 2*halfnorm;
00075   for (int x=1; x<size; ++x)
00076   { // trapezoid approximation (16 pieces) of integral between x-0.5 and x+0.5
00077     ref_mask()[x] = vcl_exp((x-0.5)*(x-0.5)*s) + vcl_exp((x+0.5)*(x+0.5)*s);
00078     for (int y=-7; y<8; ++y) ref_mask()[x] += 2*vcl_exp((x+y*0.0625)*(x+y*0.0625)*s);
00079     halfnorm += mask()[x];
00080   }
00081   for (int x=0; x<size; ++x) ref_mask()[x] /= 2*halfnorm; // normalise mask
00082   return true;
00083 }
00084 
00085 // We destroy the mask in postop, after we are all done filtering
00086 template <class ImgIn,class ImgOut,class DataIn,class DataOut,class PixelItr>
00087 bool vipl_gaussian_convolution <ImgIn,ImgOut,DataIn,DataOut,PixelItr> :: postop()
00088 {
00089   delete[] ref_mask(); ref_mask()=0;
00090   return true;
00091 }
00092 
00093 #endif // vipl_gaussian_convolution_txx_