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

Adding Morphological Dilation and Erosion Algorithms #430

Closed
wants to merge 8 commits into from
37 changes: 37 additions & 0 deletions example/morphology.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#include <boost/gil/extension/io/png.hpp>
ayushbansal07 marked this conversation as resolved.
Show resolved Hide resolved
#include <boost/gil/image_processing/morphology.hpp>
#include <boost/gil/image_view_factory.hpp>
#include <boost/gil.hpp>
#include <boost/multi_array.hpp>

const int struct_elem_size = 3;

using namespace boost::gil;
using namespace std;

int main()
{
gray8_image_t img;
read_image("test_adaptive.png", img, png_tag{});
gray8_image_t img_dilate(img.dimensions());
gray8_image_t img_erode(img.dimensions());

int se_arr[struct_elem_size][struct_elem_size] = {{0,1,0},{1,1,1},{0,1,0}};

using se_type = boost::multi_array<int, 2>;

se_type se{boost::extents[struct_elem_size][struct_elem_size]};
for(int i=0; i < struct_elem_size; ++i)
{
for(int j=0; j < struct_elem_size; ++j)
{
se[i][j] = se_arr[i][j];
}
}

dilate(view(img), view(img_dilate), se);
erode(view(img), view(img_erode), se);

write_view("dilated_image.png", view(img_dilate), png_tag{});
write_view("eroded_image.png", view(img_erode), png_tag{});
}
127 changes: 127 additions & 0 deletions include/boost/gil/image_processing/morphology.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
//
// Copyright 2019 Ayush Bansal <[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)
//
#ifndef BOOST_GIL_IMAGE_PROCESSING_MORPHOLOGY_HPP
#define BOOST_GIL_IMAGE_PROCESSING_MORPHOLOGY_HPP

#include <boost/assert.hpp>
#include <boost/gil.hpp>
mloskot marked this conversation as resolved.
Show resolved Hide resolved

namespace boost { namespace gil {

// SE refers to Structuring Element
// Result type after convolution with the structuring element
enum class morphology_operator{
ayushbansal07 marked this conversation as resolved.
Show resolved Hide resolved
erode,
dilate
};

namespace detail {

template <typename SrcView, typename DstView, typename StructElement>
void convolve_with_struct_element(SrcView const &src_view, DstView &dst_view,
StructElement const &struct_elem, std::ptrdiff_t src_y, std::ptrdiff_t src_x,
morphology_operator const &op)
{
// Template argument validation
gil_function_requires<ImageViewConcept<SrcView>>();
gil_function_requires<MutableImageViewConcept<DstView>>();

using source_channel_t = typename channel_type<SrcView>::type;

// Initial min and max values to be replaced after apply morphplogical operator
auto min = (std::numeric_limits<source_channel_t>::max());
auto max = (std::numeric_limits<source_channel_t>::min());

std::size_t struct_elem_height = struct_elem.size();
std::size_t struct_elem_width = struct_elem[0].size();

for(std::ptrdiff_t struct_elem_y = 0; struct_elem_y < struct_elem_height; ++struct_elem_y)
{
// The cooresponding value to be read from src_view is calculated as
// (src_y + struct_elem_y - struct_elem_height/2, src_x + struct_elem_x - struct_elem_width/2)
// NOTE: This calculation is only valid when the struct_elem dimensions are odd.
auto y_to_read = src_y + struct_elem_y - struct_elem_height/2;
if(y_to_read < 0 || y_to_read >= src_view.height())
ayushbansal07 marked this conversation as resolved.
Show resolved Hide resolved
continue;
typename SrcView::x_iterator src_it = src_view.row_begin(y_to_read);

for(std::ptrdiff_t struct_elem_x = 0; struct_elem_x < struct_elem_width; ++struct_elem_x)
{
// We need to consider only those positions which have 1 in Structuring Element
if(struct_elem[struct_elem_x][struct_elem_y] == 1)
mloskot marked this conversation as resolved.
Show resolved Hide resolved
{
auto x_to_read = src_x + struct_elem_x - struct_elem_width/2;
if(x_to_read < 0 || x_to_read >= src_view.width())
continue;
auto src_point_val = src_it[x_to_read];
if (src_point_val < min)
min = src_point_val;
if (src_point_val > max)
max = src_point_val;
ayushbansal07 marked this conversation as resolved.
Show resolved Hide resolved
}
}
}

typename DstView::x_iterator dst_it = dst_view.row_begin(src_y);

if (op == morphology_operator::erode)
dst_it[src_x] = min;
else if(op == morphology_operator::dilate)
dst_it[src_x] = max;
}

template <typename SrcView, typename DstView, typename StructElement>
void morph_impl(SrcView const &src_view, DstView &dst_view, StructElement const &struct_elem, morphology_operator const &op)
{
BOOST_ASSERT(src_view.dimensions() == dst_view.dimensions());
BOOST_ASSERT(struct_elem.size() != 0 && struct_elem[0].size() != 0);

std::size_t height = src_view.height();
std::size_t width = dst_view.width();

for(std::ptrdiff_t src_y = 0; src_y < height; ++src_y)
{
for(std::ptrdiff_t src_x = 0; src_x < width; ++src_x)
{
convolve_with_struct_element<SrcView, DstView, StructElement>(src_view, dst_view, struct_elem, src_y, src_x, op);
}
}
}

} //namespace boost::gil::detail

/// \addtogroup ImageProcessing
/// @{

/// \brief Performs Morphological Dilation of the given image with a given Structuring Element.
/// \param src_view - The source image view.
/// \param dst_view - The destination image view (after performing dilation).
/// \param struct_elem - The Structuing Element. Should be a 2D-array type consiting of binary int values (0 and 1).
/// Should provide size() and operator[]
template <typename SrcView, typename DstView, typename StructElement>
void dilate(SrcView const &src_view, DstView &dst_view, StructElement const &struct_elem)
{
morph_impl(src_view, dst_view, struct_elem, morphology_operator::dilate);
}

/// \brief Performs Morphological Erosion of the given image with a given Structuring Element.
/// \param src_view - The source image view.
/// \param dst_view - The destination image view (after performing dilation).
/// \param struct_elem - The Structuing Element. Should be a 2D-array type consiting of binary int values (0 and 1).
/// Should provide size() and operator[]
template <typename SrcView, typename DstView, typename StructElement>
void erode(SrcView const &src_view, DstView &dst_view, StructElement const &struct_elem)
{
morph_impl(src_view, dst_view, struct_elem, morphology_operator::erode);
}

/// @}

}} //namespace boost::gil

#endif //BOOST_GIL_IMAGE_PROCESSING_MORPHOLOGY_HPP
Loading