From 5c3d981597515ec8509c5dc250bbbef015bf76b0 Mon Sep 17 00:00:00 2001 From: laxsuryavanshi Date: Tue, 10 Mar 2020 01:16:59 +0530 Subject: [PATCH 1/3] Added feature 'Gaussian Filter' --- example/gaussian_blur.cpp | 24 ++++++++ include/boost/gil/image_processing/filter.hpp | 26 ++++++++ .../boost/gil/image_processing/numeric.hpp | 21 +++++++ test/core/image_processing/gaussian_blur.cpp | 60 +++++++++++++++++++ 4 files changed, 131 insertions(+) create mode 100644 example/gaussian_blur.cpp create mode 100644 test/core/image_processing/gaussian_blur.cpp diff --git a/example/gaussian_blur.cpp b/example/gaussian_blur.cpp new file mode 100644 index 0000000000..24b2d21a37 --- /dev/null +++ b/example/gaussian_blur.cpp @@ -0,0 +1,24 @@ +// +// Copyright 2020 Laxmikant Suryavanshi +// +// Use, modification and distribution are subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +#include +#include + +using namespace boost::gil; + +int main() +{ + rgb8_image_t img; + read_image("test.jpg",img, jpeg_tag{}); + rgb8_image_t img_out(img.dimensions()); + +// performing gaussian smoothening on image + boost::gil::gaussian_filter(const_view(img), view(img_out), 5, 1.0f); + write_view("gaussian_blur.jpg", view(img_out), jpeg_tag{}); + + return 0; +} diff --git a/include/boost/gil/image_processing/filter.hpp b/include/boost/gil/image_processing/filter.hpp index 7b960731a9..39f645229a 100644 --- a/include/boost/gil/image_processing/filter.hpp +++ b/include/boost/gil/image_processing/filter.hpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -135,6 +136,31 @@ void median_filter(SrcView const& src_view, DstView const& dst_view, std::size_t } } +template +void gaussian_filter( + SrcView const& src_view, + DstView const& dst_view, + std::size_t kernel_size, + double sigma, + boundary_option option = boundary_option::extend_zero +) +{ + gil_function_requires>(); + gil_function_requires>(); + 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"); + + auto gaussian_kernel_1d = generate_1d_gaussian_kernel(kernel_size, sigma); + + detail::convolve_1d + < + pixel + >(src_view, gaussian_kernel_1d, dst_view, option); +} + }} //namespace boost::gil #endif // !BOOST_GIL_IMAGE_PROCESSING_FILTER_HPP diff --git a/include/boost/gil/image_processing/numeric.hpp b/include/boost/gil/image_processing/numeric.hpp index 895624f6d0..225b528c80 100644 --- a/include/boost/gil/image_processing/numeric.hpp +++ b/include/boost/gil/image_processing/numeric.hpp @@ -151,6 +151,27 @@ inline detail::kernel_2d generate_gaussian_kernel(std::size_t side return detail::kernel_2d(values.begin(), values.size(), middle, middle); } +template > +inline kernel_1d generate_1d_gaussian_kernel(std::size_t side_length, double sigma) +{ + if (side_length % 2 != 1) + throw std::invalid_argument("kernel dimensions should be odd"); + + const double denominator = 2 * sigma * sigma; + auto middle = side_length / 2; + std::vector values(side_length); + for (std::size_t x = 0; x <= middle; x++) + { + const auto delta_x = middle - x; + const double power = (delta_x * delta_x) / denominator; + const double numerator = std::exp(-power); + const float value = static_cast(numerator / std::sqrt(denominator * M_PI)); + values[x] = value; + values[side_length - 1 - x] = value; + } + return kernel_1d(values.begin(), values.size(), middle, middle); +} + /// \brief Generates Sobel operator in horizontal direction /// \ingroup ImageProcessingMath /// diff --git a/test/core/image_processing/gaussian_blur.cpp b/test/core/image_processing/gaussian_blur.cpp new file mode 100644 index 0000000000..823705c672 --- /dev/null +++ b/test/core/image_processing/gaussian_blur.cpp @@ -0,0 +1,60 @@ +// +// Copyright 2020 Laxmikant Suryavanshi +// +// Use, modification and distribution are subject to the Boost Software License, +// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +#define BOOST_TEST_MODULE gil/test/core/image_processing/gaussian_filter +#include "unit_test.hpp" + +#include +#include +#include +#include + +namespace gil = boost::gil; + +const float kernel[] = +{ + 0.241971, 0.398942, 0.241971 +}; + +std::uint8_t img[] = +{ + 0, 0, 0, 0, 0, + 0, 100, 100, 100, 0, + 0, 100, 100, 100, 0, + 0, 100, 100, 100, 0, + 0, 0, 0, 0, 0 +}; + +std::uint8 output[] = +{ + 5, 15, 21, 15, 5, + 15, 41, 56, 41, 15, + 21, 56, 77, 56, 21, + 15, 41, 56, 41, 15, + 5, 15, 21, 15, 5 +}; + +BOOST_AUTO_TEST_SUITE(filter) + +BOOST_AUTO_TEST_CASE(gaussian_filter_with_default_parameters) +{ + gil::gray8c_view_t src_view = + gil::interleaved_view(5, 5, reinterpret_cast(img), 5); + + gil::image temp_img(src_view.width(), src_view.height()); + typename gil::image::view_t temp_view = view(temp_img); + gil::gray8_view_t dst_view(temp_view); + + gil::gaussian_filter(src_view, dst_view, 3, 1.0f); + + gil::gray8c_view_t out_view = + gil::interleaved_view(5, 5, reinterpret_cast(output), 5); + + BOOST_TEST(gil::equal_pixels(out_view, dst_view)); +} + +BOOST_AUTO_TEST_SUITE_END() From 06f15ee64830c3305da4f1e6ffbde48ddb786a16 Mon Sep 17 00:00:00 2001 From: laxsuryavanshi Date: Tue, 10 Mar 2020 22:16:53 +0530 Subject: [PATCH 2/3] added feature 1d <-> 2d kernel conversion todo: test and example --- .../boost/gil/extension/numeric/kernel.hpp | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/include/boost/gil/extension/numeric/kernel.hpp b/include/boost/gil/extension/numeric/kernel.hpp index 3186180cf6..d1c3de4be9 100644 --- a/include/boost/gil/extension/numeric/kernel.hpp +++ b/include/boost/gil/extension/numeric/kernel.hpp @@ -330,6 +330,33 @@ constexpr std::size_t kernel_2d_fixed::static_size; } //namespace detail +template > +kernel_1d get_1d_kernel_from( + detail::kernel_2d const& kernel) +{ + std::vector values(kernel.size()); + for (std::size_t x = 0; x < kernel.size(); x++) + values[x] = std::sqrt(kernel.at(x, x)); + return kernel_1d(values.begin(), values.size(), (kernel.size() / 2)); +} + +template > +kernel_2d get_2d_kernel_from( + kernel_1d const& kernel) +{ + auto side_length = kernel.size(); + std::vector values(side_length * side_length); + for (std::size_t y = 0; y < side_length; y++) + { + for (std::size_t x = 0; x < side_length; x++) + { + values[y * side_length + x] = kernel[y] * kernel[x]; + } + } + return detail::kernel_2d(values.begin(), side_length * side_length, + side_length / 2, side_length / 2); +} + /// \brief reverse a kernel //template //inline Kernel reverse_kernel(Kernel const& kernel) From 49947a5a689448b2dfb3147f4a6f33e99787a85b Mon Sep 17 00:00:00 2001 From: laxsuryavanshi Date: Tue, 10 Mar 2020 22:21:59 +0530 Subject: [PATCH 3/3] missing namespace kernel_2d --- include/boost/gil/extension/numeric/kernel.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/gil/extension/numeric/kernel.hpp b/include/boost/gil/extension/numeric/kernel.hpp index d1c3de4be9..6b6db3a114 100644 --- a/include/boost/gil/extension/numeric/kernel.hpp +++ b/include/boost/gil/extension/numeric/kernel.hpp @@ -341,7 +341,7 @@ kernel_1d get_1d_kernel_from( } template > -kernel_2d get_2d_kernel_from( +detail::kernel_2d get_2d_kernel_from( kernel_1d const& kernel) { auto side_length = kernel.size();