10 #ifndef BOOST_GIL_IMAGE_PROCESSING_CONVOLVE_HPP
11 #define BOOST_GIL_IMAGE_PROCESSING_CONVOLVE_HPP
13 #include <boost/gil/image_processing/kernel.hpp>
15 #include <boost/gil/algorithm.hpp>
16 #include <boost/gil/image_view_factory.hpp>
17 #include <boost/gil/metafunctions.hpp>
18 #include <boost/gil/pixel_numeric_operations.hpp>
20 #include <boost/assert.hpp>
25 #include <type_traits>
28 namespace boost {
namespace gil {
58 void correlate_rows_impl(
59 SrcView
const& src_view,
61 DstView
const& dst_view,
62 boundary_option option,
63 Correlator correlator)
65 BOOST_ASSERT(src_view.dimensions() == dst_view.dimensions());
66 BOOST_ASSERT(kernel.size() != 0);
68 if(kernel.size() == 1)
71 view_multiplies_scalar<PixelAccum>(src_view, *kernel.begin(), dst_view);
75 using src_pixel_ref_t =
typename pixel_proxy<typename SrcView::value_type>::type;
76 using dst_pixel_ref_t =
typename pixel_proxy<typename DstView::value_type>::type;
77 using x_coord_t =
typename SrcView::x_coord_t;
78 using y_coord_t =
typename SrcView::y_coord_t;
80 x_coord_t
const width = src_view.width();
81 y_coord_t
const height = src_view.height();
86 pixel_zeros_t<PixelAccum>()(acc_zero);
87 if (option == boundary_option::output_ignore || option == boundary_option::output_zero)
89 typename DstView::value_type dst_zero;
90 pixel_assigns_t<PixelAccum, dst_pixel_ref_t>()(acc_zero, dst_zero);
91 if (width <
static_cast<x_coord_t
>(kernel.size()))
93 if (option == boundary_option::output_zero)
98 std::vector<PixelAccum> buffer(width);
99 for (y_coord_t y = 0; y < height; ++y)
101 assign_pixels(src_view.row_begin(y), src_view.row_end(y), &buffer.front());
102 typename DstView::x_iterator it_dst = dst_view.row_begin(y);
103 if (option == boundary_option::output_zero)
104 std::fill_n(it_dst, kernel.left_size(), dst_zero);
105 it_dst += kernel.left_size();
106 correlator(&buffer.front(), &buffer.front() + width + 1 - kernel.size(),
107 kernel.begin(), it_dst);
108 it_dst += width + 1 - kernel.size();
109 if (option == boundary_option::output_zero)
110 std::fill_n(it_dst, kernel.right_size(), dst_zero);
116 std::vector<PixelAccum> buffer(width + kernel.size() - 1);
117 for (y_coord_t y = 0; y < height; ++y)
119 PixelAccum *it_buffer = &buffer.front();
120 if (option == boundary_option::extend_padded)
123 src_view.row_begin(y) - kernel.left_size(),
124 src_view.row_end(y) + kernel.right_size(),
127 else if (option == boundary_option::extend_zero)
129 std::fill_n(it_buffer, kernel.left_size(), acc_zero);
130 it_buffer += kernel.left_size();
131 assign_pixels(src_view.row_begin(y), src_view.row_end(y), it_buffer);
133 std::fill_n(it_buffer, kernel.right_size(), acc_zero);
135 else if (option == boundary_option::extend_constant)
138 pixel_assigns_t<src_pixel_ref_t, PixelAccum>()(*src_view.row_begin(y), filler);
139 std::fill_n(it_buffer, kernel.left_size(), filler);
140 it_buffer += kernel.left_size();
141 assign_pixels(src_view.row_begin(y), src_view.row_end(y), it_buffer);
143 pixel_assigns_t<src_pixel_ref_t, PixelAccum>()(src_view.row_end(y)[-1], filler);
144 std::fill_n(it_buffer, kernel.right_size(), filler);
148 &buffer.front(), &buffer.front() + width,
150 dst_view.row_begin(y));
158 template <
typename PixelAccum>
164 template <
typename SrcIterator,
typename KernelIterator,
typename DstIterator>
166 SrcIterator src_begin,
168 KernelIterator kernel_begin,
169 DstIterator dst_begin)
171 correlate_pixels_n<PixelAccum>(src_begin, src_end, kernel_begin, size_, dst_begin);
175 std::size_t size_{0};
181 template <std::
size_t Size,
typename PixelAccum>
184 template <
typename SrcIterator,
typename KernelIterator,
typename DstIterator>
186 SrcIterator src_begin,
188 KernelIterator kernel_begin,
189 DstIterator dst_begin)
191 correlate_pixels_k<Size, PixelAccum>(src_begin, src_end, kernel_begin, dst_begin);
205 template <
typename PixelAccum,
typename SrcView,
typename Kernel,
typename DstView>
208 SrcView
const& src_view,
209 Kernel
const& kernel,
210 DstView
const& dst_view,
211 boundary_option option = boundary_option::extend_zero)
213 detail::correlate_rows_impl<PixelAccum>(
225 template <
typename PixelAccum,
typename SrcView,
typename Kernel,
typename DstView>
228 SrcView
const& src_view,
229 Kernel
const& kernel,
230 DstView
const& dst_view,
231 boundary_option option = boundary_option::extend_zero)
233 correlate_rows<PixelAccum>(
234 transposed_view(src_view), kernel, transposed_view(dst_view), option);
244 template <
typename PixelAccum,
typename SrcView,
typename Kernel,
typename DstView>
247 SrcView
const& src_view,
248 Kernel
const& kernel,
249 DstView
const& dst_view,
250 boundary_option option = boundary_option::extend_zero)
252 correlate_rows<PixelAccum>(src_view, reverse_kernel(kernel), dst_view, option);
263 template <
typename PixelAccum,
typename SrcView,
typename Kernel,
typename DstView>
266 SrcView
const& src_view,
267 Kernel
const& kernel,
268 DstView
const& dst_view,
269 boundary_option option = boundary_option::extend_zero)
271 convolve_rows<PixelAccum>(
272 transposed_view(src_view), kernel, transposed_view(dst_view), option);
282 template <
typename PixelAccum,
typename SrcView,
typename Kernel,
typename DstView>
284 void correlate_rows_fixed(
285 SrcView
const& src_view,
286 Kernel
const& kernel,
287 DstView
const& dst_view,
288 boundary_option option = boundary_option::extend_zero)
290 using correlator = detail::correlator_k<Kernel::static_size, PixelAccum>;
291 detail::correlate_rows_impl<PixelAccum>(src_view, kernel, dst_view, option, correlator{});
302 template <
typename PixelAccum,
typename SrcView,
typename Kernel,
typename DstView>
304 void correlate_cols_fixed(
305 SrcView
const& src_view,
306 Kernel
const& kernel,
307 DstView
const& dst_view,
308 boundary_option option = boundary_option::extend_zero)
310 correlate_rows_fixed<PixelAccum>(
311 transposed_view(src_view), kernel, transposed_view(dst_view), option);
321 template <
typename PixelAccum,
typename SrcView,
typename Kernel,
typename DstView>
323 void convolve_rows_fixed(
324 SrcView
const& src_view,
325 Kernel
const& kernel,
326 DstView
const& dst_view,
327 boundary_option option = boundary_option::extend_zero)
329 correlate_rows_fixed<PixelAccum>(src_view, reverse_kernel(kernel), dst_view, option);
340 template <
typename PixelAccum,
typename SrcView,
typename Kernel,
typename DstView>
342 void convolve_cols_fixed(
343 SrcView
const& src_view,
344 Kernel
const& kernel,
345 DstView
const& dst_view,
346 boundary_option option = boundary_option::extend_zero)
348 convolve_rows_fixed<PixelAccum>(
349 transposed_view(src_view), kernel, transposed_view(dst_view), option);
363 template <
typename PixelAccum,
typename SrcView,
typename Kernel,
typename DstView>
366 SrcView
const& src_view,
367 Kernel
const& kernel,
368 DstView
const& dst_view,
369 boundary_option option = boundary_option::extend_zero)
371 convolve_rows<PixelAccum>(src_view, kernel, dst_view, option);
372 convolve_cols<PixelAccum>(dst_view, kernel, dst_view, option);
375 template <
typename SrcView,
typename DstView,
typename Kernel>
376 void convolve_2d_impl(SrcView
const& src_view, DstView
const& dst_view, Kernel
const& kernel)
378 int flip_ker_row, flip_ker_col, row_boundary, col_boundary;
380 for (std::ptrdiff_t view_row = 0; view_row < src_view.height(); ++view_row)
382 for (std::ptrdiff_t view_col = 0; view_col < src_view.width(); ++view_col)
385 for (std::size_t kernel_row = 0; kernel_row < kernel.size(); ++kernel_row)
387 flip_ker_row = kernel.size() - 1 - kernel_row;
389 for (std::size_t kernel_col = 0; kernel_col < kernel.size(); ++kernel_col)
391 flip_ker_col = kernel.size() - 1 - kernel_col;
394 row_boundary = view_row + (kernel.center_y() - flip_ker_row);
395 col_boundary = view_col + (kernel.center_x() - flip_ker_col);
398 if (row_boundary >= 0 && row_boundary < src_view.height() &&
399 col_boundary >= 0 && col_boundary < src_view.width())
402 src_view(col_boundary, row_boundary)[0] *
403 kernel.at(flip_ker_col, flip_ker_row);
407 dst_view(view_col, view_row) = aux_total;
419 template <
typename SrcView,
typename DstView,
typename Kernel>
420 void convolve_2d(SrcView
const& src_view, Kernel
const& kernel, DstView
const& dst_view)
422 BOOST_ASSERT(src_view.dimensions() == dst_view.dimensions());
423 BOOST_ASSERT(kernel.size() != 0);
425 gil_function_requires<ImageViewConcept<SrcView>>();
426 gil_function_requires<MutableImageViewConcept<DstView>>();
427 static_assert(color_spaces_are_compatible
429 typename color_space_type<SrcView>::type,
430 typename color_space_type<DstView>::type
431 >::value,
"Source and destination views must have pixels with the same color space");
433 for (std::size_t i = 0; i < src_view.num_channels(); i++)
435 detail::convolve_2d_impl(
436 nth_channel_view(src_view, i),
437 nth_channel_view(dst_view, i),
Provides functionality for performing 1D correlation between the kernel and a buffer storing row pixe...
Definition: convolve.hpp:160
BOOST_FORCEINLINE void fill_pixels(View const &view, Value const &value)
std::fill for image views
Definition: algorithm.hpp:420
defined(BOOST_NO_CXX17_HDR_MEMORY_RESOURCE)
Definition: algorithm.hpp:36
Provides functionality for performing 1D correlation between the kernel and a buffer storing row pixe...
Definition: convolve.hpp:183
Returns an integral constant type specifying the number of elements in a color base.
Definition: color_base_algorithm.hpp:42