core/vil/algo/vil_correlate_1d.h
Go to the documentation of this file.
00001 // This is core/vil/algo/vil_correlate_1d.h
00002 #ifndef vil_correlate_1d_h_
00003 #define vil_correlate_1d_h_
00004 //:
00005 // \file
00006 // \brief 1D Convolution with cunning boundary options
00007 // \author Tim Cootes (based on work by fsm)
00008 
00009 #include <vcl_algorithm.h>
00010 #include <vcl_cstring.h>
00011 #include <vcl_cassert.h>
00012 #include <vcl_iostream.h>
00013 #include <vil/vil_image_view.h>
00014 #include <vil/vil_image_resource.h>
00015 #include <vil/vil_property.h>
00016 #include <vil/algo/vil_convolve_1d.h>
00017 
00018 //: Correlate kernel[x] (x in [k_lo,k_hi]) with srcT
00019 // Assumes dest and src same size (nx)
00020 template <class srcT, class destT, class kernelT, class accumT>
00021 inline void vil_correlate_1d(const srcT* src0, unsigned nx, vcl_ptrdiff_t s_step,
00022                              destT* dest0, vcl_ptrdiff_t d_step,
00023                              const kernelT* kernel,
00024                              vcl_ptrdiff_t k_lo, vcl_ptrdiff_t k_hi,
00025                              accumT ac,
00026                              vil_convolve_boundary_option start_option,
00027                              vil_convolve_boundary_option end_option)
00028 {
00029   // Deal with start (fill elements 0..1-k_lo of dest)
00030   vil_convolve_edge_1d(src0,nx,s_step,dest0,d_step,kernel,-k_hi,-k_lo,-1,ac,start_option);
00031 
00032   const kernelT* k_begin = kernel+k_lo;
00033   const kernelT* k_end   = kernel+k_hi+1;
00034   const srcT* src = src0;
00035 
00036   destT* end_dest = dest0 + d_step*(int(nx)-k_hi);
00037   for (destT* dest = dest0-d_step*k_lo;dest!=end_dest;dest+=d_step,src+=s_step)
00038   {
00039     accumT sum = 0;
00040     const srcT* s= src;
00041     for (const kernelT *k = k_begin;k!=k_end; ++k,s+=s_step) sum+= (accumT)((*k)*(*s));
00042     *dest = destT(sum);
00043   }
00044 
00045   // Deal with end  (reflect data and kernel!)
00046   vil_convolve_edge_1d(src0+(nx-1)*s_step,nx,-s_step,
00047                        dest0+(nx-1)*d_step,-d_step,
00048                        kernel,k_lo,k_hi,1,ac,end_option);
00049 }
00050 
00051 //: correlate kernel[i] (i in [k_lo,k_hi]) with srcT in i-direction
00052 // On exit dest_im(i,j) = sum src(i+x,j)*kernel(x)  (x=k_lo..k_hi)
00053 // \note  This function does not reverse the kernel. If you want the
00054 // kernel reversed, use vil_convolve_1d instead.
00055 // \param kernel should point to tap 0.
00056 // \param dest_im will be resized to size of src_im.
00057 // \relatesalso vil_image_view
00058 template <class srcT, class destT, class kernelT, class accumT>
00059 inline void vil_correlate_1d(const vil_image_view<srcT>& src_im,
00060                              vil_image_view<destT>& dest_im,
00061                              const kernelT* kernel,
00062                              vcl_ptrdiff_t k_lo, vcl_ptrdiff_t k_hi,
00063                              accumT ac,
00064                              vil_convolve_boundary_option start_option,
00065                              vil_convolve_boundary_option end_option)
00066 {
00067   unsigned ni = src_im.ni();
00068   unsigned nj = src_im.nj();
00069   vcl_ptrdiff_t s_istep = src_im.istep(), s_jstep = src_im.jstep();
00070 
00071   dest_im.set_size(ni,nj,src_im.nplanes());
00072   vcl_ptrdiff_t d_istep = dest_im.istep(),d_jstep = dest_im.jstep();
00073 
00074   for (unsigned int p=0;p<src_im.nplanes();++p)
00075   {
00076     // Select first row of p-th plane
00077     const srcT*  src_row  = src_im.top_left_ptr()+p*src_im.planestep();
00078     destT* dest_row = dest_im.top_left_ptr()+p*dest_im.planestep();
00079 
00080     // Apply convolution to each row in turn
00081     // First check if either istep is 1 for speed optimisation.
00082     if (s_istep == 1)
00083     {
00084       if (d_istep == 1)
00085         for (unsigned int j=0;j<nj;++j,src_row+=s_jstep,dest_row+=d_jstep)
00086           vil_correlate_1d(src_row,ni,1,  dest_row,1,
00087                            kernel,k_lo,k_hi,ac,start_option,end_option);
00088       else
00089         for (unsigned int j=0;j<nj;++j,src_row+=s_jstep,dest_row+=d_jstep)
00090           vil_correlate_1d(src_row,ni,1,  dest_row,d_istep,
00091                            kernel,k_lo,k_hi,ac,start_option,end_option);
00092     }
00093     else
00094     {
00095       if (d_istep == 1)
00096         for (unsigned int j=0;j<nj;++j,src_row+=s_jstep,dest_row+=d_jstep)
00097           vil_correlate_1d(src_row,ni,s_istep,  dest_row,1,
00098                            kernel,k_lo,k_hi,ac,start_option,end_option);
00099       else
00100         for (unsigned int j=0;j<nj;++j,src_row+=s_jstep,dest_row+=d_jstep)
00101           vil_correlate_1d(src_row,ni,s_istep,  dest_row,d_istep,
00102                            kernel,k_lo,k_hi,ac,start_option,end_option);
00103     }
00104   }
00105 }
00106 
00107 template <class destT, class kernelT, class accumT>
00108 vil_image_resource_sptr vil_correlate_1d(
00109                const vil_image_resource_sptr& src_im,
00110                const destT dt,
00111                const kernelT* kernel, vcl_ptrdiff_t k_lo, vcl_ptrdiff_t k_hi,
00112                const accumT ac,
00113                vil_convolve_boundary_option start_option,
00114                vil_convolve_boundary_option end_option);
00115 
00116 //: A resource adaptor that behaves like a correlated version of its input
00117 template <class kernelT, class accumT, class destT>
00118 class vil_correlate_1d_resource : public vil_image_resource
00119 {
00120   //: Construct a correlate filter.
00121   // You can't create one of these directly, use vil_correlate_1d instead
00122   vil_correlate_1d_resource(const vil_image_resource_sptr& src,
00123                             const kernelT* kernel, vcl_ptrdiff_t k_lo, vcl_ptrdiff_t k_hi,
00124                             vil_convolve_boundary_option start_option,
00125                             vil_convolve_boundary_option end_option)  :
00126       src_(src), kernel_(kernel), klo_(k_lo), khi_(k_hi),
00127       start_option_(start_option), end_option_(end_option)
00128     {
00129       // Can't do period extension yet.
00130       assert (start_option != vil_convolve_periodic_extend ||
00131               end_option != vil_convolve_periodic_extend);
00132     }
00133 
00134   friend vil_image_resource_sptr vil_correlate_1d VCL_NULL_TMPL_ARGS (
00135     const vil_image_resource_sptr& src_im, const destT dt, const kernelT* kernel,
00136     vcl_ptrdiff_t k_lo, vcl_ptrdiff_t k_hi, const accumT ac,
00137     vil_convolve_boundary_option start_option,
00138     vil_convolve_boundary_option end_option);
00139 
00140  public:
00141   virtual vil_image_view_base_sptr get_copy_view(unsigned i0, unsigned ni,
00142                                                  unsigned j0, unsigned nj) const
00143   {
00144     if (i0 + ni > src_->ni() || j0 + nj > src_->nj())  return 0;
00145     const unsigned lsrc = (unsigned)vcl_max(0,int(i0+klo_)); // lhs of input window
00146     const unsigned hsrc = vcl_min(src_->ni(),(unsigned int)(i0+ni-klo_+khi_)); // 1+rhs of input window.
00147     const unsigned lboundary = vcl_min((unsigned) -klo_, i0); // width of lhs boundary area.
00148     assert (hsrc > lsrc);
00149     vil_image_view_base_sptr vs = src_->get_view(lsrc, hsrc-lsrc, j0, nj);
00150     vil_image_view<destT> dest(vs->ni(), vs->nj(), vs->nplanes());
00151     switch (vs->pixel_format())
00152     {
00153 #define macro( F , T ) \
00154       case F : \
00155         vil_correlate_1d(static_cast<vil_image_view<T >&>(*vs),dest, \
00156                          kernel_, klo_, khi_, accumT(), start_option_, end_option_); \
00157         return new vil_image_view<destT>(vil_crop(dest, lboundary, ni, 0, nj));
00158 
00159       macro(VIL_PIXEL_FORMAT_BYTE , vxl_byte )
00160       macro(VIL_PIXEL_FORMAT_SBYTE , vxl_sbyte )
00161       macro(VIL_PIXEL_FORMAT_UINT_32 , vxl_uint_32 )
00162       macro(VIL_PIXEL_FORMAT_UINT_16 , vxl_uint_16 )
00163       macro(VIL_PIXEL_FORMAT_INT_32 , vxl_int_32 )
00164       macro(VIL_PIXEL_FORMAT_INT_16 , vxl_int_16 )
00165       macro(VIL_PIXEL_FORMAT_BOOL , bool )
00166       macro(VIL_PIXEL_FORMAT_FLOAT , float )
00167       macro(VIL_PIXEL_FORMAT_DOUBLE , double )
00168 // complex<float> should work - but causes all manner of compiler template errors.
00169 // maybe need a better compiler, maybe there is a code fix - IMS
00170 #undef macro
00171       default:
00172         return 0;
00173     }
00174   }
00175 
00176   virtual unsigned nplanes() const { return src_->nplanes(); }
00177   virtual unsigned ni() const { return src_->ni(); }
00178   virtual unsigned nj() const { return src_->nj(); }
00179 
00180   virtual enum vil_pixel_format pixel_format() const
00181   { return vil_pixel_format_of(accumT()); }
00182 
00183 
00184   //: Put the data in this view back into the image source.
00185   virtual bool put_view(const vil_image_view_base&  /*im*/, unsigned  /*i0*/, unsigned  /*j0*/)
00186   {
00187     vcl_cerr << "WARNING: vil_correlate_1d_resource::put_back\n"
00188              << "\tYou can't push data back into a correlate filter.\n";
00189     return false;
00190   }
00191 
00192   //: Extra property information
00193   virtual bool get_property(char const* tag, void* property_value = 0) const
00194   {
00195     if (0==vcl_strcmp(tag, vil_property_read_only))
00196       return property_value ? (*static_cast<bool*>(property_value)) = true : true;
00197 
00198     return src_->get_property(tag, property_value);
00199   }
00200 
00201  protected:
00202   vil_image_resource_sptr src_;
00203   const kernelT* kernel_;
00204   vcl_ptrdiff_t klo_, khi_;
00205   vil_convolve_boundary_option start_option_, end_option_;
00206 };
00207 
00208 //: Create an image_resource object which correlate kernel[x] x in [k_lo,k_hi] with srcT
00209 // \note  This function does not reverse the kernel. If you want the
00210 // kernel reversed, use vil_convolve_1d instead.
00211 // \param kernel should point to tap 0.
00212 // \relatesalso vil_image_resource
00213 template <class destT, class kernelT, class accumT>
00214 vil_image_resource_sptr vil_correlate_1d(
00215                          const vil_image_resource_sptr& src_im,
00216                          const destT  /*dt*/,
00217                          const kernelT* kernel, vcl_ptrdiff_t k_lo, vcl_ptrdiff_t k_hi,
00218                          const accumT,
00219                          vil_convolve_boundary_option start_option,
00220                          vil_convolve_boundary_option end_option)
00221 {
00222   return new vil_correlate_1d_resource<kernelT, accumT, destT>(src_im, kernel, k_lo, k_hi, start_option, end_option);
00223 }
00224 
00225 #endif // vil_correlate_1d_h_