2
0
mirror of https://github.com/boostorg/gil.git synced 2026-01-27 06:52:11 +00:00

Clean up and refactor extension/numeric/convolve.hpp

- Tidy up formatting and code flow for readability
- Rename parameters for clarify, avoiding abbreviations
- Rename typedefs in CamelCase style instead of UPPER_CASE
- Add Doxygen comments and placeholders for documentation content to fill
This commit is contained in:
Mateusz Łoskot
2019-07-22 13:19:25 +02:00
parent 2c4529ed95
commit 055ee947a0

View File

@@ -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 <typename PixelAccum,typename SrcView,typename Kernel,typename DstView,typename Correlator>
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<typename SrcView::value_type>::type;
using PIXEL_DST_REF = typename pixel_proxy<typename DstView::value_type>::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<PixelAccum>(src,*ker.begin(),dst);
if(kernel.size() == 1)
{
// Reduces to a multiplication
view_multiplies_scalar<PixelAccum>(src_view, *kernel.begin(), dst_view);
return;
}
int width=src.width(),height=src.height();
PixelAccum acc_zero; pixel_zeros_t<PixelAccum>()(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<PixelAccum,PIXEL_DST_REF>()(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<typename SrcView::value_type>::type;
using DstPixelRef = typename pixel_proxy<typename DstView::value_type>::type;
int width = src_view.width(), height = src_view.height();
PixelAccum acc_zero;
pixel_zeros_t<PixelAccum>()(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<PixelAccum, DstPixelRef>()(acc_zero, dst_zero);
if (width < static_cast<int>(kernel.size()))
{
if (option == convolve_option_output_zero)
fill_pixels(dst_view, dst_zero);
}
else
{
std::vector<PixelAccum> buffer(width);
for(int rr=0;rr<height;++rr) {
assign_pixels(src.row_begin(rr),src.row_end(rr),&buffer.front());
typename DstView::x_iterator it_dst=dst.row_begin(rr);
if (option==convolve_option_output_zero)
std::fill_n(it_dst,ker.left_size(),dst_zero);
it_dst+=ker.left_size();
correlator(&buffer.front(),&buffer.front()+width+1-ker.size(),
ker.begin(),it_dst);
it_dst+=width+1-ker.size();
if (option==convolve_option_output_zero)
std::fill_n(it_dst,ker.right_size(),dst_zero);
for (int rr = 0; rr < height; ++rr)
{
assign_pixels(src_view.row_begin(rr), src_view.row_end(rr), &buffer.front());
typename DstView::x_iterator it_dst = dst_view.row_begin(rr);
if (option == convolve_option_output_zero)
std::fill_n(it_dst, kernel.left_size(), dst_zero);
it_dst += kernel.left_size();
correlator(&buffer.front(), &buffer.front() + width + 1 - kernel.size(),
kernel.begin(), it_dst);
it_dst += width + 1 - kernel.size();
if (option == convolve_option_output_zero)
std::fill_n(it_dst, kernel.right_size(), dst_zero);
}
}
} else {
std::vector<PixelAccum> buffer(width+ker.size()-1);
for(int rr=0;rr<height;++rr) {
PixelAccum* it_buffer=&buffer.front();
if (option==convolve_option_extend_padded) {
assign_pixels(src.row_begin(rr)-ker.left_size(),
src.row_end(rr)+ker.right_size(),
it_buffer);
} else if (option==convolve_option_extend_zero) {
std::fill_n(it_buffer,ker.left_size(),acc_zero);
it_buffer+=ker.left_size();
assign_pixels(src.row_begin(rr),src.row_end(rr),it_buffer);
it_buffer+=width;
std::fill_n(it_buffer,ker.right_size(),acc_zero);
} else if (option==convolve_option_extend_constant) {
PixelAccum filler;
pixel_assigns_t<PIXEL_SRC_REF,PixelAccum>()(*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<PIXEL_SRC_REF,PixelAccum>()(src.row_end(rr)[-1],filler);
std::fill_n(it_buffer,ker.right_size(),filler);
}
else
{
std::vector<PixelAccum> 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<SrcPixelRef, PixelAccum>()(*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<SrcPixelRef, PixelAccum>()(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 <typename PixelAccum>
class correlator_n {
class correlator_n
{
public:
correlator_n(std::size_t size) : size_(size) {}
template <typename SrcIterator, typename KernelIterator, typename DstIterator>
void operator()(
SrcIterator src_begin,
SrcIterator src_end,
KernelIterator kernel_begin,
DstIterator dst_begin)
{
correlate_pixels_n<PixelAccum>(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 <typename SrcIterator,typename KernelIterator,typename DstIterator>
void operator()(SrcIterator src_begin,SrcIterator src_end,
KernelIterator ker_begin,
DstIterator dst_begin) {
correlate_pixels_n<PixelAccum>(src_begin,src_end,ker_begin,_size,dst_begin);
}
};
template <std::size_t Size,typename PixelAccum>
struct correlator_k {
public:
template <typename SrcIterator,typename KernelIterator,typename DstIterator>
void operator()(SrcIterator src_begin,SrcIterator src_end,
KernelIterator ker_begin,
DstIterator dst_begin){
correlate_pixels_k<Size,PixelAccum>(src_begin,src_end,ker_begin,dst_begin);
std::size_t size_{0};
};
template <std::size_t Size, typename PixelAccum>
struct correlator_k
{
template <typename SrcIterator, typename KernelIterator, typename DstIterator>
void operator()(
SrcIterator src_begin,
SrcIterator src_end,
KernelIterator kernel_begin,
DstIterator dst_begin)
{
correlate_pixels_k<Size, PixelAccum>(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 <typename PixelAccum,typename SrcView,typename Kernel,typename DstView>
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<PixelAccum>(src,ker,dst,option,detail::correlator_n<PixelAccum>(ker.size()));
}
/// \ingroup ImageAlgorithms
///correlate a 1D variable-size kernel along the columns of an image
template <typename PixelAccum,typename SrcView,typename Kernel,typename DstView>
BOOST_FORCEINLINE
void correlate_cols(const SrcView& src, const Kernel& ker, const DstView& dst,
convolve_boundary_option option=convolve_option_extend_zero) {
correlate_rows<PixelAccum>(transposed_view(src),ker,transposed_view(dst),option);
}
/// \ingroup ImageAlgorithms
///convolve a 1D variable-size kernel along the rows of an image
template <typename PixelAccum,typename SrcView,typename Kernel,typename DstView>
BOOST_FORCEINLINE
void convolve_rows(const SrcView& src, const Kernel& ker, const DstView& dst,
convolve_boundary_option option=convolve_option_extend_zero) {
correlate_rows<PixelAccum>(src,reverse_kernel(ker),dst,option);
}
/// \ingroup ImageAlgorithms
///convolve a 1D variable-size kernel along the columns of an image
template <typename PixelAccum,typename SrcView,typename Kernel,typename DstView>
BOOST_FORCEINLINE
void convolve_cols(const SrcView& src, const Kernel& ker, const DstView& dst,
convolve_boundary_option option=convolve_option_extend_zero) {
convolve_rows<PixelAccum>(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 <typename PixelAccum,typename SrcView,typename Kernel,typename DstView>
BOOST_FORCEINLINE
void convolve(const SrcView& src, const Kernel& ker, const DstView& dst,
convolve_boundary_option option=convolve_option_extend_zero) {
convolve_rows<PixelAccum>(src, ker, dst, option);
convolve_cols<PixelAccum>(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 <typename PixelAccum, typename SrcView, typename Kernel, typename DstView>
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<PixelAccum>(
src_view, kernel, dst_view, option, detail::correlator_n<PixelAccum>(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 <typename PixelAccum, typename SrcView, typename Kernel, typename DstView>
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<PixelAccum>(
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 <typename PixelAccum, typename SrcView, typename Kernel, typename DstView>
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<PixelAccum>(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 <typename PixelAccum, typename SrcView, typename Kernel, typename DstView>
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<PixelAccum>(
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 <typename PixelAccum, typename SrcView, typename Kernel, typename DstView>
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<PixelAccum>(src_view, kernel, dst_view, option);
convolve_cols<PixelAccum>(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 <typename PixelAccum, typename SrcView, typename Kernel, typename DstView>
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<Kernel::static_size, PixelAccum>;
detail::correlate_rows_imp<PixelAccum>(
src, kernel, dst, option, correlator{});
detail::correlate_rows_impl<PixelAccum>(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 <typename PixelAccum,typename SrcView,typename Kernel,typename DstView>
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<PixelAccum>(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<PixelAccum>(
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 <typename PixelAccum,typename SrcView,typename Kernel,typename DstView>
/// \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 <typename PixelAccum, typename SrcView, typename Kernel, typename DstView>
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<PixelAccum>(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<PixelAccum>(src_view, reverse_kernel(kernel), dst_view, option);
}
/// \ingroup ImageAlgorithms
///convolve a 1D fixed-size kernel along the columns of an image
template <typename PixelAccum,typename SrcView,typename Kernel,typename DstView>
/// \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 <typename PixelAccum, typename SrcView, typename Kernel, typename DstView>
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<PixelAccum>(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<PixelAccum>(
transposed_view(src_view), kernel, transposed_view(dst_view), option);
}
}} // namespace boost::gil