diff --git a/example/gaussian_blur.cpp b/example/gaussian_blur.cpp new file mode 100644 index 0000000000..bb4bb4a825 --- /dev/null +++ b/example/gaussian_blur.cpp @@ -0,0 +1,26 @@ +// +// 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 Blur on image +// here kernel size is 5 and sigma is taken as 1 + 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..24c0597a74 100644 --- a/include/boost/gil/image_processing/filter.hpp +++ b/include/boost/gil/image_processing/filter.hpp @@ -16,12 +16,14 @@ #include #include +#include +#include #include +#include #include - namespace boost { namespace gil { template @@ -135,6 +137,59 @@ void median_filter(SrcView const& src_view, DstView const& dst_view, std::size_t } } +namespace detail { + +template +void get_1d_gaussian_kernel( + KernelT& kernel, + long int kernel_size, + double sigma) +{ + if ((kernel_size%2) == 0) + throw std::invalid_argument("kernel dimensions should be odd"); + + const double exp_denom = 2 * sigma * sigma; + auto center = kernel_size / 2; + for (long int x = 0; x <= center; x++) + { + const auto delta_x = center - x; + const double power = (delta_x * delta_x) / exp_denom; + const double numerator = std::exp(-power); + const float value = static_cast(numerator/std::sqrt(M_PI * exp_denom)); + kernel[x] = value; + kernel[kernel_size-1-x] = value; + } +} + +} // namespace detail + +template +void gaussian_filter( + SrcView src_view, + DstView dst_view, + long int 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"); + + std::vector kernel_values(kernel_size); + detail::getGaussianKernel(kernel_values, kernel_size, sigma, normalize); + auto center = static_cast(kernel_size/2); + kernel_1d kernel(kernel_values.begin(), kernel_size, center); + + detail::convolve_1d + < + pixel + >(src_view, kernel, dst_view, option); +} + }} //namespace boost::gil #endif // !BOOST_GIL_IMAGE_PROCESSING_FILTER_HPP diff --git a/include/boost/gil/image_processing/threshold.hpp b/include/boost/gil/image_processing/threshold.hpp index af05e4d268..96de803772 100644 --- a/include/boost/gil/image_processing/threshold.hpp +++ b/include/boost/gil/image_processing/threshold.hpp @@ -45,7 +45,7 @@ void threshold_impl(SrcView const& src_view, DstView const& dst_view, Operator c typename color_space_type::type >::value, "Source and destination views must have pixels with the same color space"); - //iterate over the image chaecking each pixel value for the threshold + //iterate over the image checking each pixel value for the threshold for (std::ptrdiff_t y = 0; y < src_view.height(); y++) { typename SrcView::x_iterator src_it = src_view.row_begin(y); @@ -64,7 +64,7 @@ void threshold_impl(SrcView const& src_view, DstView const& dst_view, Operator c /// @{ /// /// \brief Direction of image segmentation. -/// The direction specifieds which pixels are considered as corresponding to object +/// The direction specifies which pixels are considered as corresponding to object /// and which pixels correspond to background. enum class threshold_direction { diff --git a/test/core/image_processing/gaussian_filter.cpp b/test/core/image_processing/gaussian_filter.cpp new file mode 100644 index 0000000000..7e12a7b1ed --- /dev/null +++ b/test/core/image_processing/gaussian_filter.cpp @@ -0,0 +1,62 @@ +// +// 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()