Commit 8f84d165 authored by Edwin Carlinet's avatar Edwin Carlinet
Browse files

Add chamfer distance transform.

	*  mln/transform/chamfer_distance_transform.hpp,
	*  tests/CMakeLists.txt,
	*  tests/transform/CMakeLists.txt,
	*  tests/transform/chamfer_distance_transform.cpp: New.
parent db8cde18
#ifndef MLN_TRANSFORM_CHAMFER_DISTANCE_TRANSFORM_HPP
# define MLN_TRANSFORM_CHAMFER_DISTANCE_TRANSFORM_HPP
# include <mln/core/image/image.hpp>
# include <mln/core/neighborhood/neighborhood.hpp>
# include <mln/core/extension/fill.hpp>
# include <mln/core/trace.hpp>
namespace mln
{
namespace transform
{
template <class I, class N, class OutputImage>
void
chamfer_distance_transform(const Image<I>& f,
const Neighborhood<N>& nbh,
OutputImage&& out);
template <class I, class N, typename DistanceType = int>
mln_ch_value(I, DistanceType)
chamfer_distance_transform(const Image<I>& f,
const Neighborhood<N>& nbh);
/**********************************/
/** Implementation ***/
/**********************************/
template <class I, class N, class OutputImage>
void
chamfer_distance_transform(const Image<I>& f_,
const Neighborhood<N>& nbh_,
OutputImage&& out)
{
static_assert( std::is_convertible<mln_value(I), bool>::value,
"Input value type must be convertible to bool");
mln_entering("mln::transform::chamfer_distance_transform");
typedef mln_value(OutputImage) distance_t;
const I& f = exact(f_);
const N& nbh = exact(nbh_);
extension::fill(out, 0);
// Forward scan
{
mln_pixter(pxin, pxout, f, out);
mln_iter(q, nbh(pxout));
mln_forall(pxin, pxout) {
if (pxin->val()) {
distance_t vmin = value_traits<distance_t>::max();
mln_forall(q)
if (q->index() < pxout->index())
vmin = std::min<distance_t>(vmin, q->val() + 1);
pxout->val() = vmin;
} else {
pxout->val() = 0;
}
}
}
// Backward
{
mln_riter(pxin, f.pixels());
mln_riter(pxout, out.pixels());
mln_iter(q, nbh(pxout));
mln_forall(pxin, pxout)
if (pxin->val())
{
distance_t vmin = pxout->val();
mln_forall(q)
if (q->index() > pxout->index())
vmin = std::min<distance_t>(vmin, q->val()+1);
pxout->val() = vmin;
}
}
mln_exiting();
}
template <class I, class N, typename DistanceType>
mln_ch_value(I, DistanceType)
chamfer_distance_transform(const Image<I>& f_,
const Neighborhood<N>& nbh_)
{
const I& f = exact(f_);
const N& nbh = exact(nbh_);
mln_ch_value(I, DistanceType) out = imchvalue<DistanceType>(f);
chamfer_distance_transform(f, nbh, out);
return out;
}
}
}
#endif // ! MLN_TRANSFORM_CHAMFER_DISTANCE_TRANSFORM_HPP
......@@ -4,5 +4,5 @@ link_libraries(${Boost_UNIT_TEST_FRAMEWORK_LIBRARY})
add_definitions(-DBOOST_TEST_DYN_LINK)
add_definitions(-DMLN_IMG_PATH="$(CMAKE_SOURCE_DIR)/img/")
SUBDIRS(core draw io colors morpho accu labeling graph graphcut)
SUBDIRS(core draw io colors morpho accu labeling graph graphcut transform)
add_executable(chamfer_distance_transform chamfer_distance_transform.cpp)
add_core_test(chamfer_distance_transform chamfer_distance_transform)
#include <mln/core/image/image2d.hpp>
#include <mln/core/neighb2d.hpp>
#include <mln/core/algorithm/iota.hpp>
#include <mln/transform/chamfer_distance_transform.hpp>
#define BOOST_TEST_MODULE Transform
#include <tests/test.hpp>
BOOST_AUTO_TEST_SUITE(chamfer_distance_transform)
BOOST_AUTO_TEST_CASE(chamfer_distance_transform_1)
{
using namespace mln;
image2d<bool> f = { {0,0,0,0,0},
{0,1,1,1,0},
{0,1,1,1,0},
{0,1,1,1,0},
{0,0,0,0,0} };
image2d<int> ref = { {0,0,0,0,0},
{0,1,1,1,0},
{0,1,2,1,0},
{0,1,1,1,0},
{0,0,0,0,0} };
auto res = transform::chamfer_distance_transform(f, c4);
MLN_CHECK_IMEQUAL(res, ref);
}
BOOST_AUTO_TEST_CASE(chamfer_distance_transform_2)
{
using namespace mln;
image2d<bool> f = { {1,0,0,0,0,1},
{0,1,1,1,1,0},
{0,1,1,1,1,0},
{0,1,1,1,1,0},
{1,0,0,0,0,1} };
image2d<int> ref = { {1,0,0,0,0,1},
{0,1,1,1,1,0},
{0,1,2,2,1,0},
{0,1,1,1,1,0},
{1,0,0,0,0,1}};
auto res = transform::chamfer_distance_transform(f, c4);
MLN_CHECK_IMEQUAL(res, ref);
}
// Input and output are the same image
BOOST_AUTO_TEST_CASE(chamfer_distance_transform_3)
{
using namespace mln;
image2d<int> f = { {1,0,0,0,0,1},
{0,1,1,1,1,0},
{0,1,1,1,1,0},
{0,1,1,1,1,0},
{1,0,0,0,0,1} };
image2d<int> ref = { {1,0,0,0,0,1},
{0,1,1,1,1,0},
{0,1,2,2,1,0},
{0,1,1,1,1,0},
{1,0,0,0,0,1}};
transform::chamfer_distance_transform(f, c4, f);
MLN_CHECK_IMEQUAL(f, ref);
}
BOOST_AUTO_TEST_SUITE_END()
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment