TuttleOFX
1
|
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