Skip to content
Merged
Show file tree
Hide file tree
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
Expand Up @@ -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>
Expand Down Expand Up @@ -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>
Expand All @@ -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
Expand Up @@ -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})

Expand Down
1 change: 1 addition & 0 deletions test/core/image_processing/Jamfile
Original file line number Diff line number Diff line change
Expand Up @@ -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 <miralshah2211@gmail.com>
//
// 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>
Comment thread
miralshah365 marked this conversation as resolved.
Resolved
#include <boost/gil/image_processing/filter.hpp>
Comment thread
miralshah365 marked this conversation as resolved.
Resolved


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()