Commit 59f6aa29 authored by Edwin Carlinet's avatar Edwin Carlinet

Implement dilation by perdiodic lines.

parent 82931be8
#ifndef MLN_MORPHO_CANVAS_PRIVATE_DILATION_BY_PERIODIC_LINE_HPP
#define MLN_MORPHO_CANVAS_PRIVATE_DILATION_BY_PERIODIC_LINE_HPP
#include <mln/core/domain/box.hpp>
#include <mln/core/se/periodic_line2d.hpp>
#include <mln/core/trace.hpp>
#include "running_max_1d.hpp"
namespace mln
{
namespace morpho
{
namespace internal
{
/// Copy the line starting at \p src_point with period \p period into a buffer
template <class I, class V>
void copy_to_periodic_line(const I& f, box2d domain, point2d src_point, point2d period, V* lineptr,
std::size_t& size)
{
mln_precondition(period[0] >= 0 && (period[0] != 0 || period[1] != 0));
mln_precondition(domain.has(src_point));
const int dy = period[0];
const int dx = period[1];
const auto height = domain.pmax[0] - src_point[0];
const auto width = dx > 0 ? (domain.pmax[1] - src_point[1]) : (src_point[1] - domain.pmin[1] + 1);
const int nx = dx != 0 ? ((width - 1) / std::abs(dx)) : std::numeric_limits<int>::max();
const int ny = dy != 0 ? ((height - 1) / std::abs(dy)) : std::numeric_limits<int>::max();
const std::size_t n = std::min(nx, ny) + 1;
point2d p = src_point;
for (std::size_t i = 0; i < n; ++i, p += period)
lineptr[i] = f(p);
size = n;
}
/// Copy the buffer of the line of length \p size
/// to the output image at \p pdest
template <class J, class V>
void copy_from_periodic_line(const V* lineptr, std::size_t size, point2d period, point2d pdest, J& output)
{
point2d p = pdest;
for (std::size_t i = 0; i < size; ++i, p += period)
output(p) = lineptr[i];
}
// Special algorithm for dilation by line
// The algorithm runs inplace
template <class I, class BinaryFunction>
void dilation_by_periodic_line(I& f, const mln::se::periodic_line2d& line, BinaryFunction sup, mln_value(I) zero)
{
mln_entering("mln::morpho::internal::dilation_by_periodic_line");
auto domain = f.domain();
using V = mln_value(I);
auto period = line.period();
const int dy = period[0];
const int dx = period[1];
mln_assertion(dy >= 0);
int buffer_size = std::max(domain.shape()[0], domain.shape()[1]);
auto p = std::make_unique<V[]>(buffer_size); // temporary 1D-line
auto g = std::make_unique<V[]>(buffer_size); // Max-forward integral over the line
auto h = std::make_unique<V[]>(buffer_size); // Max-backward integral over the line
int k = line.repetition();
// Process row-wise
if (dx != 0)
{
// Depending on dx, we process from left border or the right border
int x0 = (dx > 0) ? domain.pmin[1] : domain.pmax[1] - 1;
for (int i = std::abs(dx) - 1; i >= 0; --i)
{
int x = x0 + (dx > 0 ? i : -i);
for (int y = domain.pmin[0]; y < domain.pmax[0]; ++y)
{
point2d origin = {(short)y, (short)x};
std::size_t n;
copy_to_periodic_line(f, domain, origin, period, p.get(), n);
mln::morpho::internal::running_max_1d(p.get(), g.get(), h.get(), (int)n, 2 * k + 1, -k, sup, zero);
copy_from_periodic_line(p.get(), n, period, origin, f);
}
}
}
// Process col-wise
if (dy != 0)
{
// We always process from the top border (because dy > 0)
auto y0 = domain.pmin[0];
int xstart = (dx > 0) ? domain.pmin[1] + dx : domain.pmin[1];
int xend = (dx >= 0) ? domain.pmax[1] : domain.pmax[1] + dx;
for (int i = 0; i < dy; ++i)
{
int y = y0 + i;
for (int x = xstart; x < xend; ++x)
{
point2d origin = {(short)y, (short)x};
std::size_t n;
copy_to_periodic_line(f, domain, origin, period, p.get(), n);
mln::morpho::internal::running_max_1d(p.get(), g.get(), h.get(), (int)n, 2 * k + 1, -k, sup, zero);
copy_from_periodic_line(p.get(), n, period, origin, f);
}
}
}
}
} // end of namespace mln::morpho::internal
} // end of namespace mln::morpho
} // end of namespace mln
#endif //! MLN_MORPHO_CANVAS_PRIVATE_DILATION_BY_PERIODIC_LINE_HPP
......@@ -3,8 +3,10 @@
#include <mln/core/grays.hpp>
#include <mln/core/image/image2d.hpp>
#include <mln/core/win2d.hpp>
#include <mln/core/algorithm/iota.hpp>
#include <mln/io/imread.hpp>
#include <mln/morpho/structural/dilate.hpp>
#include <mln/morpho/canvas/private/dilation_by_periodic_line.hpp>
#include <mln/core/se/disc.hpp>
#include <tests/helpers.hpp>
......@@ -13,6 +15,52 @@
using namespace mln;
void test_dilation_by_periodic_line(const mln::point2d& dp, int k)
{
mln_assertion((dp >= mln::point2d{0,0}));
mln::image2d<mln::uint8> input(5, 9);
mln::iota(input, 0);
// Generate ref
mln::image2d<mln::uint8> ref = mln::clone(input);
for (int i = 0; i < k; ++i)
mln_foreach(auto p, ref.domain())
if (ref.domain().has(p + dp))
ref(p) = ref(p + dp);
// Run algo
mln::se::periodic_line2d line(dp, k);
auto sup = [](auto x, auto y) { return std::max(x,y); };
mln::morpho::internal::dilation_by_periodic_line(input, line, sup, 0);
ASSERT_IMAGES_EQ(ref, input);
}
TEST(Dilation, PeriodicLine2d_horizontal)
{
test_dilation_by_periodic_line(mln::point2d{0,1}, 3);
}
TEST(Dilation, PeriodicLine2d_vertical)
{
test_dilation_by_periodic_line(mln::point2d{1,0}, 3);
}
TEST(Dilation, PeriodicLine2d_diagonal)
{
test_dilation_by_periodic_line(mln::point2d{1,-1}, 2);
}
TEST(Dilation, PeriodicLine2d_horizontal_knightmove)
{
test_dilation_by_periodic_line(mln::point2d{1,-2}, 2);
}
TEST(Dilation, PeriodicLine2d_vertical_knightmove)
{
test_dilation_by_periodic_line(mln::point2d{2,-1}, 2);
}
TEST(Dilation, Disc_euclidean)
{
......
Markdown is supported
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