TuttleOFX  1
convolve.hpp
Go to the documentation of this file.
00001 #ifndef _TERRY_FILTER_CONVOLVE_HPP_
00002 #define _TERRY_FILTER_CONVOLVE_HPP_
00003 
00004 #include "correlate.hpp"
00005 #include "detail/kernel.hpp"
00006 
00007 #include <terry/numeric/scalar.hpp>
00008 #include <terry/numeric/init.hpp>
00009 #include <terry/numeric/assign.hpp>
00010 
00011 #include <boost/gil/gil_config.hpp>
00012 #include <boost/gil/image_view_factory.hpp>
00013 #include <boost/gil/algorithm.hpp>
00014 #include <boost/gil/metafunctions.hpp>
00015 #include <boost/numeric/conversion/cast.hpp>
00016 #include <boost/mpl/bool.hpp>
00017 
00018 #include <cstddef>
00019 #include <cassert>
00020 #include <algorithm>
00021 #include <vector>
00022 #include <functional>
00023 
00024 
00025 namespace terry {
00026 using namespace boost::gil;
00027 
00028 namespace filter {
00029 
00030 /// @ingroup ImageAlgorithms
00031 /// Boundary options for 1D correlations/convolutions
00032 enum convolve_boundary_option  {
00033     convolve_option_output_ignore,   /// do nothing to the output
00034     convolve_option_output_zero,     /// set the output to zero
00035     convolve_option_extend_padded,   /// assume the source boundaries to be padded already
00036     convolve_option_extend_zero,     /// assume the source boundaries to be zero
00037     convolve_option_extend_constant, /// assume the source boundaries to be the boundary value
00038     convolve_option_extend_mirror    /// assume the source boundaries to be the mirror of source
00039 };
00040 
00041 namespace detail {
00042 
00043 /// @ingroup PointModel
00044 template <typename T> GIL_FORCEINLINE
00045 bool operator>=(const point2<T>& p1, const point2<T>& p2) { return (p1.x>=p2.x && p1.y>=p2.y); }
00046 /// @ingroup PointModel
00047 template <typename T> GIL_FORCEINLINE
00048 bool operator<=(const point2<T>& p1, const point2<T>& p2) { return (p1.x<=p2.x && p1.y<=p2.y); }
00049 /// @ingroup PointModel
00050 template <typename T, typename T2> GIL_FORCEINLINE
00051 bool operator>=(const point2<T>& p, const T2 v) { return (p.x>=v && p.y>=v); }
00052 /// @ingroup PointModel
00053 template <typename T, typename T2> GIL_FORCEINLINE
00054 bool operator<=(const point2<T>& p, const T2 v) { return (p.x<=v && p.y<=v); }
00055 
00056 /// compute the correlation of 1D kernel with the rows of an image
00057 /// @param src source view
00058 /// @param dst destination view
00059 /// @param ker dynamic size kernel
00060 /// @param dst_tl topleft point of dst in src coordinates. Must be Point(0,0) if src.dimensions()==dst.dimensions().
00061 ///        We can see it as a vector to move dst in src coordinates.
00062 /// @param option boundary option
00063 /// @param correlator correlator functor
00064 template <typename PixelAccum,typename SrcView,typename Kernel,typename DstView,typename Correlator>
00065 void correlate_rows_imp( const SrcView& src, const Kernel& ker, const DstView& dst, const typename SrcView::point_t& dst_tl,
00066                          const convolve_boundary_option option,
00067                          Correlator correlator )
00068 {
00069         using namespace terry::numeric;
00070 
00071         // dst must be contained in src
00072     assert( dst_tl <= src.dimensions() );
00073     assert( ker.size() != 0 );
00074 
00075         typedef typename SrcView::point_t point_t;
00076         typedef typename point_t::value_type coord_t;
00077     typedef typename pixel_proxy<typename SrcView::value_type>::type PIXEL_SRC_REF;
00078     typedef typename pixel_proxy<typename DstView::value_type>::type PIXEL_DST_REF;
00079     typedef typename Kernel::value_type kernel_type;
00080 
00081     if( ker.size() == 1 )
00082         {
00083                 // reduces to a multiplication
00084                 view_multiplies_scalar<PixelAccum>(
00085                                 subimage_view(src, dst_tl, dst.dimensions()),
00086                                 *ker.begin(),
00087                                 dst
00088                         );
00089         return;
00090     }
00091 
00092     if( dst.dimensions().x == 0 || dst.dimensions().y == 0 )
00093                 return;
00094         
00095         //  ................................................................
00096         //  .                     src with kernel size adds                .
00097         //  .                                                              .
00098         //  .          _________________________________________           .
00099         //  .          |             src and dst               |           .
00100         //  .          |          ____________                 |           .
00101         // <. left_out | left_in |            | right_in       | right_out .>
00102         //  .          |         |    roi     |                |           .
00103         //  .          |         |            |                |           .
00104         //  .          |         |____________|                |           .
00105         //  .          |_______________________________________|           .
00106         //  .                                                              .
00107         //  ................................................................
00108         // < > : represents the temporary buffer
00109         const point_t dst_br  = dst_tl + dst.dimensions();
00110         const coord_t left_in   = std::min(boost::numeric_cast<coord_t>(ker.left_size()), dst_tl.x);
00111         const coord_t left_out  = std::max(boost::numeric_cast<coord_t>(ker.left_size()) - dst_tl.x, (coord_t)0);
00112         const coord_t right_tmp = src.dimensions().x - dst_br.x;
00113         const coord_t right_in  = std::min(boost::numeric_cast<coord_t>(ker.right_size()), right_tmp);
00114         const coord_t right_out = std::max(boost::numeric_cast<coord_t>(ker.right_size()) - right_tmp, (coord_t)0);
00115 
00116         const coord_t srcRoi_left = dst_tl.x - left_in;
00117         const coord_t srcRoi_right = dst_br.x + right_in;
00118         const coord_t srcRoi_width = dst.dimensions().x + left_in + right_in;
00119 
00120     PixelAccum acc_zero; pixel_zeros_t<PixelAccum>()(acc_zero);
00121 
00122         if( option == convolve_option_output_ignore || option == convolve_option_output_zero )
00123         {
00124         typename DstView::value_type dst_zero; pixel_assigns_t<PixelAccum,PIXEL_DST_REF>()(acc_zero,dst_zero);
00125         if( dst.dimensions().x < static_cast<coord_t>(ker.size()) )
00126                 {
00127             if( option == convolve_option_output_zero )
00128                 fill_pixels( dst, dst_zero );
00129         }
00130                 else
00131                 {
00132                         std::vector<PixelAccum> buffer(srcRoi_width);
00133             for( coord_t yy = 0; yy < dst.dimensions().y; ++yy )
00134                         {
00135                                 coord_t yy_src = yy + dst_tl.y;
00136                 assign_pixels( src.x_at(srcRoi_left,yy_src),
00137                                                src.x_at(srcRoi_right,yy_src),
00138                                                            &buffer.front() );
00139 
00140                 typename DstView::x_iterator it_dst=dst.row_begin(yy);
00141                 if (option==convolve_option_output_zero)
00142                     std::fill_n(it_dst,left_out,dst_zero);
00143                                 it_dst += left_out;
00144 
00145                                 const int buffer_dst_size = dst.dimensions().x - left_out-right_out;
00146                                 correlator( &buffer.front(), &buffer.front() + buffer_dst_size, // why not always use begin(), does front() have a performance impact ?
00147                             ker.begin(), it_dst );
00148                 it_dst += buffer_dst_size;
00149 
00150                 if( option == convolve_option_output_zero )
00151                     std::fill_n( it_dst, right_out, dst_zero );
00152             }
00153         }
00154     }
00155         else
00156         {
00157         std::vector<PixelAccum> buffer( dst.dimensions().x + (ker.size() - 1) );
00158         for( int yy=0; yy<dst.dimensions().y; ++yy )
00159                 {
00160                         coord_t yy_src = yy + dst_tl.y;
00161                         // fill buffer from src view depending on boundary option
00162             switch( option )
00163                         {
00164                                 case convolve_option_extend_padded:
00165                                 {
00166                                         assign_pixels( src.x_at(dst_tl.x-ker.left_size(),yy_src),
00167                                                                    src.x_at(dst_br.x+ker.right_size(),yy_src),
00168                                                                    &buffer.front() );
00169                                         break;
00170                                 }
00171                                 case convolve_option_extend_zero:
00172                                 {
00173                                         PixelAccum* it_buffer=&buffer.front();
00174                                         std::fill_n(it_buffer,left_out,acc_zero);
00175                                         it_buffer += left_out;
00176                                         
00177                                         it_buffer = assign_pixels(src.x_at(srcRoi_left,yy_src),src.x_at(srcRoi_right,yy_src),it_buffer);
00178 
00179                                         std::fill_n(it_buffer,right_out,acc_zero);
00180                                         break;
00181                                 }
00182                                 case convolve_option_extend_constant:
00183                                 {
00184                                         PixelAccum* it_buffer=&buffer.front();
00185                                         PixelAccum filler;
00186                                         pixel_assigns_t<PIXEL_SRC_REF,PixelAccum>()(*src.x_at(srcRoi_left,yy_src),filler);
00187                                         std::fill_n(it_buffer,left_out,filler);
00188                                         it_buffer += left_out;
00189 
00190                                         it_buffer = assign_pixels(src.x_at(srcRoi_left,yy_src),src.x_at(srcRoi_right,yy_src),it_buffer);
00191 
00192                                         pixel_assigns_t<PIXEL_SRC_REF,PixelAccum>()(*src.x_at(srcRoi_right-1,yy_src),filler);
00193                                         std::fill_n(it_buffer,right_out,filler);
00194                                         break;
00195                                 }
00196                                 case convolve_option_extend_mirror:
00197                                 {
00198                                         PixelAccum* it_buffer = &buffer.front();
00199                                         typedef typename SrcView::reverse_iterator reverse_iterator;
00200                                         const unsigned int nleft = boost::numeric_cast<unsigned int>(left_out / srcRoi_width);
00201                                         coord_t copy_size = buffer.size();
00202                                         const coord_t left_rest = left_out % srcRoi_width;
00203                                         bool reverse;
00204                                         if( nleft % 2 ) // odd
00205                                         {
00206                                                 assign_pixels( src.at(srcRoi_right-1-left_rest,yy_src),
00207                                                                            src.at(srcRoi_right-1,yy_src),
00208                                                                            it_buffer );
00209                                                 reverse = true; // next step reversed
00210                                         }
00211                                         else
00212                                         {
00213                                                 assign_pixels( reverse_iterator(src.at(srcRoi_left+left_rest,yy_src)),
00214                                                                            reverse_iterator(src.at(srcRoi_left,yy_src)),
00215                                                                            it_buffer );
00216                                                 reverse = false; // next step not reversed
00217                                         }
00218                                         it_buffer += left_rest;
00219                                         copy_size -= left_rest;
00220                                         while( copy_size )
00221                                         {
00222                                                 coord_t tmp_size;
00223                                                 if( copy_size > srcRoi_width ) // if kernel left size > src width... (extrem case)
00224                                                         tmp_size = srcRoi_width;
00225                                                 else // standard case
00226                                                         tmp_size = copy_size;
00227                                                 
00228                                                 if( reverse )
00229                                                 {
00230                                                         assign_pixels( reverse_iterator(src.at(srcRoi_right,yy_src)),
00231                                                                                    reverse_iterator(src.at(srcRoi_right-tmp_size,yy_src)),
00232                                                                                    it_buffer );
00233                                                 }
00234                                                 else
00235                                                 {
00236                                                         assign_pixels( src.at(srcRoi_left,yy_src),
00237                                                                                    src.at(srcRoi_left+tmp_size,yy_src),
00238                                                                                    it_buffer );
00239                                                 }
00240                                                 it_buffer += tmp_size;
00241                                                 copy_size -= tmp_size;
00242                                                 reverse = !reverse;
00243                                         }
00244                                         break;
00245                                 }
00246                                 case convolve_option_output_ignore:
00247                                 case convolve_option_output_zero:
00248                                         assert(false);
00249             }
00250             correlator( &buffer.front(),&buffer.front()+dst.dimensions().x,
00251                         ker.begin(),
00252                         dst.row_begin(yy) );
00253         }
00254     }
00255 }
00256 
00257 template <typename PixelAccum>
00258 class correlator_n
00259 {
00260 private:
00261     std::size_t _size;
00262 public:
00263     correlator_n(std::size_t size_in) : _size(size_in) {}
00264     template <typename SrcIterator,typename KernelIterator,typename DstIterator>
00265         GIL_FORCEINLINE
00266     void operator()(SrcIterator src_begin,SrcIterator src_end,
00267                     KernelIterator ker_begin,
00268                     DstIterator dst_begin) {
00269         correlate_pixels_n<PixelAccum>(src_begin,src_end,ker_begin,_size,dst_begin);
00270     }
00271 };
00272 
00273 template <std::size_t Size,typename PixelAccum>
00274 struct correlator_k
00275 {
00276 public:
00277     template <typename SrcIterator,typename KernelIterator,typename DstIterator>
00278         GIL_FORCEINLINE
00279     void operator()(SrcIterator src_begin,SrcIterator src_end,
00280                     KernelIterator ker_begin,
00281                     DstIterator dst_begin){
00282         correlate_pixels_k<Size,PixelAccum>(src_begin,src_end,ker_begin,dst_begin);
00283     }
00284 };
00285 
00286 /// @ingroup ImageAlgorithms
00287 /// correlate a 1D variable-size kernel along the rows of an image
00288 template <typename PixelAccum,typename SrcView,typename Kernel,typename DstView>
00289 GIL_FORCEINLINE
00290 void correlate_1d_imp( const SrcView& src, const Kernel& ker, const DstView& dst, const typename SrcView::point_t& dst_tl,
00291                    const convolve_boundary_option option, const boost::mpl::true_ rows, const boost::mpl::false_ /*fixed*/ )
00292 {
00293         correlate_rows_imp<PixelAccum>(src,ker,dst,dst_tl,option,detail::correlator_n<PixelAccum>(ker.size()));
00294 }
00295 
00296 /// @ingroup ImageAlgorithms
00297 /// correlate a 1D fixed-size kernel along the rows of an image
00298 template <typename PixelAccum,typename SrcView,typename Kernel,typename DstView>
00299 GIL_FORCEINLINE
00300 void correlate_1d_imp( const SrcView& src, const Kernel& ker, const DstView& dst, const typename SrcView::point_t& dst_tl,
00301                    const convolve_boundary_option option, const boost::mpl::true_ rows, const boost::mpl::true_ /*fixed*/ )
00302 {
00303         correlate_rows_imp<PixelAccum>(src,ker,dst,dst_tl,option,detail::correlator_k<Kernel::static_size,PixelAccum>());
00304 }
00305 
00306 /// @ingroup ImageAlgorithms
00307 /// correlate a 1D variable-size kernel along the columns of an image
00308 /// can be remove with "fixed" param as template argument
00309 template <typename PixelAccum,typename SrcView,typename Kernel,typename DstView>
00310 GIL_FORCEINLINE
00311 void correlate_1d_imp( const SrcView& src, const Kernel& ker, const DstView& dst, const typename SrcView::point_t& dst_tl,
00312                    const convolve_boundary_option option, const boost::mpl::false_ rows, const boost::mpl::false_ fixed )
00313 {
00314         correlate_1d_imp<PixelAccum>( transposed_view(src), ker, transposed_view(dst), typename SrcView::point_t(dst_tl.y, dst_tl.x), option, boost::mpl::true_(), fixed );
00315 }
00316 
00317 /// @ingroup ImageAlgorithms
00318 /// correlate a 1D fixed-size kernel along the columns of an image
00319 template <typename PixelAccum,typename SrcView,typename Kernel,typename DstView>
00320 GIL_FORCEINLINE
00321 void correlate_1d_imp( const SrcView& src, const Kernel& ker, const DstView& dst, const typename SrcView::point_t& dst_tl,
00322                    const convolve_boundary_option option, const boost::mpl::false_ rows, const boost::mpl::true_ fixed )
00323 {
00324         correlate_1d_imp<PixelAccum>( transposed_view(src), ker, transposed_view(dst), typename SrcView::point_t(dst_tl.y, dst_tl.x), option, boost::mpl::true_(), fixed );
00325 }
00326 
00327 /// @ingroup ImageAlgorithms
00328 /// correlate a 1D fixed-size kernel along the rows of an image
00329 template <bool rows, typename PixelAccum,typename SrcView,typename Kernel,typename DstView>
00330 GIL_FORCEINLINE
00331 void correlate_1d_auto_imp( const SrcView& src, const Kernel& ker, const DstView& dst, const typename SrcView::point_t& dst_tl,
00332                           const convolve_boundary_option option, const boost::mpl::true_ fixed )
00333 {
00334         // already a fixed-size kernel, so nothing special to do for the auto conversion variable-size to fixed-size kernel
00335         correlate_1d_imp<PixelAccum,SrcView,Kernel,DstView>( src, ker, dst, dst_tl, option, boost::mpl::bool_<rows>(), fixed );
00336 }
00337 
00338 /// @ingroup ImageAlgorithms
00339 /// correlate a 1D variable-size kernel along the rows of an image
00340 template <bool rows, typename PixelAccum, typename SrcView,typename Kernel,typename DstView>
00341 GIL_FORCEINLINE
00342 void correlate_1d_auto_imp( const SrcView& src, const Kernel& ker, const DstView& dst, const typename SrcView::point_t& dst_tl,
00343                           const convolve_boundary_option option, const boost::mpl::false_ /*fixed*/ )
00344 {
00345         typedef boost::mpl::bool_<rows> Rows;
00346         typedef boost::mpl::true_ Fixed;
00347 
00348         switch( ker.size() )
00349         {
00350                 case 3:
00351                 {
00352                         typedef kernel_1d_fixed<typename Kernel::value_type, 3> FixedKernel;
00353                         FixedKernel fker( ker.begin(), ker.center() );
00354                         correlate_1d_imp<PixelAccum,SrcView,FixedKernel,DstView>( src, fker, dst, dst_tl, option, Rows(), Fixed() );
00355                         break;
00356                 }
00357                 case 5:
00358                 {
00359                         typedef kernel_1d_fixed<typename Kernel::value_type, 5> FixedKernel;
00360                         FixedKernel fker( ker.begin(), ker.center() );
00361                         correlate_1d_imp<PixelAccum,SrcView,FixedKernel,DstView>( src, fker, dst, dst_tl, option, Rows(), Fixed() );
00362                         break;
00363                 }
00364                 case 7:
00365                 {
00366                         typedef kernel_1d_fixed<typename Kernel::value_type, 7> FixedKernel;
00367                         FixedKernel fker( ker.begin(), ker.center() );
00368                         correlate_1d_imp<PixelAccum,SrcView,FixedKernel,DstView>( src, fker, dst, dst_tl, option, Rows(), Fixed() );
00369                         break;
00370                 }
00371                 default:
00372                 {
00373                         correlate_1d_imp<PixelAccum,SrcView,Kernel,DstView>( src, ker, dst, dst_tl, option, Rows(), boost::mpl::false_() );
00374                         break;
00375                 }
00376         }
00377 }
00378 
00379 /// @ingroup ImageAlgorithms
00380 /// correlate a 1D variable-size kernel along the rows of an image
00381 template <bool rows, typename PixelAccum, typename SrcView,typename Kernel,typename DstView>
00382 GIL_FORCEINLINE
00383 void correlate_1d_auto( const SrcView& src, const Kernel& ker, const DstView& dst, const typename SrcView::point_t& dst_tl,
00384                         const convolve_boundary_option option, const boost::mpl::true_ autoEnabled )
00385 {
00386         typedef typename Kernel::is_fixed_size_t Fixed;
00387         correlate_1d_auto_imp<rows,PixelAccum,SrcView,Kernel,DstView>( src, ker, dst, dst_tl, option, Fixed() );
00388 }
00389 
00390 /// @ingroup ImageAlgorithms
00391 /// correlate a 1D variable-size kernel along the rows of an image
00392 template <bool rows, typename PixelAccum, typename SrcView,typename Kernel,typename DstView>
00393 GIL_FORCEINLINE
00394 void correlate_1d_auto( const SrcView& src, const Kernel& ker, const DstView& dst, const typename SrcView::point_t& dst_tl,
00395                         const convolve_boundary_option option, const boost::mpl::false_ autoEnabled )
00396 {
00397         typedef typename Kernel::is_fixed_size_t Fixed;
00398         typedef boost::mpl::bool_<rows> Rows;
00399         correlate_1d_imp<PixelAccum,SrcView,Kernel,DstView>( src, ker, dst, dst_tl, option, Rows(), Fixed() );
00400 }
00401 
00402 } // namespace detail //
00403 
00404 
00405 /// @ingroup ImageAlgorithms
00406 /// correlate a 1D variable-size kernel along the rows of an image
00407 template <bool autoEnabled, bool rows, typename PixelAccum, typename SrcView,typename Kernel,typename DstView>
00408 GIL_FORCEINLINE
00409 void correlate_1d_imp( const SrcView& src, const Kernel& ker, const DstView& dst, const typename SrcView::point_t& dst_tl,
00410                         const convolve_boundary_option option = convolve_option_extend_zero )
00411 {
00412         detail::correlate_1d_auto<rows,PixelAccum,SrcView,Kernel,DstView>( src, ker, dst, dst_tl, option, boost::mpl::bool_<autoEnabled>() );
00413 }
00414 
00415 /// @ingroup ImageAlgorithms
00416 /// correlate a 1D variable-size kernel along the rows of an image
00417 template <bool rows, typename PixelAccum, typename SrcView,typename Kernel,typename DstView>
00418 GIL_FORCEINLINE
00419 void correlate_1d_auto( const SrcView& src, const Kernel& ker, const DstView& dst, const typename SrcView::point_t& dst_tl,
00420                         const convolve_boundary_option option = convolve_option_extend_zero )
00421 {
00422         correlate_1d_imp<true,rows,PixelAccum,rows,SrcView,Kernel,DstView>( src, ker, dst, dst_tl, option );
00423 }
00424 
00425 /// @ingroup ImageAlgorithms
00426 /// correlate a 1D variable-size kernel along the rows of an image
00427 template <bool rows, typename PixelAccum, typename SrcView,typename Kernel,typename DstView>
00428 GIL_FORCEINLINE
00429 void correlate_1d( const SrcView& src, const Kernel& ker, const DstView& dst, const typename SrcView::point_t& dst_tl,
00430                         const convolve_boundary_option option = convolve_option_extend_zero )
00431 {
00432         correlate_1d_imp<false,rows,PixelAccum,rows,SrcView,Kernel,DstView>( src, ker, dst, dst_tl, option);
00433 }
00434 
00435 /// @ingroup ImageAlgorithms
00436 /// correlate a 1D variable-size kernel along the rows of an image
00437 template <bool autoEnabled,typename PixelAccum,typename SrcView,typename Kernel,typename DstView>
00438 GIL_FORCEINLINE
00439 void correlate_rows_imp(const SrcView& src, const Kernel& ker, const DstView& dst, const typename SrcView::point_t& dst_tl,
00440                     const convolve_boundary_option option = convolve_option_extend_zero )
00441 {
00442         correlate_1d_imp<autoEnabled,true,PixelAccum,SrcView,Kernel,DstView>( src, ker, dst, dst_tl, option );
00443 }
00444 
00445 /// @ingroup ImageAlgorithms
00446 /// correlate a 1D variable-size kernel along the rows of an image
00447 template <typename PixelAccum,typename SrcView,typename Kernel,typename DstView>
00448 GIL_FORCEINLINE
00449 void correlate_rows_auto(const SrcView& src, const Kernel& ker, const DstView& dst, const typename SrcView::point_t& dst_tl,
00450                     const convolve_boundary_option option = convolve_option_extend_zero )
00451 {
00452         correlate_rows_imp<true,PixelAccum,SrcView,Kernel,DstView>( src, ker, dst, dst_tl, option );
00453 }
00454 
00455 /// @ingroup ImageAlgorithms
00456 /// correlate a 1D variable-size kernel along the rows of an image
00457 template <typename PixelAccum,typename SrcView,typename Kernel,typename DstView>
00458 GIL_FORCEINLINE
00459 void correlate_rows(const SrcView& src, const Kernel& ker, const DstView& dst, const typename SrcView::point_t& dst_tl = typename SrcView::point_t(0,0),
00460                     const convolve_boundary_option option = convolve_option_extend_zero )
00461 {
00462         correlate_rows_imp<false,PixelAccum,SrcView,Kernel,DstView>( src, ker, dst, dst_tl, option );
00463 }
00464 
00465 /// @ingroup ImageAlgorithms
00466 /// correlate a 1D variable-size kernel along the columns of an image
00467 template <bool autoEnabled,typename PixelAccum,typename SrcView,typename Kernel,typename DstView>
00468 GIL_FORCEINLINE
00469 void correlate_cols_imp(const SrcView& src, const Kernel& ker, const DstView& dst, const typename SrcView::point_t& dst_tl,
00470                     const convolve_boundary_option option = convolve_option_extend_zero )
00471 {
00472         correlate_1d_imp<autoEnabled,false,PixelAccum,SrcView,Kernel,DstView>( src, ker, dst, dst_tl, option );
00473 }
00474 
00475 /// @ingroup ImageAlgorithms
00476 /// correlate a 1D variable-size kernel along the columns of an image
00477 template <typename PixelAccum,typename SrcView,typename Kernel,typename DstView>
00478 GIL_FORCEINLINE
00479 void correlate_cols_auto(const SrcView& src, const Kernel& ker, const DstView& dst, const typename SrcView::point_t& dst_tl,
00480                     const convolve_boundary_option option = convolve_option_extend_zero )
00481 {
00482         correlate_cols_imp<true,PixelAccum,SrcView,Kernel,DstView>( src, ker, dst, dst_tl, option );
00483 }
00484 
00485 /// @ingroup ImageAlgorithms
00486 /// correlate a 1D variable-size kernel along the columns of an image
00487 template <typename PixelAccum,typename SrcView,typename Kernel,typename DstView>
00488 GIL_FORCEINLINE
00489 void correlate_cols(const SrcView& src, const Kernel& ker, const DstView& dst, const typename SrcView::point_t& dst_tl = typename SrcView::point_t(0,0),
00490                     const convolve_boundary_option option = convolve_option_extend_zero )
00491 {
00492         correlate_cols_imp<false,PixelAccum,SrcView,Kernel,DstView>( src, ker, dst, dst_tl, option );
00493 }
00494 
00495 /// @ingroup ImageAlgorithms
00496 /// correlate a 2D separable variable-size kernel (kernelX and kernelY)
00497 template <bool autoEnabled, typename PixelAccum, template<typename> class Alloc, typename SrcView, typename KernelX,typename KernelY,typename DstView >
00498 GIL_FORCEINLINE
00499 void correlate_rows_cols_imp( const SrcView& src,
00500                           const KernelX& kernelX,
00501                                                   const KernelY& kernelY,
00502                                                   const DstView& dst,
00503                                                   const typename SrcView::point_t& dst_tl,
00504                                                   const convolve_boundary_option option = convolve_option_extend_zero )
00505 {
00506     typedef typename DstView::point_t Point;
00507     typedef typename DstView::coord_t Coord;
00508         typedef typename view_type_from_pixel<PixelAccum, is_planar<DstView>::value >::type ViewAccum;
00509         typedef image<PixelAccum, is_planar<DstView>::value, Alloc<unsigned char> > ImageAccum;
00510 
00511         if( kernelX.size() > 2 && kernelY.size() > 2 )
00512         {
00513                 if( dst.dimensions() == src.dimensions() ) // no tiles... easy !
00514                 {
00515                         typename SrcView::point_t zero(0,0);
00516                         correlate_rows_imp<autoEnabled,PixelAccum>( src, kernelX, dst, zero, option );
00517                         correlate_cols_imp<autoEnabled,PixelAccum>( dst, kernelY, dst, zero, option );
00518                 }
00519                 else
00520                 {
00521                         // we have 2 pass, so to use tiles, we need a temporary buffer
00522                         // _________________src______________
00523                         // |      ....proc_src_roi.....      |
00524                         // |      :  :             :  :      |
00525                         // |      :  :_____________:  :      |
00526                         // |      :  |             |  :      |
00527                         // |      :  |     dst     |  :      |
00528                         // |      :  |             |  :      |
00529                         // |      :  |_____________|  :      |
00530                         // |      :  : tmp_buffer  :  :      |
00531                         // |      :..:.............:..:      |
00532                         // |_________________________________|
00533                         // tmp_buffer: is the temporary buffer used after the correlate_rows
00534                         //             (width of procWin and height of proc_src_roi)
00535                         Coord top_in = std::min( boost::numeric_cast<Coord>( kernelY.left_size()), dst_tl.y );
00536                         Coord bottom_in = std::min( boost::numeric_cast<Coord>( kernelY.right_size()), src.height()-(dst_tl.y+dst.height()) );
00537                         Point image_tmp_size( dst.dimensions() );
00538                         image_tmp_size.y += top_in + bottom_in;
00539                         Point image_tmp_tl( dst_tl );
00540                         image_tmp_tl.y -= top_in;
00541                         
00542                         ImageAccum image_tmp( image_tmp_size );
00543                         ViewAccum view_tmp = view( image_tmp );
00544                         const Point dst_tmp_tl( 0, top_in );
00545 
00546                         correlate_rows_imp<autoEnabled,PixelAccum>( src, kernelX, view_tmp, image_tmp_tl, option );
00547                         correlate_cols_imp<autoEnabled,PixelAccum>( view_tmp, kernelY, dst, dst_tmp_tl, option );
00548                 }
00549         }
00550         else if( kernelX.size() > 2 )
00551         {
00552                 correlate_rows_imp<autoEnabled,PixelAccum>( src, kernelX, dst, dst_tl, option );
00553         }
00554         else if( kernelY.size() > 2 )
00555         {
00556                 correlate_cols_imp<autoEnabled,PixelAccum>( src, kernelY, dst, dst_tl, option );
00557         }
00558 }
00559 
00560 /// @ingroup ImageAlgorithms
00561 /// correlate a 2D separable variable-size kernel (kernelX and kernelY)
00562 template <typename PixelAccum, template<typename> class Alloc, typename SrcView, typename KernelX, typename KernelY, typename DstView>
00563 GIL_FORCEINLINE
00564 void correlate_rows_cols_auto( const SrcView& src,
00565                           const KernelX& kernelX,
00566                                                   const KernelY& kernelY,
00567                                                   const DstView& dst,
00568                                                   const typename SrcView::point_t& dst_tl,
00569                                                   const convolve_boundary_option option = convolve_option_extend_zero )
00570 {
00571         correlate_rows_cols_imp<true,PixelAccum,Alloc,SrcView,KernelX,KernelY,DstView>( src, kernelX, kernelY, dst, dst_tl, option );
00572 }
00573 
00574 /// @ingroup ImageAlgorithms
00575 /// correlate a 2D separable variable-size kernel (kernelX and kernelY)
00576 template <typename PixelAccum, template<typename> class Alloc, typename SrcView, typename KernelX, typename KernelY, typename DstView>
00577 GIL_FORCEINLINE
00578 void correlate_rows_cols( const SrcView& src,
00579                           const KernelX& kernelX,
00580                                                   const KernelY& kernelY,
00581                                                   const DstView& dst,
00582                                                   const typename SrcView::point_t& dst_tl,
00583                                                   const convolve_boundary_option option = convolve_option_extend_zero )
00584 {
00585         correlate_rows_cols_imp<false,PixelAccum,Alloc,SrcView,KernelX,KernelY,DstView>( src, kernelX, kernelY, dst, dst_tl, option );
00586 }
00587 
00588 }
00589 }
00590 
00591 #endif
00592