diff --git a/include/boost/gil/extension/numeric/convolve.hpp b/include/boost/gil/extension/numeric/convolve.hpp index 439b8e472..ffbed435b 100644 --- a/include/boost/gil/extension/numeric/convolve.hpp +++ b/include/boost/gil/extension/numeric/convolve.hpp @@ -29,8 +29,11 @@ namespace boost { namespace gil { // 2D seperable convolutions and correlations /// \ingroup ImageAlgorithms -/// Boundary options for 1D correlations/convolutions -enum convolve_boundary_option { +/// \brief Boundary options for 1D correlations and convolutions +/// Use it as `enum class` with mutually exclusive constants, not as bitfields. +/// \todo TODO: Change to enum class? +enum /*class*/ convolve_boundary_option +{ convolve_option_output_ignore, /// do nothing to the output convolve_option_output_zero, /// set the output to zero convolve_option_extend_padded, /// assume the source boundaries to be padded already @@ -39,183 +42,313 @@ enum convolve_boundary_option { }; namespace detail { -/// compute the correlation of 1D kernel with the rows of an image -template -void correlate_rows_imp(const SrcView& src, const Kernel& ker, const DstView& dst, - convolve_boundary_option option, - Correlator correlator) { - BOOST_ASSERT(src.dimensions() == dst.dimensions()); - BOOST_ASSERT(ker.size() != 0); - using PIXEL_SRC_REF = typename pixel_proxy::type; - using PIXEL_DST_REF = typename pixel_proxy::type; +/// \brief Compute the correlation of 1D kernel with the rows of an image +/// \tparam PixelAccum - TODO +/// \tparam SrcView Models ImageViewConcept +/// \tparam Kernel - TODO +/// \tparam DstView Models MutableImageViewConcept +/// \tparam Correlator - TODO +/// \param src_view +/// \param kernel - TODO +/// \param dst_view Destination where new computed values of pixels are assigned to +/// \param option - TODO +/// \param correlator - TODO +template +< + typename PixelAccum, + typename SrcView, + typename Kernel, + typename DstView, + typename Correlator +> +void correlate_rows_impl( + SrcView const& src_view, + Kernel const& kernel, + DstView const& dst_view, + convolve_boundary_option option, + Correlator correlator) +{ + BOOST_ASSERT(src_view.dimensions() == dst_view.dimensions()); + BOOST_ASSERT(kernel.size() != 0); - if(ker.size()==1) {//reduces to a multiplication - view_multiplies_scalar(src,*ker.begin(),dst); + if(kernel.size() == 1) + { + // Reduces to a multiplication + view_multiplies_scalar(src_view, *kernel.begin(), dst_view); return; } - int width=src.width(),height=src.height(); - PixelAccum acc_zero; pixel_zeros_t()(acc_zero); - if (width==0) return; - if (option==convolve_option_output_ignore || option==convolve_option_output_zero) { - typename DstView::value_type dst_zero; pixel_assigns_t()(acc_zero,dst_zero); - if (width<(int)ker.size()) { - if (option==convolve_option_output_zero) - fill_pixels(dst,dst_zero); - } else { + using SrcPixelRef = typename pixel_proxy::type; + using DstPixelRef = typename pixel_proxy::type; + + int width = src_view.width(), height = src_view.height(); + PixelAccum acc_zero; + pixel_zeros_t()(acc_zero); + if (width == 0) + return; + if (option == convolve_option_output_ignore || option == convolve_option_output_zero) + { + typename DstView::value_type dst_zero; + pixel_assigns_t()(acc_zero, dst_zero); + if (width < static_cast(kernel.size())) + { + if (option == convolve_option_output_zero) + fill_pixels(dst_view, dst_zero); + } + else + { std::vector buffer(width); - for(int rr=0;rr buffer(width+ker.size()-1); - for(int rr=0;rr()(*src.row_begin(rr),filler); - std::fill_n(it_buffer,ker.left_size(),filler); - it_buffer+=ker.left_size(); - assign_pixels(src.row_begin(rr),src.row_end(rr),it_buffer); - it_buffer+=width; - pixel_assigns_t()(src.row_end(rr)[-1],filler); - std::fill_n(it_buffer,ker.right_size(),filler); + } + else + { + std::vector buffer(width + kernel.size() - 1); + for (int rr = 0; rr < height; ++rr) + { + PixelAccum *it_buffer = &buffer.front(); + if (option == convolve_option_extend_padded) + { + assign_pixels( + src_view.row_begin(rr) - kernel.left_size(), + src_view.row_end(rr) + kernel.right_size(), + it_buffer); } - correlator(&buffer.front(),&buffer.front()+width, - ker.begin(), - dst.row_begin(rr)); + else if (option == convolve_option_extend_zero) + { + std::fill_n(it_buffer, kernel.left_size(), acc_zero); + it_buffer += kernel.left_size(); + assign_pixels(src_view.row_begin(rr), src_view.row_end(rr), it_buffer); + it_buffer += width; + std::fill_n(it_buffer, kernel.right_size(), acc_zero); + } + else if (option == convolve_option_extend_constant) + { + PixelAccum filler; + pixel_assigns_t()(*src_view.row_begin(rr), filler); + std::fill_n(it_buffer, kernel.left_size(), filler); + it_buffer += kernel.left_size(); + assign_pixels(src_view.row_begin(rr), src_view.row_end(rr), it_buffer); + it_buffer += width; + pixel_assigns_t()(src_view.row_end(rr)[-1], filler); + std::fill_n(it_buffer, kernel.right_size(), filler); + } + + correlator( + &buffer.front(), &buffer.front() + width, + kernel.begin(), + dst_view.row_begin(rr)); } } } + template -class correlator_n { +class correlator_n +{ +public: + correlator_n(std::size_t size) : size_(size) {} + + template + void operator()( + SrcIterator src_begin, + SrcIterator src_end, + KernelIterator kernel_begin, + DstIterator dst_begin) + { + correlate_pixels_n(src_begin, src_end, kernel_begin, size_, dst_begin); + } + private: - std::size_t _size; -public: - correlator_n(std::size_t size_in) : _size(size_in) {} - template - void operator()(SrcIterator src_begin,SrcIterator src_end, - KernelIterator ker_begin, - DstIterator dst_begin) { - correlate_pixels_n(src_begin,src_end,ker_begin,_size,dst_begin); - } -}; -template -struct correlator_k { -public: - template - void operator()(SrcIterator src_begin,SrcIterator src_end, - KernelIterator ker_begin, - DstIterator dst_begin){ - correlate_pixels_k(src_begin,src_end,ker_begin,dst_begin); + std::size_t size_{0}; +}; + +template +struct correlator_k +{ + template + void operator()( + SrcIterator src_begin, + SrcIterator src_end, + KernelIterator kernel_begin, + DstIterator dst_begin) + { + correlate_pixels_k(src_begin, src_end, kernel_begin, dst_begin); } }; + } // namespace detail /// \ingroup ImageAlgorithms -///correlate a 1D variable-size kernel along the rows of an image -template -BOOST_FORCEINLINE -void correlate_rows(const SrcView& src, const Kernel& ker, const DstView& dst, - convolve_boundary_option option=convolve_option_extend_zero) { - detail::correlate_rows_imp(src,ker,dst,option,detail::correlator_n(ker.size())); -} - -/// \ingroup ImageAlgorithms -///correlate a 1D variable-size kernel along the columns of an image -template -BOOST_FORCEINLINE -void correlate_cols(const SrcView& src, const Kernel& ker, const DstView& dst, - convolve_boundary_option option=convolve_option_extend_zero) { - correlate_rows(transposed_view(src),ker,transposed_view(dst),option); -} - -/// \ingroup ImageAlgorithms -///convolve a 1D variable-size kernel along the rows of an image -template -BOOST_FORCEINLINE -void convolve_rows(const SrcView& src, const Kernel& ker, const DstView& dst, - convolve_boundary_option option=convolve_option_extend_zero) { - correlate_rows(src,reverse_kernel(ker),dst,option); -} - -/// \ingroup ImageAlgorithms -///convolve a 1D variable-size kernel along the columns of an image -template -BOOST_FORCEINLINE -void convolve_cols(const SrcView& src, const Kernel& ker, const DstView& dst, - convolve_boundary_option option=convolve_option_extend_zero) { - convolve_rows(transposed_view(src),ker,transposed_view(dst),option); -} - -/// \ingroup ImageAlgorithms -///convolve a 1D variable-size kernel along both rows and columns of an image -template -BOOST_FORCEINLINE -void convolve(const SrcView& src, const Kernel& ker, const DstView& dst, - convolve_boundary_option option=convolve_option_extend_zero) { - convolve_rows(src, ker, dst, option); - convolve_cols(dst, ker, dst, option); -} - -/// \ingroup ImageAlgorithms -///correlate a 1D fixed-size kernel along the rows of an image +/// \brief Correlate 1D variable-size kernel along the rows of image +/// \tparam PixelAccum TODO +/// \tparam SrcView Models ImageViewConcept +/// \tparam Kernel TODO +/// \tparam DstView Models MutableImageViewConcept template BOOST_FORCEINLINE -void correlate_rows_fixed(const SrcView& src, const Kernel& kernel, const DstView& dst, - convolve_boundary_option option=convolve_option_extend_zero) +void correlate_rows( + SrcView const& src_view, + Kernel const& kernel, + DstView const& dst_view, + convolve_boundary_option option = convolve_option_extend_zero) +{ + detail::correlate_rows_impl( + src_view, kernel, dst_view, option, detail::correlator_n(kernel.size())); +} + +/// \ingroup ImageAlgorithms +/// \brief Correlate 1D variable-size kernel along the columns of image +/// \tparam PixelAccum TODO +/// \tparam SrcView Models ImageViewConcept +/// \tparam Kernel TODO +/// \tparam DstView Models MutableImageViewConcept +template +BOOST_FORCEINLINE +void correlate_cols( + SrcView const& src_view, + Kernel const& kernel, + DstView const& dst_view, + convolve_boundary_option option = convolve_option_extend_zero) +{ + correlate_rows( + transposed_view(src_view), kernel, transposed_view(dst_view), option); +} + +/// \ingroup ImageAlgorithms +/// \brief Convolve 1D variable-size kernel along the rows of image +/// \tparam PixelAccum TODO +/// \tparam SrcView Models ImageViewConcept +/// \tparam Kernel TODO +/// \tparam DstView Models MutableImageViewConcept +template +BOOST_FORCEINLINE +void convolve_rows( + SrcView const& src_view, + Kernel const& kernel, + DstView const& dst_view, + convolve_boundary_option option = convolve_option_extend_zero) +{ + correlate_rows(src_view, reverse_kernel(kernel), dst_view, option); +} + +/// \ingroup ImageAlgorithms +/// \brief Convolve 1D variable-size kernel along the columns of image +/// \tparam PixelAccum TODO +/// \tparam SrcView Models ImageViewConcept +/// \tparam Kernel TODO +/// \tparam DstView Models MutableImageViewConcept +template +BOOST_FORCEINLINE +void convolve_cols( + SrcView const& src_view, + Kernel const& kernel, + DstView const& dst_view, + convolve_boundary_option option = convolve_option_extend_zero) +{ + convolve_rows( + transposed_view(src_view), kernel, transposed_view(dst_view), option); +} + +/// \ingroup ImageAlgorithms +/// \brief Convolve 1D variable-size kernel along both rows and columns of image +/// \tparam PixelAccum TODO +/// \tparam SrcView Models ImageViewConcept +/// \tparam Kernel TODO +/// \tparam DstView Models MutableImageViewConcept +template +BOOST_FORCEINLINE +void convolve( + SrcView const& src_view, + Kernel const& kernel, + DstView const& dst_view, + convolve_boundary_option option = convolve_option_extend_zero) +{ + convolve_rows(src_view, kernel, dst_view, option); + convolve_cols(dst_view, kernel, dst_view, option); +} + +/// \ingroup ImageAlgorithms +/// \brief Correlate 1D fixed-size kernel along the rows of image +/// \tparam PixelAccum TODO +/// \tparam SrcView Models ImageViewConcept +/// \tparam Kernel TODO +/// \tparam DstView Models MutableImageViewConcept +template +BOOST_FORCEINLINE +void correlate_rows_fixed( + SrcView const& src_view, + Kernel const& kernel, + DstView const& dst_view, + convolve_boundary_option option = convolve_option_extend_zero) { using correlator = detail::correlator_k; - detail::correlate_rows_imp( - src, kernel, dst, option, correlator{}); + detail::correlate_rows_impl(src_view, kernel, dst_view, option, correlator{}); } /// \ingroup ImageAlgorithms -///correlate a 1D fixed-size kernel along the columns of an image +/// \brief Correlate 1D fixed-size kernel along the columns of image +/// \tparam PixelAccum TODO +/// \tparam SrcView Models ImageViewConcept +/// \tparam Kernel TODO +/// \tparam DstView Models MutableImageViewConcept template BOOST_FORCEINLINE -void correlate_cols_fixed(const SrcView& src, const Kernel& ker, const DstView& dst, - convolve_boundary_option option=convolve_option_extend_zero) { - correlate_rows_fixed(transposed_view(src),ker,transposed_view(dst),option); +void correlate_cols_fixed( + SrcView const& src_view, + Kernel const& kernel, + DstView const& dst_view, + convolve_boundary_option option = convolve_option_extend_zero) +{ + correlate_rows_fixed( + transposed_view(src_view), kernel, transposed_view(dst_view), option); } /// \ingroup ImageAlgorithms -///convolve a 1D fixed-size kernel along the rows of an image -template +/// \brief Convolve 1D fixed-size kernel along the rows of image +/// \tparam PixelAccum TODO +/// \tparam SrcView Models ImageViewConcept +/// \tparam Kernel TODO +/// \tparam DstView Models MutableImageViewConcept +template BOOST_FORCEINLINE -void convolve_rows_fixed(const SrcView& src, const Kernel& ker, const DstView& dst, - convolve_boundary_option option=convolve_option_extend_zero) { - correlate_rows_fixed(src,reverse_kernel(ker),dst,option); +void convolve_rows_fixed( + SrcView const& src_view, + Kernel const& kernel, + DstView const& dst_view, + convolve_boundary_option option = convolve_option_extend_zero) +{ + correlate_rows_fixed(src_view, reverse_kernel(kernel), dst_view, option); } /// \ingroup ImageAlgorithms -///convolve a 1D fixed-size kernel along the columns of an image -template +/// \brief Convolve 1D fixed-size kernel along the columns of image +/// \tparam PixelAccum TODO +/// \tparam SrcView Models ImageViewConcept +/// \tparam Kernel TODO +/// \tparam DstView Models MutableImageViewConcept +template BOOST_FORCEINLINE -void convolve_cols_fixed(const SrcView& src, const Kernel& ker, const DstView& dst, - convolve_boundary_option option=convolve_option_extend_zero) { - convolve_rows_fixed(transposed_view(src),ker,transposed_view(dst),option); +void convolve_cols_fixed( + SrcView const& src_view, + Kernel const& kernel, + DstView const& dst_view, + convolve_boundary_option option = convolve_option_extend_zero) +{ + convolve_rows_fixed( + transposed_view(src_view), kernel, transposed_view(dst_view), option); } }} // namespace boost::gil