core/vil/algo/vil_gauss_filter.h
Go to the documentation of this file.
00001 // This is core/vil/algo/vil_gauss_filter.h
00002 #ifndef vil_gauss_filter_h_
00003 #define vil_gauss_filter_h_
00004 //:
00005 // \file
00006 // \brief Smooths images.
00007 // \author Ian Scott
00008 
00009 #include <vcl_vector.h>
00010 #include <vil/vil_image_view.h>
00011 #include <vil/algo/vil_convolve_1d.h>
00012 #include <vil/vil_transpose.h>
00013 
00014 class vil_gauss_filter_5tap_params
00015 {
00016   double sigma_;
00017   double filt2_, filt1_, filt0_;
00018   double filt_edge2_, filt_edge1_, filt_edge0_;
00019   double filt_pen_edge2_, filt_pen_edge1_,
00020          filt_pen_edge0_, filt_pen_edge_n1_;
00021  public:
00022   //: Set the
00023   explicit vil_gauss_filter_5tap_params(double sigma_);
00024   //: The width of the Gaussian
00025   double sigma() const {return sigma_;}
00026 
00027   //: Filter tap value
00028   // The value of the two outside elements of the 5-tap 1D FIR filter
00029   double filt2() const { return filt2_;}
00030   //: Filter tap value
00031   // The value of elements 2 and 4 of the 5-tap 1D FIR filter
00032   double filt1() const { return filt1_;}
00033   //: Filter tap value
00034   // The value of the central element of the 5-tap 1D FIR filter
00035   double filt0() const { return filt0_;}
00036 
00037   //: Filter tap value
00038   // The value of the first element of the 3 tap 1D FIR filter for use at the edge of the window
00039   // Corresponds to the filt2_ elements in a symmetrical filter
00040   double filt_edge2() const { return filt_edge2_;}
00041   //: Filter tap value
00042   // The value of the second element of the 3 tap 1D FIR filter for use at the edge of the window
00043   // Corresponds to the filt1_ elements in a symmetrical filter
00044   double filt_edge1() const { return filt_edge1_;}
00045   //: Filter tap value
00046   // The value of the third element of the 3 tap 1D FIR filter for use at the edge of the window
00047   // Corresponds to the filt0_ element in a symmetrical filter
00048   double filt_edge0() const { return filt_edge0_;}
00049 
00050   //: Filter tap value
00051   // The value of the first element of the 4 tap 1D FIR filter for use 1 pixel away the edge of the window
00052   // Corresponds to the filt2_ elements in a symmetrical filter
00053   double filt_pen_edge2() const { return filt_pen_edge2_;}
00054   //: Filter tap value
00055   // The value of the second element of the 4 tap 1D FIR filter for use 1 pixel away the edge of the window
00056   // Corresponds to the filt1_ elements in a symmetrical filter
00057   double filt_pen_edge1() const { return filt_pen_edge1_;}
00058   //: Filter tap value
00059   // The value of the third element of the 4 tap 1D FIR filter for use 1 pixel away the edge of the window
00060   // Corresponds to the filt0_ elements in a symmetrical filter
00061   double filt_pen_edge0() const { return filt_pen_edge0_;}
00062   //: Filter tap value
00063   // The value of the fourth element of the 4 tap 1D FIR filter for use 1 pixel away the edge of the window
00064   // Corresponds to the filt1_ elements in a symmetrical filter
00065   double filt_pen_edge_n1() const { return filt_pen_edge_n1_;}
00066 };
00067 
00068 
00069 //: Smooth a single plane src_im to produce dest_im
00070 //  Applies 5 element FIR filter in x and y.
00071 //  Assumes dest_im has sufficient data allocated.
00072 template <class srcT, class destT>
00073 void vil_gauss_filter_5tap(const srcT* src_im, vcl_ptrdiff_t src_ystep,
00074                            unsigned ni, unsigned nj,
00075                            destT* dest_im, vcl_ptrdiff_t dest_ystep,
00076                            const vil_gauss_filter_5tap_params& params,
00077                            destT* work);
00078 
00079 //: Smooth a src_im to produce dest_im
00080 //  Applies 5 element FIR filter in x and y.
00081 template <class srcT, class destT>
00082 void vil_gauss_filter_5tap(const vil_image_view<srcT>& src_im,
00083                            vil_image_view<destT>& dest_im,
00084                            const vil_gauss_filter_5tap_params &params,
00085                            vil_image_view<destT> &work);
00086 
00087 
00088 //: Smooth a src_im to produce dest_im
00089 //  Applies 5 element FIR filter in x and y.
00090 template <class srcT, class destT>
00091 inline void vil_gauss_filter_5tap(const vil_image_view<srcT>& src_im,
00092                                   vil_image_view<destT>& dest_im,
00093                                   const vil_gauss_filter_5tap_params &params)
00094 {
00095   vil_image_view<destT> work;
00096   vil_gauss_filter_5tap(src_im, dest_im, params, work);
00097 }
00098 
00099 
00100 //: Generate an n-tap FIR filter from a Gaussian function.
00101 // The filter uses the equation $k D^d \exp -\frac{x^2}{2\sigma^2} $,
00102 // where D is the differential operator, and k is a normalising constant.
00103 // \param diff The number of differential operators to apply to the filter.
00104 // If you want just a normal gaussian, set diff to 0.
00105 // \param sd The width of the gaussian.
00106 //
00107 // The taps will be calculated using the integral of the above equation over
00108 // the pixel width. However, aliasing will reduce the meaningfulness of
00109 // your filter when sd << (diff+1). In most applications you will
00110 // want filter.size() ~= sd*7, which will avoid significant truncation,
00111 // without wasting the outer taps on near-zero values.
00112 void vil_gauss_filter_gen_ntap(double sd, unsigned diff,
00113                                vcl_vector<double> &filter_dest);
00114 
00115 //: Smooth a src_im to produce dest_im with gaussian of width sd
00116 //  Generates gaussian filter of width sd, using (2*half_width+1)
00117 //  values in the filter.  Typically half_width>3sd.
00118 //  Convolves this with src_im to generate dest_im.
00119 template <class srcT, class destT>
00120 inline void vil_gauss_filter_1d(const vil_image_view<srcT>& src_im,
00121                                 vil_image_view<destT>& dest_im,
00122                                 double sd, unsigned half_width)
00123 {
00124   vcl_vector<double> filter(2*half_width+1);
00125   vil_gauss_filter_gen_ntap(sd,0,filter);
00126   vil_convolve_1d(src_im,dest_im,&filter[half_width],-int(half_width),half_width,
00127                   float(),vil_convolve_zero_extend,vil_convolve_zero_extend);
00128 }
00129 
00130 //: Smooth a src_im to produce dest_im with gaussian of width sd
00131 //  Generates gaussian filter of width sd, using (2*half_width+1)
00132 //  values in the filter.  Typically half_width>3sd.
00133 //  Convolves this with src_im to generate work_im, then applies filter
00134 //  vertically to generate dest_im.
00135 template <class srcT, class destT>
00136 inline void vil_gauss_filter_2d(const vil_image_view<srcT>& src_im,
00137                                 vil_image_view<destT>& dest_im,
00138                                 double sd, unsigned half_width,
00139                                 vil_convolve_boundary_option boundary = vil_convolve_zero_extend)
00140 {
00141   // Generate filter
00142   vcl_vector<double> filter(2*half_width+1);
00143   vil_gauss_filter_gen_ntap(sd,0,filter);
00144 
00145   // Apply 1D convolution along i direction
00146   vil_image_view<destT> work_im;
00147   vil_convolve_1d(src_im,work_im,&filter[half_width],-int(half_width),half_width,
00148                   float(), boundary, boundary);
00149 
00150   // Apply 1D convolution along j direction by applying filter to transpose
00151   dest_im.set_size(src_im.ni(),src_im.nj(),src_im.nplanes());
00152   vil_image_view<destT> work_im_t = vil_transpose(work_im);
00153   vil_image_view<destT> dest_im_t = vil_transpose(dest_im);
00154 
00155   vil_convolve_1d(work_im_t,dest_im_t,
00156                   &filter[half_width],-int(half_width),half_width,
00157                   float(), boundary, boundary);
00158 }
00159 
00160 
00161 //: Smooth a src_im to produce dest_im with gaussian of width sd
00162 //  Generates two gaussian filters of width sd_i,sd_j, using (2*half_width_i+1)
00163 //  values in the filter.  Typically half_width>3sd.
00164 //  Convolves this with src_im to generate work_im, then applies filter
00165 //  vertically to generate dest_im.
00166 template <class srcT, class destT>
00167 inline void vil_gauss_filter_2d(const vil_image_view<srcT>& src_im,
00168                                 vil_image_view<destT>& dest_im,
00169                                 double sd_i, unsigned half_width_i,
00170                                 double sd_j, unsigned half_width_j,
00171                                 vil_convolve_boundary_option boundary = vil_convolve_zero_extend)
00172 {
00173   // Generate filter for i
00174   vcl_vector<double> filter_i(2*half_width_i+1);
00175   vil_gauss_filter_gen_ntap(sd_i,0,filter_i);
00176 
00177   // Apply 1D convolution along i direction
00178   vil_image_view<destT> work_im;
00179   vil_convolve_1d(src_im,work_im,&filter_i[half_width_i],-int(half_width_i),half_width_i,
00180                   float(), boundary, boundary);
00181 
00182   // Apply 1D convolution along j direction by applying filter to transpose
00183   dest_im.set_size(src_im.ni(),src_im.nj(),src_im.nplanes());
00184   vil_image_view<destT> work_im_t = vil_transpose(work_im);
00185   vil_image_view<destT> dest_im_t = vil_transpose(dest_im);
00186 
00187   // Generate filter for j
00188   vcl_vector<double> filter_j(2*half_width_j+1);
00189   vil_gauss_filter_gen_ntap(sd_j,0,filter_j);
00190 
00191   vil_convolve_1d(work_im_t,dest_im_t,
00192                   &filter_j[half_width_j],-int(half_width_j),half_width_j,
00193                   float(), boundary, boundary);
00194 }
00195 
00196 
00197 #endif // vil_gauss_filter_h_