Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implemented median_filter #393

Merged
merged 1 commit into from
Oct 15, 2019
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 83 additions & 6 deletions include/boost/gil/image_processing/filter.hpp
Original file line number Diff line number Diff line change
@@ -9,15 +9,19 @@
#ifndef BOOST_GIL_IMAGE_PROCESSING_FILTER_HPP
#define BOOST_GIL_IMAGE_PROCESSING_FILTER_HPP

#include <cstddef>
#include <vector>

#include <boost/gil/image.hpp>
#include <boost/gil/image_view.hpp>
#include <boost/gil/extension/numeric/algorithm.hpp>
#include <boost/gil/extension/numeric/kernel.hpp>
#include <boost/gil/extension/numeric/convolve.hpp>

#include <boost/gil/image.hpp>
#include <boost/gil/image_view.hpp>

#include <cstddef>
#include <vector>




namespace boost { namespace gil {

template <typename SrcView, typename DstView>
@@ -45,7 +49,12 @@ void box_filter(
if (anchor == -1) anchor = static_cast<int>(kernel_size / 2);
kernel_1d<float> kernel(kernel_values.begin(), kernel_size, anchor);

convolve_1d<pixel<float, typename SrcView::value_type::layout_t>>(src_view, kernel, dst_view, option);
convolve_1d<pixel<float, typename SrcView::value_type::layout_t>>(
src_view,
kernel,
dst_view,
option
);
}

template <typename SrcView, typename DstView>
@@ -60,6 +69,74 @@ void blur(
box_filter(src_view, dst_view, kernel_size, anchor, true, option);
}


namespace detail
{
template <typename SrcView, typename DstView>
void filter_median_impl(SrcView const& src_view, DstView const& dst_view, std::size_t kernel_size)
{
std::size_t half_kernel_size = kernel_size / 2;

// deciding output channel type and creating functor
using src_channel_t = typename channel_type<SrcView>::type;

std::vector<src_channel_t> values;
values.reserve(kernel_size * kernel_size);

for (std::ptrdiff_t y = 0; y < src_view.height(); y++)
{
typename DstView::x_iterator dst_it = dst_view.row_begin(y);

for (std::ptrdiff_t x = 0; x < src_view.width(); x++)
{
auto sub_view = subimage_view(
src_view,
x - half_kernel_size, y - half_kernel_size,
kernel_size,
kernel_size
);
values.assign(sub_view.begin(), sub_view.end());

std::nth_element(values.begin(), values.begin() + (values.size() / 2), values.end());
dst_it[x] = values[values.size() / 2];
}
}
}
} // namespace detail

template <typename SrcView, typename DstView>
void median_filter(SrcView const& src_view, DstView const& dst_view, std::size_t kernel_size)
{
static_assert(color_spaces_are_compatible
<
typename color_space_type<SrcView>::type,
typename color_space_type<DstView>::type
>::value, "Source and destination views must have pixels with the same color space");

std::size_t half_kernel_size = kernel_size / 2;
auto extended_img = extend_boundary(
src_view,
half_kernel_size,
boundary_option::extend_constant
);
auto extended_view = subimage_view(
view(extended_img),
half_kernel_size,
half_kernel_size,
src_view.width(),
src_view.height()
);

for (std::size_t channel = 0; channel < extended_view.num_channels(); channel++)
{
detail::filter_median_impl(
nth_channel_view(extended_view, channel),
nth_channel_view(dst_view, channel),
kernel_size
);
}
}

}} //namespace boost::gil

#endif // !BOOST_GIL_IMAGE_PROCESSING_FILTER_HPP
3 changes: 2 additions & 1 deletion test/core/image_processing/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -32,7 +32,8 @@ foreach(_name
simple_kernels
harris
hessian
box_filter)
box_filter
median_filter)
set(_test t_core_image_processing_${_name})
set(_target test_core_image_processing_${_name})

1 change: 1 addition & 0 deletions test/core/image_processing/Jamfile
Original file line number Diff line number Diff line change
@@ -22,3 +22,4 @@ run simple_kernels.cpp ;
run harris.cpp ;
run hessian.cpp ;
run box_filter.cpp /boost/test//boost_unit_test_framework : : : <link>shared:<define>BOOST_TEST_DYN_LINK=1 ;
run median_filter.cpp /boost/test//boost_unit_test_framework : : : <link>shared:<define>BOOST_TEST_DYN_LINK=1 ;
65 changes: 65 additions & 0 deletions test/core/image_processing/median_filter.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
//
// Copyright 2019 Miral Shah <[email protected]>
//
// 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 test_image_processing_median_filter
#include "unit_test.hpp"

#include <boost/gil/image_view.hpp>
#include <boost/gil/algorithm.hpp>
#include <boost/gil/gray.hpp>
#include <boost/gil/image_processing/filter.hpp>


namespace gil = boost::gil;

std::uint8_t img[] =
{
183, 128, 181, 86, 34, 55, 134, 164, 15,
90, 59, 94, 158, 202, 0, 106, 120, 255,
65, 48, 4, 21, 21, 38, 50, 37, 228,
27, 245, 254, 164, 135, 192, 17, 241, 19,
56, 165, 253, 169, 24, 200, 249, 70, 199,
59, 84, 41, 96, 70, 58, 24, 20, 218,
235, 180, 12, 168, 224, 204, 166, 153, 1,
181, 213, 232, 178, 165, 253, 93, 214, 72,
171, 50, 20, 65, 67, 133, 249, 157, 105
};

std::uint8_t output[] =
{
128, 128, 128, 94, 55, 55, 120, 134, 120,
90, 90, 86, 86, 38, 50, 55, 120, 164,
65, 65, 94, 135, 135, 50, 50, 106, 228,
56, 65, 165, 135, 135, 50, 70, 70, 199,
59, 84, 165, 135, 135, 70, 70, 70, 199,
84, 84, 165, 96, 168, 166, 153, 153, 153,
181, 180, 168, 165, 168, 165, 153, 93, 72,
181, 180, 168, 165, 168, 166, 166, 153, 105,
171, 171, 65, 67, 133, 133, 157, 157, 105
};

BOOST_AUTO_TEST_SUITE(filter)

BOOST_AUTO_TEST_CASE(median_filter_with_kernel_size_3)
{
gil::gray8c_view_t src_view =
gil::interleaved_view(9, 9, reinterpret_cast<const gil::gray8_pixel_t*>(img), 9);

gil::image<gil::gray8_pixel_t> temp_img(src_view.width(), src_view.height());
typename gil::image<gil::gray8_pixel_t>::view_t temp_view = view(temp_img);
gil::gray8_view_t dst_view(temp_view);

gil::median_filter(src_view, dst_view, 3);

gil::gray8c_view_t out_view =
gil::interleaved_view(9, 9, reinterpret_cast<const gil::gray8_pixel_t*>(output), 9);

BOOST_TEST(gil::equal_pixels(out_view, dst_view));
}

BOOST_AUTO_TEST_SUITE_END()