diff --git a/test/core/image_processing/convolve.cpp b/test/core/image_processing/convolve.cpp index c3ecb431d8..8a15255ec7 100644 --- a/test/core/image_processing/convolve.cpp +++ b/test/core/image_processing/convolve.cpp @@ -1,6 +1,7 @@ // // Copyright 2019-2020 Mateusz Loskot // Copyright 2021 Pranam Lashkari +// Copyright 2021 Prathamesh Tagore // // Distributed under the Boost Software License, Version 1.0 // See accompanying file LICENSE_1_0.txt or copy at @@ -101,7 +102,6 @@ struct test_image_5x5_kernel_3x3_identity auto const kernel = fixture::create_kernel({0, 0, 0, 0, 1, 0, 0, 0, 0}); gil::detail::convolve_1d(gil::const_view(img_out), kernel, gil::view(img_out)); - // TODO: Test different boundary options BOOST_TEST(gil::equal_pixels(gil::const_view(img), gil::const_view(img_out))); } @@ -111,6 +111,199 @@ struct test_image_5x5_kernel_3x3_identity } }; +// Convention used for naming variables : +// 1. img : Original image which is to be used for testing. +// 2. img_out : Output image obtained after applying 1D row and column convolution using library +// function. +// 3. img_expected_row : Expected image after applying row convolution on "img". +// 4. img_expected_col : Expected image after applying column convolution on "img_expected_row". + +struct test_image_5x5_kernel_1x9_boundary_extend_zero +{ + template + void operator()(Image const&) + { + using image_t = Image; + using pixel_t = typename image_t::value_type; + using channel_t = typename gil::channel_type::type; + auto img = fixture::generate_image(5, 5, fixture::random_value{}); + auto img_view = gil::view(img); + image_t img_out(img), img_expected_row(img_view.width(), img_view.height()); + image_t img_expected_col(img_view.width(), img_view.height()); + unsigned int const kernel_shift_offset = 2; + + fixture::row_conv1D_offset_img_generator(img_view, gil::view(img_expected_row), + kernel_shift_offset); + fixture::col_conv1D_offset_img_generator(gil::view(img_expected_row), + gil::view(img_expected_col), kernel_shift_offset); + + auto const kernel_shift_by_two = fixture::create_kernel( + {0, 0, 0, 0, 0, 0, 1, 0, 0}); + gil::detail::convolve_1d(gil::const_view(img), kernel_shift_by_two, + gil::view(img_out), boost::gil::boundary_option::extend_zero); + + BOOST_TEST(gil::equal_pixels(gil::const_view(img_out), gil::const_view(img_expected_col))); + } + static void run() + { + boost::mp11::mp_for_each( + test_image_5x5_kernel_1x9_boundary_extend_zero{}); + } +}; + +struct test_image_5x5_kernel_1x9_boundary_extend_constant +{ + template + void operator()(Image const&) + { + using image_t = Image; + using pixel_t = typename image_t::value_type; + using channel_t = typename gil::channel_type::type; + auto img = fixture::generate_image(5, 5, fixture::random_value{}); + auto img_view = gil::view(img); + image_t img_out(img), img_expected_row(img); + unsigned int const kernel_shift_offset = 2; + + fixture::row_conv1D_offset_img_generator(img_view, gil::view(img_expected_row), + kernel_shift_offset); + fixture::row_conv1D_offset_img_generator(img_view, gil::view(img_expected_row), + 1, 0, 0, img_view.height(), 2); + + image_t img_expected_col(img_expected_row); + + fixture::col_conv1D_offset_img_generator(gil::view(img_expected_row), + gil::view(img_expected_col), kernel_shift_offset); + fixture::col_conv1D_offset_img_generator(gil::view(img_expected_row), + gil::view(img_expected_col), 1, 0, 0, 2, img_view.width()); + + auto const kernel_shift_by_two = fixture::create_kernel({0, 0, 0, 0, 0, 0, 1, 0, 0}); + gil::detail::convolve_1d(gil::const_view(img), kernel_shift_by_two, + gil::view(img_out), boost::gil::boundary_option::extend_constant); + + BOOST_TEST(gil::equal_pixels(gil::const_view(img_out), gil::const_view(img_expected_col))); + } + static void run() + { + boost::mp11::mp_for_each( + test_image_5x5_kernel_1x9_boundary_extend_constant{}); + } +}; + +struct test_image_5x5_kernel_1x3_boundary_output_zero +{ + template + void operator()(Image const&) + { + using image_t = Image; + using pixel_t = typename image_t::value_type; + using channel_t = typename gil::channel_type::type; + auto img = fixture::generate_image(5, 5, fixture::random_value{}); + auto img_view = gil::view(img); + image_t img_out(img), img_expected_row(img_view.width(), img_view.height()); + image_t img_expected_col(img_view.width(), img_view.height()); + unsigned int const kernel_shift_offset = 1; + + fixture::row_conv1D_offset_img_generator(img_view, gil::view(img_expected_row), + kernel_shift_offset, 0, 0, img_view.height(), img_view.width() - 1); + fixture::col_conv1D_offset_img_generator(gil::view(img_expected_row), + gil::view(img_expected_col), kernel_shift_offset, 0, 0, img_view.height() - 1, + img_view.width()); + + auto const kernel_shift_by_one = fixture::create_kernel({0, 0, 1}); + gil::detail::convolve_1d(gil::const_view(img), kernel_shift_by_one, + gil::view(img_out), boost::gil::boundary_option::output_zero); + + BOOST_TEST(gil::equal_pixels(gil::const_view(img_out), gil::const_view(img_expected_col))); + } + static void run() + { + boost::mp11::mp_for_each( + test_image_5x5_kernel_1x3_boundary_output_zero{}); + } +}; + +struct test_image_5x5_kernel_1x3_boundary_output_ignore +{ + template + void operator()(Image const&) + { + using image_t = Image; + using pixel_t = typename image_t::value_type; + using channel_t = typename gil::channel_type::type; + auto img = fixture::generate_image(5, 5, fixture::random_value{}); + auto img_view = gil::view(img); + image_t img_out(img), img_expected_row(img); + unsigned int const kernel_shift_offset = 1; + + fixture::row_conv1D_offset_img_generator(img_view, gil::view(img_expected_row), + kernel_shift_offset, 0, 0, img_view.height(), img_view.width() - 1); + + image_t img_expected_col(img_expected_row); + + fixture::col_conv1D_offset_img_generator(gil::view(img_expected_row), + gil::view(img_expected_col), kernel_shift_offset, 0, 0, img_view.height() - 1, + img_view.width()); + + auto const kernel_shift_by_one = fixture::create_kernel({0, 0, 1}); + gil::detail::convolve_1d(gil::const_view(img), kernel_shift_by_one, + gil::view(img_out), gil::boundary_option::output_ignore); + + BOOST_TEST(gil::equal_pixels(gil::const_view(img_out), gil::const_view(img_expected_col))); + } + static void run() + { + boost::mp11::mp_for_each( + test_image_5x5_kernel_1x3_boundary_output_ignore{}); + } +}; + +struct test_image_5x5_kernel_1x3_boundary_extend_padded +{ + template + void operator()(Image const&) + { + using image_t = Image; + using pixel_t = typename image_t::value_type; + using channel_t = typename gil::channel_type::type; + auto img = fixture::generate_image(5, 5, fixture::random_value{}); + auto img_view = gil::view(img); + image_t img_out(img), img_expected_row(img); + unsigned int const kernel_shift_offset = 1; + + fixture::row_conv1D_offset_img_generator(img_view, gil::view(img_expected_row), + kernel_shift_offset); + + image_t img_expected_col(img_expected_row); + + fixture::col_conv1D_offset_img_generator(gil::view(img_expected_row), + gil::view(img_expected_col), kernel_shift_offset); + + auto const kernel_shift_by_one = fixture::create_kernel({0, 0, 1}); + gil::detail::convolve_1d(gil::const_view(img), kernel_shift_by_one, + gil::view(img_out), gil::boundary_option::extend_padded); + + // First row and first column of "img_out" and "img_expected_col" are intentionally made + // similar. + auto img_out_it1 = gil::view(img_out).col_begin(0); + auto img_expected_col_it1 = gil::view(img_expected_col).col_begin(0); + for (std::ptrdiff_t x = 0; x < gil::view(img_out).width(); ++x) + img_expected_col_it1[x] = img_out_it1[x]; + + auto img_out_it2 = gil::view(img_out).row_begin(0); + auto img_expected_col_it2 = gil::view(img_expected_col).row_begin(0); + for (std::ptrdiff_t y = 0; y < gil::view(img_out).height(); ++y) + img_expected_col_it2[y] = img_out_it2[y]; + + BOOST_TEST(gil::equal_pixels(gil::const_view(img_out), gil::const_view(img_expected_col))); + + } + static void run() + { + boost::mp11::mp_for_each( + test_image_5x5_kernel_1x3_boundary_extend_padded{}); + } +}; + int main() { test_image_1x1_kernel_1x1_identity::run(); @@ -118,5 +311,10 @@ int main() test_image_3x3_kernel_3x3_identity::run(); test_image_5x5_kernel_3x3_identity::run(); + test_image_5x5_kernel_1x9_boundary_extend_zero::run(); + test_image_5x5_kernel_1x9_boundary_extend_constant::run(); + test_image_5x5_kernel_1x3_boundary_output_zero::run(); + test_image_5x5_kernel_1x3_boundary_output_ignore::run(); + test_image_5x5_kernel_1x3_boundary_extend_padded::run(); return ::boost::report_errors(); } diff --git a/test/core/image_processing/convolve_cols.cpp b/test/core/image_processing/convolve_cols.cpp index c78f181b97..579a73092e 100644 --- a/test/core/image_processing/convolve_cols.cpp +++ b/test/core/image_processing/convolve_cols.cpp @@ -1,6 +1,7 @@ // // Copyright 2019-2020 Mateusz Loskot // Copyright 2021 Pranam Lashkari +// Copyright 2021 Prathamesh Tagore // // Distributed under the Boost Software License, Version 1.0 // See accompanying file LICENSE_1_0.txt or copy at @@ -65,10 +66,169 @@ struct test_image_1x1_kernel_3x3_identity } }; +struct test_image_5x5_kernel_1x9_boundary_extend_zero +{ + template + void operator()(Image const&) + { + using image_t = Image; + using pixel_t = typename image_t::value_type; + using channel_t = typename gil::channel_type::type; + auto img = fixture::generate_image(5, 5, fixture::random_value{}); + auto img_view = gil::view(img); + image_t img_out(img), img_expected(img_view.width(), img_view.height()); + unsigned int const kernel_shift_offset = 2; + + fixture::col_conv1D_offset_img_generator(img_view, gil::view(img_expected), + kernel_shift_offset); + + auto const kernel_shift_by_two = fixture::create_kernel( + {0, 0, 0, 0, 0, 0, 1, 0, 0}); + gil::convolve_cols(gil::const_view(img), kernel_shift_by_two, + gil::view(img_out), gil::boundary_option::extend_zero); + BOOST_TEST(gil::equal_pixels(gil::const_view(img_out), gil::const_view(img_expected))); + } + static void run() + { + boost::mp11::mp_for_each( + test_image_5x5_kernel_1x9_boundary_extend_zero{}); + } +}; + +struct test_image_5x5_kernel_1x9_boundary_extend_constant +{ + template + void operator()(Image const&) + { + using image_t = Image; + using pixel_t = typename image_t::value_type; + using channel_t = typename gil::channel_type::type; + auto img = fixture::generate_image(5, 5, fixture::random_value{}); + auto img_view = gil::view(img); + image_t img_out(img), img_expected(img); + unsigned int const kernel_shift_offset = 2; + + fixture::col_conv1D_offset_img_generator(img_view, gil::view(img_expected), + kernel_shift_offset); + fixture::col_conv1D_offset_img_generator(img_view, gil::view(img_expected), + 1, 0, 0, 2, img_view.width()); + + auto const kernel_shift_by_two = fixture::create_kernel( + {0, 0, 0, 0, 0, 0, 1, 0, 0}); + gil::convolve_cols(gil::const_view(img), kernel_shift_by_two, + gil::view(img_out), gil::boundary_option::extend_constant); + + BOOST_TEST(gil::equal_pixels(gil::const_view(img_out), gil::const_view(img_expected))); + } + static void run() + { + boost::mp11::mp_for_each( + test_image_5x5_kernel_1x9_boundary_extend_constant{}); + } +}; + +struct test_image_5x5_kernel_1x3_boundary_output_zero +{ + template + void operator()(Image const&) + { + using image_t = Image; + using pixel_t = typename image_t::value_type; + using channel_t = typename gil::channel_type::type; + auto img = fixture::generate_image(5, 5, fixture::random_value{}); + auto img_view = gil::view(img); + image_t img_out(img), img_expected(img_view.width(), img_view.height()); + unsigned int const kernel_shift_offset = 1; + + fixture::col_conv1D_offset_img_generator(img_view, gil::view(img_expected), + kernel_shift_offset, 0, 0, img_view.height() - 1, img_view.width()); + + auto const kernel_shift_by_one = fixture::create_kernel({0, 0, 1}); + gil::convolve_cols(gil::const_view(img), kernel_shift_by_one, + gil::view(img_out), gil::boundary_option::output_zero); + + BOOST_TEST(gil::equal_pixels(gil::const_view(img_out), gil::const_view(img_expected))); + } + static void run() + { + boost::mp11::mp_for_each( + test_image_5x5_kernel_1x3_boundary_output_zero{}); + } +}; + +struct test_image_5x5_kernel_1x3_boundary_output_ignore +{ + template + void operator()(Image const&) + { + using image_t = Image; + using pixel_t = typename image_t::value_type; + using channel_t = typename gil::channel_type::type; + auto img = fixture::generate_image(5, 5, fixture::random_value{}); + auto img_view = gil::view(img); + image_t img_out(img), img_expected(img); + unsigned int const kernel_shift_offset = 1; + + fixture::col_conv1D_offset_img_generator(img_view, gil::view(img_expected), + kernel_shift_offset, 0, 0, img_view.height() - 1, img_view.width()); + + auto const kernel_shift_by_one = fixture::create_kernel({0, 0, 1}); + gil::convolve_cols(gil::const_view(img), kernel_shift_by_one, + gil::view(img_out), gil::boundary_option::output_ignore); + + BOOST_TEST(gil::equal_pixels(gil::const_view(img_out), gil::const_view(img_expected))); + } + static void run() + { + boost::mp11::mp_for_each( + test_image_5x5_kernel_1x3_boundary_output_ignore{}); + } +}; + +struct test_image_5x5_kernel_1x3_boundary_extend_padded +{ + template + void operator()(Image const&) + { + using image_t = Image; + using pixel_t = typename image_t::value_type; + using channel_t = typename gil::channel_type::type; + auto img = fixture::generate_image(5, 5, fixture::random_value{}); + auto img_view = gil::view(img); + image_t img_out(img), img_expected(img); + unsigned int const kernel_shift_offset = 1; + + fixture::col_conv1D_offset_img_generator(img_view, gil::view(img_expected), + kernel_shift_offset); + + auto const kernel_shift_by_one = fixture::create_kernel({0, 0, 1}); + gil::convolve_cols(gil::const_view(img), kernel_shift_by_one, + gil::view(img_out), gil::boundary_option::extend_padded); + + // First column of "img_out" and "img_expected" is intentionally made similar. + auto img_out_it = gil::view(img_out).row_begin(0); + auto img_expected_it = gil::view(img_expected).row_begin(0); + for (std::ptrdiff_t y = 0; y < gil::view(img_out).height(); ++y) + img_expected_it[y] = img_out_it[y]; + + BOOST_TEST(gil::equal_pixels(gil::const_view(img_out), gil::const_view(img_expected))); + } + static void run() + { + boost::mp11::mp_for_each( + test_image_5x5_kernel_1x3_boundary_extend_padded{}); + } +}; + int main() { test_image_1x1_kernel_1x1_identity::run(); test_image_1x1_kernel_3x3_identity::run(); + test_image_5x5_kernel_1x9_boundary_extend_zero::run(); + test_image_5x5_kernel_1x9_boundary_extend_constant::run(); + test_image_5x5_kernel_1x3_boundary_output_zero::run(); + test_image_5x5_kernel_1x3_boundary_output_ignore::run(); + test_image_5x5_kernel_1x3_boundary_extend_padded::run(); return ::boost::report_errors(); } diff --git a/test/core/image_processing/convolve_rows.cpp b/test/core/image_processing/convolve_rows.cpp index d4a99fcc8a..5e745aa32c 100644 --- a/test/core/image_processing/convolve_rows.cpp +++ b/test/core/image_processing/convolve_rows.cpp @@ -1,6 +1,7 @@ // // Copyright 2019-2020 Mateusz Loskot // Copyright 2021 Pranam Lashkari +// Copyright 2021 Prathamesh Tagore // // Distributed under the Boost Software License, Version 1.0 // See accompanying file LICENSE_1_0.txt or copy at @@ -65,10 +66,169 @@ struct test_image_1x1_kernel_3x3_identity } }; +struct test_image_5x5_kernel_1x9_boundary_extend_zero +{ + template + void operator()(Image const&) + { + using image_t = Image; + using pixel_t = typename image_t::value_type; + using channel_t = typename gil::channel_type::type; + auto img = fixture::generate_image(5, 5, fixture::random_value{}); + auto img_view = gil::view(img); + image_t img_out(img), img_expected(img_view.width(), img_view.height()); + unsigned int const kernel_shift_offset = 2; + + fixture::row_conv1D_offset_img_generator(img_view, gil::view(img_expected), + kernel_shift_offset); + + auto const kernel_shift_by_two = fixture::create_kernel( + {0, 0, 0, 0, 0, 0, 1, 0, 0}); + gil::convolve_rows(gil::const_view(img), kernel_shift_by_two, + gil::view(img_out), gil::boundary_option::extend_zero); + BOOST_TEST(gil::equal_pixels(gil::const_view(img_out), gil::const_view(img_expected))); + } + static void run() + { + boost::mp11::mp_for_each( + test_image_5x5_kernel_1x9_boundary_extend_zero{}); + } +}; + +struct test_image_5x5_kernel_1x9_boundary_extend_constant +{ + template + void operator()(Image const&) + { + using image_t = Image; + using pixel_t = typename image_t::value_type; + using channel_t = typename gil::channel_type::type; + auto img = fixture::generate_image(5, 5, fixture::random_value{}); + auto img_view = gil::view(img); + image_t img_out(img), img_expected(img); + unsigned int const kernel_shift_offset = 2; + + fixture::row_conv1D_offset_img_generator(img_view, gil::view(img_expected), + kernel_shift_offset); + fixture::row_conv1D_offset_img_generator(img_view, gil::view(img_expected), + 1, 0, 0, img_view.height(), 2); + + auto const kernel_shift_by_two = fixture::create_kernel( + {0, 0, 0, 0, 0, 0, 1, 0, 0}); + gil::convolve_rows(gil::const_view(img), kernel_shift_by_two, + gil::view(img_out), gil::boundary_option::extend_constant); + + BOOST_TEST(gil::equal_pixels(gil::const_view(img_out), gil::const_view(img_expected))); + } + static void run() + { + boost::mp11::mp_for_each( + test_image_5x5_kernel_1x9_boundary_extend_constant{}); + } +}; + +struct test_image_5x5_kernel_1x3_boundary_output_zero +{ + template + void operator()(Image const&) + { + using image_t = Image; + using pixel_t = typename image_t::value_type; + using channel_t = typename gil::channel_type::type; + auto img = fixture::generate_image(5, 5, fixture::random_value{}); + auto img_view = gil::view(img); + image_t img_out(img), img_expected(img_view.width(), img_view.height()); + unsigned int const kernel_shift_offset = 1; + + fixture::row_conv1D_offset_img_generator(img_view, gil::view(img_expected), + kernel_shift_offset, 0, 0, img_view.height(), img_view.width() - 1); + + auto const kernel_shift_by_one = fixture::create_kernel({0, 0, 1}); + gil::convolve_rows(gil::const_view(img), kernel_shift_by_one, + gil::view(img_out), gil::boundary_option::output_zero); + + BOOST_TEST(gil::equal_pixels(gil::const_view(img_out), gil::const_view(img_expected))); + } + static void run() + { + boost::mp11::mp_for_each( + test_image_5x5_kernel_1x3_boundary_output_zero{}); + } +}; + +struct test_image_5x5_kernel_1x3_boundary_output_ignore +{ + template + void operator()(Image const&) + { + using image_t = Image; + using pixel_t = typename image_t::value_type; + using channel_t = typename gil::channel_type::type; + auto img = fixture::generate_image(5, 5, fixture::random_value{}); + auto img_view = gil::view(img); + image_t img_out(img), img_expected(img); + unsigned int const kernel_shift_offset = 1; + + fixture::row_conv1D_offset_img_generator(img_view, gil::view(img_expected), + kernel_shift_offset, 0, 0, img_view.height(), img_view.width() - 1); + + auto const kernel_shift_by_one = fixture::create_kernel({0, 0, 1}); + gil::convolve_rows(gil::const_view(img), kernel_shift_by_one, + gil::view(img_out), gil::boundary_option::output_ignore); + + BOOST_TEST(gil::equal_pixels(gil::const_view(img_out), gil::const_view(img_expected))); + } + static void run() + { + boost::mp11::mp_for_each( + test_image_5x5_kernel_1x3_boundary_output_ignore{}); + } +}; + +struct test_image_5x5_kernel_1x3_boundary_extend_padded +{ + template + void operator()(Image const&) + { + using image_t = Image; + using pixel_t = typename image_t::value_type; + using channel_t = typename gil::channel_type::type; + auto img = fixture::generate_image(5, 5, fixture::random_value{}); + auto img_view = gil::view(img); + image_t img_out(img), img_expected(img); + unsigned int const kernel_shift_offset = 1; + + fixture::row_conv1D_offset_img_generator(img_view, gil::view(img_expected), + kernel_shift_offset); + + auto const kernel_shift_by_one = fixture::create_kernel({0, 0, 1}); + gil::convolve_rows(gil::const_view(img), kernel_shift_by_one, + gil::view(img_out), gil::boundary_option::extend_padded); + + // First row of "img_out" and "img_expected" is intentionally made similar. + auto img_out_it = gil::view(img_out).col_begin(0); + auto img_expected_it = gil::view(img_expected).col_begin(0); + for (std::ptrdiff_t x = 0; x < gil::view(img_out).width(); ++x) + img_expected_it[x] = img_out_it[x]; + + BOOST_TEST(gil::equal_pixels(gil::const_view(img_out), gil::const_view(img_expected))); + } + static void run() + { + boost::mp11::mp_for_each( + test_image_5x5_kernel_1x3_boundary_extend_padded{}); + } +}; + int main() { test_image_1x1_kernel_1x1_identity::run(); test_image_1x1_kernel_3x3_identity::run(); + test_image_5x5_kernel_1x9_boundary_extend_zero::run(); + test_image_5x5_kernel_1x9_boundary_extend_constant::run(); + test_image_5x5_kernel_1x3_boundary_output_zero::run(); + test_image_5x5_kernel_1x3_boundary_output_ignore::run(); + test_image_5x5_kernel_1x3_boundary_extend_padded::run(); return ::boost::report_errors(); } diff --git a/test/core/image_processing/test_fixture.hpp b/test/core/image_processing/test_fixture.hpp index b49fb6cd76..c4916aa87a 100644 --- a/test/core/image_processing/test_fixture.hpp +++ b/test/core/image_processing/test_fixture.hpp @@ -1,6 +1,7 @@ // // Copyright 2019 Mateusz Loskot // Copyright 2021 Pranam Lashkari +// Copyright 2021 Prathamesh Tagore // // Distributed under the Boost Software License, Version 1.0 // See accompanying file LICENSE_1_0.txt or copy at @@ -28,4 +29,58 @@ auto create_kernel(std::initializer_list const& values) return kernel; } +// Adds an offset similar to 1D row convolution with kernel {0, 0, 0, 0, 0, 0, 1, 0, 0} +// having its anchor point at 5th element and boundary option as "extend_zero". +template +void row_conv1D_offset_img_generator(SrcView src_view, DstView dst_view, int const offset, + std::ptrdiff_t start_row = 0, std::ptrdiff_t start_col = 0, std::ptrdiff_t end_row = -1, + std::ptrdiff_t end_col = -1) +{ + BOOST_ASSERT(src_view.dimensions() == dst_view.dimensions()); + static_assert(color_spaces_are_compatible + < + typename color_space_type::type, + typename color_space_type::type + >::value, "Source and destination views must have pixels with the same color space"); + + if (end_row == -1) + end_row = src_view.height(); + if (end_col == -1) + end_col = src_view.width(); + for (std::ptrdiff_t y = start_row; y < end_row; ++y) + { + auto src_it = src_view.row_begin(y); + auto dst_it = dst_view.row_begin(y); + for (std::ptrdiff_t x = offset + start_col; x < end_col; ++x) + dst_it[x] = src_it[x - offset]; + } +} + +// Adds an offset similar to 1D column convolution with kernel {0, 0, 0, 0, 0, 0, 1, 0, 0} +// having its anchor point at 5th element and boundary option as "extend_zero". +template +void col_conv1D_offset_img_generator(SrcView src_view, DstView dst_view, int const offset, + std::ptrdiff_t start_row = 0, std::ptrdiff_t start_col = 0, std::ptrdiff_t end_row = -1, + std::ptrdiff_t end_col = -1) +{ + BOOST_ASSERT(src_view.dimensions() == dst_view.dimensions()); + static_assert(color_spaces_are_compatible + < + typename color_space_type::type, + typename color_space_type::type + >::value, "Source and destination views must have pixels with the same color space"); + + if (end_row == -1) + end_row = src_view.height(); + if (end_col == -1) + end_col = src_view.width(); + for (std::ptrdiff_t x = start_col; x < end_col; ++x) + { + auto src_it = src_view.col_begin(x); + auto dst_it = dst_view.col_begin(x); + for (std::ptrdiff_t y = offset + start_row; y < end_row; ++y) + dst_it[y] = src_it[y - offset]; + } +} + }}}} // namespace boost::gil::test::fixture