dilation_by_periodic_line.hpp 5.53 KB
Newer Older
1
2
3
4
5
6
7
8
#pragma once



#include <mln/core/box.hpp>
#include <mln/core/se/periodic_line2d.hpp>
#include <mln/core/trace.hpp>
#include <mln/morpho/experimental/private/running_max_1d.hpp>
Edwin Carlinet's avatar
Edwin Carlinet committed
9
#include <mln/morpho/experimental/private/dilation_vertical_block2d.hpp>
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <mln/core/canvas/private/traverse2d.hpp>


namespace mln::morpho::details
{

  /// \param[in] in Input image
  /// \param[out] out Output image (can be the same as \p in for inplace version)
  /// \param[in] line Line structuring element
  /// \param[in] sup Supremum operator
  /// \param[in] roi Processing roi
  template <class I, class J, class BinaryFunction>
  [[gnu::noinline]] void dilation_by_periodic_line(I& in, J& out,
                                                   const mln::experimental::se::periodic_line2d& line,
                                                   BinaryFunction sup,
                                                   mln::experimental::box2d roi);

  /******************************************/
  /****          Implementation          ****/
  /******************************************/

  // fixme: could be optimized for indexable images
  template <class I>
Edwin Carlinet's avatar
Edwin Carlinet committed
33
  [[gnu::noinline]] void copy_to_periodic_line(I& f,
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
                                               mln::experimental::point2d origin,
                                               mln::experimental::point2d direction,
                                               std::size_t n,
                                               image_value_t<I>* __restrict buffer)
  {
    auto p = origin;
    for (std::size_t i = 0; i < n; ++i, p += direction)
      buffer[i] = f.at(p);
  }

  // fixme: could be optimized for indexable images
  template <class J>
  [[gnu::noinline]] void copy_from_periodic_line(const image_value_t<J>* __restrict buffer,
                                                 mln::experimental::point2d origin,
                                                 mln::experimental::point2d direction,
                                                 std::size_t n,
                                                 J output)
  {
    auto p = origin;
    for (std::size_t i = 0; i < n; ++i, p += direction)
      output(p) = buffer[i];
  }


Edwin Carlinet's avatar
Edwin Carlinet committed
58
59
60
61



  // Generic implementation
62
  template <class I, class J, class BinaryFunction>
Edwin Carlinet's avatar
Edwin Carlinet committed
63
64
65
66
  void dilation_by_periodic_line_generic(I& in, J& out,
                                         const mln::experimental::se::periodic_line2d& line,
                                         BinaryFunction sup,
                                         mln::experimental::box2d roi)
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
  {
    using V = image_value_t<I>;

    int       k      = line.repetition();
    auto      period = line.period();

    // Some sanity check
    {
      assert(period.y() >= 0);
      assert(out.domain().includes(roi));
      assert(in.domain().includes(roi));
    }

    int buffer_size = std::max(roi.width(), roi.height()) + 2 * k;

    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


    // By supplying the extension mode (user or fill), we can speed up and avoid computing
    // the extension values.

    // std::fill_n(g.get(), buffer_size, V(0));
    // std::fill_n(h.get(), buffer_size, V(0));

    auto fun = [&, k](mln::experimental::point2d origin, mln::experimental::point2d dir, std::size_t n) {
      copy_to_periodic_line(in, origin - k * period, dir, n + 2 * k, p.get());
      //copy_to_periodic_line(in, origin, dir, n, p.get() + k);
      mln::morpho::experimental::details::running_max_1d(p.get() + k, g.get() + k, h.get() + k, (int)n, k, sup);
      copy_from_periodic_line(p.get() + k, origin, dir, n, out);
    };

    mln::canvas::details::traverse_along_direction(roi, period, fun);
  }
Edwin Carlinet's avatar
Edwin Carlinet committed
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135

  // Dispatch to generic version
  template <class I, class J, class BinaryFunction>
  void dilation_by_periodic_line(I& in, J& out,
                                 const mln::experimental::se::periodic_line2d& line,
                                 BinaryFunction sup,
                                 mln::experimental::box2d roi)
  {
    dilation_by_periodic_line_generic(in, out, line, sup, roi);
  }


  template <class I, class T, class BinaryFunction>
  std::enable_if_t<std::is_arithmetic_v<T> && !std::is_same_v<T, bool>>
  dilation_by_periodic_line(I& in, mln::experimental::image2d<T>& out,
                            const mln::experimental::se::periodic_line2d& line, BinaryFunction sup,
                            mln::experimental::box2d roi)
  {
    int                   k      = line.repetition();
    [[maybe_unused]] auto period = line.period();


    // Some sanity check
    {
      assert(period.y() >= 0);
      assert(out.domain().includes(roi));
      assert(in.domain().includes(roi));
    }

    // Specialization for vertical line
    if (line.is_vertical())
    {
      mln_entering("Running specialization for vertical dilation over 2d buffer with arithmetic types");

Edwin Carlinet's avatar
Edwin Carlinet committed
136
      mln::morpho::experimental::details::running_max_2d<T>(in, out, sup, roi, k, /* use_extension = */ true, /* vertical = */ true);
Edwin Carlinet's avatar
Edwin Carlinet committed
137
138
139
140
141
142
      return;
    }
    else if (line.is_horizontal())
    {
      mln_entering("Running specialization for horizontal dilation over 2d buffer with arithmetic types");

Edwin Carlinet's avatar
Edwin Carlinet committed
143
      mln::morpho::experimental::details::running_max_2d<T>(in, out, sup, roi, k, /* use_extension = */ true, /* vertical = */ false);
Edwin Carlinet's avatar
Edwin Carlinet committed
144
145
146
147
148
149
150
151
      return;
    }

    dilation_by_periodic_line_generic(in, out, line, sup, roi);
  }



152
} // namespace mln::morpho::internal