convolve.hpp 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. //
  2. // Copyright 2005-2007 Adobe Systems Incorporated
  3. //
  4. // Distributed under the Boost Software License, Version 1.0
  5. // See accompanying file LICENSE_1_0.txt or copy at
  6. // http://www.boost.org/LICENSE_1_0.txt
  7. //
  8. #ifndef BOOST_GIL_EXTENSION_NUMERIC_CONVOLVE_HPP
  9. #define BOOST_GIL_EXTENSION_NUMERIC_CONVOLVE_HPP
  10. #include <boost/gil/extension/numeric/algorithm.hpp>
  11. #include <boost/gil/extension/numeric/kernel.hpp>
  12. #include <boost/gil/extension/numeric/pixel_numeric_operations.hpp>
  13. #include <boost/gil/algorithm.hpp>
  14. #include <boost/gil/image_view_factory.hpp>
  15. #include <boost/gil/metafunctions.hpp>
  16. #include <boost/assert.hpp>
  17. #include <algorithm>
  18. #include <cstddef>
  19. #include <functional>
  20. #include <type_traits>
  21. #include <vector>
  22. namespace boost { namespace gil {
  23. // 2D seperable convolutions and correlations
  24. /// \ingroup ImageAlgorithms
  25. /// Boundary options for 1D correlations/convolutions
  26. enum convolve_boundary_option {
  27. convolve_option_output_ignore, /// do nothing to the output
  28. convolve_option_output_zero, /// set the output to zero
  29. convolve_option_extend_padded, /// assume the source boundaries to be padded already
  30. convolve_option_extend_zero, /// assume the source boundaries to be zero
  31. convolve_option_extend_constant /// assume the source boundaries to be the boundary value
  32. };
  33. namespace detail {
  34. /// compute the correlation of 1D kernel with the rows of an image
  35. template <typename PixelAccum,typename SrcView,typename Kernel,typename DstView,typename Correlator>
  36. void correlate_rows_imp(const SrcView& src, const Kernel& ker, const DstView& dst,
  37. convolve_boundary_option option,
  38. Correlator correlator) {
  39. BOOST_ASSERT(src.dimensions() == dst.dimensions());
  40. BOOST_ASSERT(ker.size() != 0);
  41. using PIXEL_SRC_REF = typename pixel_proxy<typename SrcView::value_type>::type;
  42. using PIXEL_DST_REF = typename pixel_proxy<typename DstView::value_type>::type;
  43. if(ker.size()==1) {//reduces to a multiplication
  44. view_multiplies_scalar<PixelAccum>(src,*ker.begin(),dst);
  45. return;
  46. }
  47. int width=src.width(),height=src.height();
  48. PixelAccum acc_zero; pixel_zeros_t<PixelAccum>()(acc_zero);
  49. if (width==0) return;
  50. if (option==convolve_option_output_ignore || option==convolve_option_output_zero) {
  51. typename DstView::value_type dst_zero; pixel_assigns_t<PixelAccum,PIXEL_DST_REF>()(acc_zero,dst_zero);
  52. if (width<(int)ker.size()) {
  53. if (option==convolve_option_output_zero)
  54. fill_pixels(dst,dst_zero);
  55. } else {
  56. std::vector<PixelAccum> buffer(width);
  57. for(int rr=0;rr<height;++rr) {
  58. assign_pixels(src.row_begin(rr),src.row_end(rr),&buffer.front());
  59. typename DstView::x_iterator it_dst=dst.row_begin(rr);
  60. if (option==convolve_option_output_zero)
  61. std::fill_n(it_dst,ker.left_size(),dst_zero);
  62. it_dst+=ker.left_size();
  63. correlator(&buffer.front(),&buffer.front()+width+1-ker.size(),
  64. ker.begin(),it_dst);
  65. it_dst+=width+1-ker.size();
  66. if (option==convolve_option_output_zero)
  67. std::fill_n(it_dst,ker.right_size(),dst_zero);
  68. }
  69. }
  70. } else {
  71. std::vector<PixelAccum> buffer(width+ker.size()-1);
  72. for(int rr=0;rr<height;++rr) {
  73. PixelAccum* it_buffer=&buffer.front();
  74. if (option==convolve_option_extend_padded) {
  75. assign_pixels(src.row_begin(rr)-ker.left_size(),
  76. src.row_end(rr)+ker.right_size(),
  77. it_buffer);
  78. } else if (option==convolve_option_extend_zero) {
  79. std::fill_n(it_buffer,ker.left_size(),acc_zero);
  80. it_buffer+=ker.left_size();
  81. assign_pixels(src.row_begin(rr),src.row_end(rr),it_buffer);
  82. it_buffer+=width;
  83. std::fill_n(it_buffer,ker.right_size(),acc_zero);
  84. } else if (option==convolve_option_extend_constant) {
  85. PixelAccum filler;
  86. pixel_assigns_t<PIXEL_SRC_REF,PixelAccum>()(*src.row_begin(rr),filler);
  87. std::fill_n(it_buffer,ker.left_size(),filler);
  88. it_buffer+=ker.left_size();
  89. assign_pixels(src.row_begin(rr),src.row_end(rr),it_buffer);
  90. it_buffer+=width;
  91. pixel_assigns_t<PIXEL_SRC_REF,PixelAccum>()(src.row_end(rr)[-1],filler);
  92. std::fill_n(it_buffer,ker.right_size(),filler);
  93. }
  94. correlator(&buffer.front(),&buffer.front()+width,
  95. ker.begin(),
  96. dst.row_begin(rr));
  97. }
  98. }
  99. }
  100. template <typename PixelAccum>
  101. class correlator_n {
  102. private:
  103. std::size_t _size;
  104. public:
  105. correlator_n(std::size_t size_in) : _size(size_in) {}
  106. template <typename SrcIterator,typename KernelIterator,typename DstIterator>
  107. void operator()(SrcIterator src_begin,SrcIterator src_end,
  108. KernelIterator ker_begin,
  109. DstIterator dst_begin) {
  110. correlate_pixels_n<PixelAccum>(src_begin,src_end,ker_begin,_size,dst_begin);
  111. }
  112. };
  113. template <std::size_t Size,typename PixelAccum>
  114. struct correlator_k {
  115. public:
  116. template <typename SrcIterator,typename KernelIterator,typename DstIterator>
  117. void operator()(SrcIterator src_begin,SrcIterator src_end,
  118. KernelIterator ker_begin,
  119. DstIterator dst_begin){
  120. correlate_pixels_k<Size,PixelAccum>(src_begin,src_end,ker_begin,dst_begin);
  121. }
  122. };
  123. } // namespace detail
  124. /// \ingroup ImageAlgorithms
  125. ///correlate a 1D variable-size kernel along the rows of an image
  126. template <typename PixelAccum,typename SrcView,typename Kernel,typename DstView>
  127. BOOST_FORCEINLINE
  128. void correlate_rows(const SrcView& src, const Kernel& ker, const DstView& dst,
  129. convolve_boundary_option option=convolve_option_extend_zero) {
  130. detail::correlate_rows_imp<PixelAccum>(src,ker,dst,option,detail::correlator_n<PixelAccum>(ker.size()));
  131. }
  132. /// \ingroup ImageAlgorithms
  133. ///correlate a 1D variable-size kernel along the columns of an image
  134. template <typename PixelAccum,typename SrcView,typename Kernel,typename DstView>
  135. BOOST_FORCEINLINE
  136. void correlate_cols(const SrcView& src, const Kernel& ker, const DstView& dst,
  137. convolve_boundary_option option=convolve_option_extend_zero) {
  138. correlate_rows<PixelAccum>(transposed_view(src),ker,transposed_view(dst),option);
  139. }
  140. /// \ingroup ImageAlgorithms
  141. ///convolve a 1D variable-size kernel along the rows of an image
  142. template <typename PixelAccum,typename SrcView,typename Kernel,typename DstView>
  143. BOOST_FORCEINLINE
  144. void convolve_rows(const SrcView& src, const Kernel& ker, const DstView& dst,
  145. convolve_boundary_option option=convolve_option_extend_zero) {
  146. correlate_rows<PixelAccum>(src,reverse_kernel(ker),dst,option);
  147. }
  148. /// \ingroup ImageAlgorithms
  149. ///convolve a 1D variable-size kernel along the columns of an image
  150. template <typename PixelAccum,typename SrcView,typename Kernel,typename DstView>
  151. BOOST_FORCEINLINE
  152. void convolve_cols(const SrcView& src, const Kernel& ker, const DstView& dst,
  153. convolve_boundary_option option=convolve_option_extend_zero) {
  154. convolve_rows<PixelAccum>(transposed_view(src),ker,transposed_view(dst),option);
  155. }
  156. /// \ingroup ImageAlgorithms
  157. ///correlate a 1D fixed-size kernel along the rows of an image
  158. template <typename PixelAccum, typename SrcView, typename Kernel, typename DstView>
  159. BOOST_FORCEINLINE
  160. void correlate_rows_fixed(const SrcView& src, const Kernel& kernel, const DstView& dst,
  161. convolve_boundary_option option=convolve_option_extend_zero)
  162. {
  163. using correlator = detail::correlator_k
  164. <
  165. std::extent<Kernel>::value,
  166. PixelAccum
  167. >;
  168. detail::correlate_rows_imp<PixelAccum>(
  169. src, kernel, dst, option, correlator{});
  170. }
  171. /// \ingroup ImageAlgorithms
  172. ///correlate a 1D fixed-size kernel along the columns of an image
  173. template <typename PixelAccum,typename SrcView,typename Kernel,typename DstView>
  174. BOOST_FORCEINLINE
  175. void correlate_cols_fixed(const SrcView& src, const Kernel& ker, const DstView& dst,
  176. convolve_boundary_option option=convolve_option_extend_zero) {
  177. correlate_rows_fixed<PixelAccum>(transposed_view(src),ker,transposed_view(dst),option);
  178. }
  179. /// \ingroup ImageAlgorithms
  180. ///convolve a 1D fixed-size kernel along the rows of an image
  181. template <typename PixelAccum,typename SrcView,typename Kernel,typename DstView>
  182. BOOST_FORCEINLINE
  183. void convolve_rows_fixed(const SrcView& src, const Kernel& ker, const DstView& dst,
  184. convolve_boundary_option option=convolve_option_extend_zero) {
  185. correlate_rows_fixed<PixelAccum>(src,reverse_kernel(ker),dst,option);
  186. }
  187. /// \ingroup ImageAlgorithms
  188. ///convolve a 1D fixed-size kernel along the columns of an image
  189. template <typename PixelAccum,typename SrcView,typename Kernel,typename DstView>
  190. BOOST_FORCEINLINE
  191. void convolve_cols_fixed(const SrcView& src, const Kernel& ker, const DstView& dst,
  192. convolve_boundary_option option=convolve_option_extend_zero) {
  193. convolve_rows_fixed<PixelAccum>(transposed_view(src),ker,transposed_view(dst),option);
  194. }
  195. }} // namespace boost::gil
  196. #endif