Boost GIL


morphology.hpp
1 //
2 // Copyright 2021 Prathamesh Tagore <prathameshtagore@gmail.com>
3 //
4 // Use, modification and distribution are subject to the Boost Software License,
5 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
6 // http://www.boost.org/LICENSE_1_0.txt)
7 //
8 
9 #ifndef BOOST_GIL_IMAGE_PROCESSING_MORPHOLOGY_HPP
10 #define BOOST_GIL_IMAGE_PROCESSING_MORPHOLOGY_HPP
11 
12 #include <boost/gil/image_processing/kernel.hpp>
13 #include <boost/gil/gray.hpp>
14 #include <boost/gil/image_processing/threshold.hpp>
15 
16 namespace boost
17 {
18 namespace gil
19 {
20 namespace detail
21 {
22 enum class morphological_operation
23 {
24  dilation,
25  erosion,
26 };
29 
42 template <typename SrcView, typename DstView, typename Kernel>
43 void morph_impl(SrcView const& src_view, DstView const& dst_view, Kernel const& kernel,
44  morphological_operation identifier)
45 {
46  std::ptrdiff_t flip_ker_row, flip_ker_col, row_boundary, col_boundary;
48  for (std::ptrdiff_t view_row = 0; view_row < src_view.height(); ++view_row)
49  {
50  for (std::ptrdiff_t view_col = 0; view_col < src_view.width(); ++view_col)
51  {
52  target_element = src_view(view_col, view_row);
53  for (std::size_t kernel_row = 0; kernel_row < kernel.size(); ++kernel_row)
54  {
55  flip_ker_row = kernel.size() - 1 - kernel_row; // row index of flipped kernel
56 
57  for (std::size_t kernel_col = 0; kernel_col < kernel.size(); ++kernel_col)
58  {
59  flip_ker_col = kernel.size() - 1 - kernel_col; // column index of flipped kernel
60 
61  // We ensure that we consider only those pixels which are overlapped
62  // on a non-zero kernel_element as
63  if (kernel.at(flip_ker_row, flip_ker_col) == 0)
64  {
65  continue;
66  }
67  // index of input signal, used for checking boundary
68  row_boundary = view_row + (kernel.center_y() - flip_ker_row);
69  col_boundary = view_col + (kernel.center_x() - flip_ker_col);
70 
71  // ignore input samples which are out of bound
72  if (row_boundary >= 0 && row_boundary < src_view.height() &&
73  col_boundary >= 0 && col_boundary < src_view.width())
74  {
75 
76  if (identifier == morphological_operation::dilation)
77  {
78  target_element =
79  (std::max)(src_view(col_boundary, row_boundary)[0], target_element);
80  }
81  else if (identifier == morphological_operation::erosion)
82  {
83  target_element =
84  (std::min)(src_view(col_boundary, row_boundary)[0], target_element);
85  }
86  }
87  }
88  }
89  dst_view(view_col, view_row) = target_element;
90  }
91  }
92 }
93 
105 template <typename SrcView, typename DstView, typename Kernel>
106 void morph(SrcView const& src_view, DstView const& dst_view, Kernel const& ker_mat,
107  morphological_operation identifier)
108 {
109  BOOST_ASSERT(ker_mat.size() != 0 && src_view.dimensions() == dst_view.dimensions());
110  gil_function_requires<ImageViewConcept<SrcView>>();
111  gil_function_requires<MutableImageViewConcept<DstView>>();
112 
113  gil_function_requires<ColorSpacesCompatibleConcept<typename color_space_type<SrcView>::type,
114  typename color_space_type<DstView>::type>>();
115 
116  gil::image<typename DstView::value_type> intermediate_img(src_view.dimensions());
117 
118  for (std::size_t i = 0; i < src_view.num_channels(); i++)
119  {
120  morph_impl(nth_channel_view(src_view, i), nth_channel_view(view(intermediate_img), i),
121  ker_mat, identifier);
122  }
123  copy_pixels(view(intermediate_img), dst_view);
124 }
125 
134 template <typename SrcView, typename DiffView>
135 void difference_impl(SrcView const& src_view1, SrcView const& src_view2, DiffView const& diff_view)
136 {
137  for (std::ptrdiff_t view_row = 0; view_row < src_view1.height(); ++view_row)
138  for (std::ptrdiff_t view_col = 0; view_col < src_view1.width(); ++view_col)
139  diff_view(view_col, view_row) =
140  src_view1(view_col, view_row) - src_view2(view_col, view_row);
141 }
142 
150 template <typename SrcView, typename DiffView>
151 void difference(SrcView const& src_view1, SrcView const& src_view2, DiffView const& diff_view)
152 {
153  gil_function_requires<ImageViewConcept<SrcView>>();
154  gil_function_requires<MutableImageViewConcept<DiffView>>();
155 
156  gil_function_requires<ColorSpacesCompatibleConcept<
157  typename color_space_type<SrcView>::type, typename color_space_type<DiffView>::type>>();
158 
159  for (std::size_t i = 0; i < src_view1.num_channels(); i++)
160  {
161  difference_impl(nth_channel_view(src_view1, i), nth_channel_view(src_view2, i),
162  nth_channel_view(diff_view, i));
163  }
164 }
165 } // namespace detail
166 
179 template <typename SrcView, typename IntOpView, typename Kernel>
180 void dilate(SrcView const& src_view, IntOpView const& int_op_view, Kernel const& ker_mat,
181  int iterations)
182 {
183  copy_pixels(src_view, int_op_view);
184  for (int i = 0; i < iterations; ++i)
185  morph(int_op_view, int_op_view, ker_mat, detail::morphological_operation::dilation);
186 }
187 
200 template <typename SrcView, typename IntOpView, typename Kernel>
201 void erode(SrcView const& src_view, IntOpView const& int_op_view, Kernel const& ker_mat,
202  int iterations)
203 {
204  copy_pixels(src_view, int_op_view);
205  for (int i = 0; i < iterations; ++i)
206  morph(int_op_view, int_op_view, ker_mat, detail::morphological_operation::erosion);
207 }
208 
218 template <typename SrcView, typename IntOpView, typename Kernel>
219 void opening(SrcView const& src_view, IntOpView const& int_op_view, Kernel const& ker_mat)
220 {
221  erode(src_view, int_op_view, ker_mat, 1);
222  dilate(int_op_view, int_op_view, ker_mat, 1);
223 }
224 
235 template <typename SrcView, typename IntOpView, typename Kernel>
236 void closing(SrcView const& src_view, IntOpView const& int_op_view, Kernel const& ker_mat)
237 {
238  dilate(src_view, int_op_view, ker_mat, 1);
239  erode(int_op_view, int_op_view, ker_mat, 1);
240 }
241 
253 template <typename SrcView, typename DstView, typename Kernel>
254 void morphological_gradient(SrcView const& src_view, DstView const& dst_view, Kernel const& ker_mat)
255 {
256  using namespace boost::gil;
257  gil::image<typename DstView::value_type> int_dilate(src_view.dimensions()),
258  int_erode(src_view.dimensions());
259  dilate(src_view, view(int_dilate), ker_mat, 1);
260  erode(src_view, view(int_erode), ker_mat, 1);
261  difference(view(int_dilate), view(int_erode), dst_view);
262 }
263 
273 template <typename SrcView, typename DstView, typename Kernel>
274 void top_hat(SrcView const& src_view, DstView const& dst_view, Kernel const& ker_mat)
275 {
276  using namespace boost::gil;
277  gil::image<typename DstView::value_type> int_opening(src_view.dimensions());
278  opening(src_view, view(int_opening), ker_mat);
279  difference(src_view, view(int_opening), dst_view);
280 }
281 
291 template <typename SrcView, typename DstView, typename Kernel>
292 void black_hat(SrcView const& src_view, DstView const& dst_view, Kernel const& ker_mat)
293 {
294  using namespace boost::gil;
295  gil::image<typename DstView::value_type> int_closing(src_view.dimensions());
296  closing(src_view, view(int_closing), ker_mat);
297  difference(view(int_closing), src_view, dst_view);
298 }
300 }} // namespace boost::gil
301 #endif // BOOST_GIL_IMAGE_PROCESSING_MORPHOLOGY_HPP
boost::gil::image
container interface over image view. Models ImageConcept, PixelBasedConcept
Definition: image.hpp:42
boost::gil::detail::difference
void difference(SrcView const &src_view1, SrcView const &src_view2, DiffView const &diff_view)
Passes parameter values to the function 'difference_impl' alongwith individual channel views of input...
Definition: morphology.hpp:151
boost::gil::detail::morph
void morph(SrcView const &src_view, DstView const &dst_view, Kernel const &ker_mat, morphological_operation identifier)
Checks feasibility of the desired operation and passes parameter values to the function morph_impl al...
Definition: morphology.hpp:106
boost::gil::nth_channel_view
nth_channel_view_type< View >::type nth_channel_view(const View &src, int n)
Definition: image_view_factory.hpp:418
boost::gil::ColorSpacesCompatibleConcept
Two color spaces are compatible if they are the same.
Definition: color.hpp:60
boost::gil::detail::morph_impl
void morph_impl(SrcView const &src_view, DstView const &dst_view, Kernel const &kernel, morphological_operation identifier)
Implements morphological operations at pixel level.This function compares neighbouring pixel values a...
Definition: morphology.hpp:43
boost::gil::copy_pixels
BOOST_FORCEINLINE void copy_pixels(const View1 &src, const View2 &dst)
std::copy for image views
Definition: algorithm.hpp:288
boost::gil::view
const image< Pixel, IsPlanar, Alloc >::view_t & view(image< Pixel, IsPlanar, Alloc > &img)
Returns the non-constant-pixel view of an image.
Definition: image.hpp:549
boost::gil::channel_type
Definition: color_convert.hpp:31
boost::gil::detail::difference_impl
void difference_impl(SrcView const &src_view1, SrcView const &src_view2, DiffView const &diff_view)
Calculates the difference between pixel values of first image_view and second image_view.
Definition: morphology.hpp:135