filter.hpp 5.78 KB
Newer Older
Edwin Carlinet's avatar
Edwin Carlinet committed
1
2
3
4
#pragma once

#include <mln/core/image/image.hpp>
#include <mln/core/image/view/adaptor.hpp>
Michaël Roynard's avatar
Michaël Roynard committed
5
#include <mln/core/image/view/clip.hpp>
Edwin Carlinet's avatar
Edwin Carlinet committed
6
#include <mln/core/rangev3/view/filter.hpp>
Michaël Roynard's avatar
WIP    
Michaël Roynard committed
7
#include <mln/core/rangev3/view/remove_if.hpp>
Michaël Roynard's avatar
Michaël Roynard committed
8

Michaël Roynard's avatar
Michaël Roynard committed
9
10
11
12
#include <range/v3/empty.hpp>
#include <range/v3/size.hpp>
#include <range/v3/utility/functional.hpp>

Edwin Carlinet's avatar
Edwin Carlinet committed
13
14
#include <type_traits>

Michaël Roynard's avatar
Michaël Roynard committed
15

Edwin Carlinet's avatar
Edwin Carlinet committed
16
17
18
19
namespace mln
{

  template <class I, class F>
Michaël Roynard's avatar
Michaël Roynard committed
20
  class filter_view : public image_adaptor<I>, public experimental::Image<filter_view<I, F>>
Edwin Carlinet's avatar
Edwin Carlinet committed
21
  {
Michaël Roynard's avatar
Michaël Roynard committed
22
    using fun_t = F;
Edwin Carlinet's avatar
Edwin Carlinet committed
23
24
25
26
27
    fun_t f;

  public:
    /// Type definitions
    /// \{
Michaël Roynard's avatar
Michaël Roynard committed
28
    using new_pixel_type = image_pixel_t<I>;
Michaël Roynard's avatar
Michaël Roynard committed
29
    using typename filter_view::image_adaptor::point_type;
Edwin Carlinet's avatar
Edwin Carlinet committed
30
31
    using typename filter_view::image_adaptor::reference;
    using typename filter_view::image_adaptor::value_type;
Michaël Roynard's avatar
WIP    
Michaël Roynard committed
32

Michaël Roynard's avatar
Michaël Roynard committed
33
    class domain_type : ::ranges::view_base
Michaël Roynard's avatar
WIP    
Michaël Roynard committed
34
    {
Michaël Roynard's avatar
Michaël Roynard committed
35
36
37
      using fun_t = ::ranges::composed<F, std::reference_wrapper<I>>; // f o I::operator()
      using dom_t = decltype(std::declval<I*>()->domain());
      using rng_t = mln::ranges::remove_if_view<::ranges::view::all_t<dom_t>, ::ranges::logical_negate<fun_t>>;
Michaël Roynard's avatar
WIP    
Michaël Roynard committed
38

Michaël Roynard's avatar
Michaël Roynard committed
39
      fun_t         m_fun;
Michaël Roynard's avatar
Michaël Roynard committed
40
41
      dom_t         m_dom;
      mutable rng_t m_rng; // domain can be a range, so non-const
Michaël Roynard's avatar
Michaël Roynard committed
42
43

      static_assert(::ranges::ForwardRange<rng_t>());
Michaël Roynard's avatar
Michaël Roynard committed
44
      static_assert(::ranges::View<::ranges::view::all_t<dom_t>>());
Michaël Roynard's avatar
WIP    
Michaël Roynard committed
45
46

    public:
Michaël Roynard's avatar
Michaël Roynard committed
47
48
      using value_type = ::ranges::range_value_t<rng_t>;
      using reference  = ::ranges::range_reference_t<rng_t>;
Michaël Roynard's avatar
WIP    
Michaël Roynard committed
49

Michaël Roynard's avatar
WIP    
Michaël Roynard committed
50
      domain_type(I* ima, F f)
Michaël Roynard's avatar
Michaël Roynard committed
51
        : m_fun(std::move(f), std::ref(*ima))
Michaël Roynard's avatar
Michaël Roynard committed
52
        , m_dom(ima->domain())
Michaël Roynard's avatar
Michaël Roynard committed
53
        , m_rng(mln::ranges::view::filter(::ranges::view::all(m_dom), m_fun))
Michaël Roynard's avatar
WIP    
Michaël Roynard committed
54
55
56
      {
      }

Michaël Roynard's avatar
Michaël Roynard committed
57
58
      auto begin() const { return ::ranges::begin(m_rng); }
      auto end() const { return ::ranges::end(m_rng); }
Michaël Roynard's avatar
WIP    
Michaël Roynard committed
59

60
      bool has(point_type p) const { return m_dom.has(p) && m_fun(p); }
Michaël Roynard's avatar
Michaël Roynard committed
61
      bool empty() const { return ::ranges::empty(m_rng); }
Michaël Roynard's avatar
WIP    
Michaël Roynard committed
62
    };
Edwin Carlinet's avatar
Edwin Carlinet committed
63
64
    /// \}

Michaël Roynard's avatar
WIP    
Michaël Roynard committed
65

Edwin Carlinet's avatar
Edwin Carlinet committed
66
67
    /// Traits & Image Properties
    /// \{
Michaël Roynard's avatar
Michaël Roynard committed
68
    using accessible = image_accessible_t<I>;
Michaël Roynard's avatar
Michaël Roynard committed
69
    using indexable  = image_indexable_t<I>;
Michaël Roynard's avatar
Michaël Roynard committed
70
71
72
    using view       = std::true_type;
    // May be too restrictive (might be extended by image)
    using extension_category = mln::extension::none_extension_tag;
Michaël Roynard's avatar
Michaël Roynard committed
73
    using concrete_type      = clip_view<image_concrete_t<I>, domain_type>;
Michaël Roynard's avatar
Michaël Roynard committed
74
    template <class V>
Michaël Roynard's avatar
Michaël Roynard committed
75
    using ch_value_type = clip_view<image_ch_value_t<I, V>, domain_type>;
Edwin Carlinet's avatar
Edwin Carlinet committed
76
77
    /// \}

Michaël Roynard's avatar
Michaël Roynard committed
78
    // Checks
Michaël Roynard's avatar
Michaël Roynard committed
79
    PYLENE_CONCEPT_TS_ASSERT(mln::concepts::AccessibleImage<I>, "The image must be accessible.");
Edwin Carlinet's avatar
Edwin Carlinet committed
80
81
82
83
84
85
86

  private:
    struct pix_filter_fn
    {
      fun_t f;

      template <class Pix>
Michaël Roynard's avatar
Michaël Roynard committed
87
      bool operator()(const Pix& px) const
Edwin Carlinet's avatar
Edwin Carlinet committed
88
89
90
91
92
      {
        return f(px.val());
      }
    };

Michaël Roynard's avatar
WIP    
Michaël Roynard committed
93

Edwin Carlinet's avatar
Edwin Carlinet committed
94
95
96
97
98
99
100
  public:
    filter_view(I ima, F fun)
      : filter_view::image_adaptor{std::move(ima)}
      , f{std::move(fun)}
    {
    }

Michaël Roynard's avatar
Michaël Roynard committed
101
102
103
104
105
106
107
108
109
110
    internal::initializer<concrete_type, clip_view<I, domain_type>> concretize() const
    {
      return mln::clip_view{this->base(), domain()};
    }

    template <typename V>
    internal::initializer<ch_value_type<V>, clip_view<I, domain_type>> ch_value() const
    {
      return mln::clip_view{this->base(), domain()};
    }
Edwin Carlinet's avatar
Edwin Carlinet committed
111

Michaël Roynard's avatar
Michaël Roynard committed
112
    domain_type domain() const { return {const_cast<I*>(&this->base()), this->f}; }
Edwin Carlinet's avatar
Edwin Carlinet committed
113
114
115
116
117
118
119
120
121
122

    auto new_values() { return mln::ranges::view::filter(this->base().new_values(), f); }

    auto new_pixels()
    {
      auto g = [f_ = this->f](const auto& px) -> bool { return f_(px.val()); };
      return mln::ranges::view::filter(this->base().new_pixels(), g);
    }


Michaël Roynard's avatar
Michaël Roynard committed
123
124
125
126
127
128
129
130
131
132
    /// Indexable-image related methods
    /// \{
    template <typename dummy = I>
    reference operator[](image_index_t<dummy> i)
    {
      return this->base()[i];
    }
    /// \}


Michaël Roynard's avatar
Michaël Roynard committed
133
134
135
136
    /// Accessible-image related methods
    /// \{
    template <typename Ret = reference>
    std::enable_if_t<accessible::value, Ret> operator()(point_type p)
Edwin Carlinet's avatar
Edwin Carlinet committed
137
    {
Michaël Roynard's avatar
Michaël Roynard committed
138
      mln_precondition(this->base().domain().has(p));
Michaël Roynard's avatar
Michaël Roynard committed
139
140
      mln_precondition(std::invoke(f, this->base()(p)));
      return this->base()(p);
Edwin Carlinet's avatar
Edwin Carlinet committed
141
    }
Michaël Roynard's avatar
Michaël Roynard committed
142
143
    template <typename Ret = reference>
    std::enable_if_t<accessible::value, Ret> at(point_type p)
Edwin Carlinet's avatar
Edwin Carlinet committed
144
145
146
    {
      return this->base().at(p);
    }
Michaël Roynard's avatar
Michaël Roynard committed
147
148
    template <typename Ret = new_pixel_type>
    std::enable_if_t<accessible::value, Ret> new_pixel(point_type p)
Edwin Carlinet's avatar
Edwin Carlinet committed
149
150
151
152
153
    {
      mln_precondition(this->base().domain().has(p));
      mln_precondition(std::invoke(f, this->base().at(p)));
      return this->base().new_pixel(p);
    }
Michaël Roynard's avatar
Michaël Roynard committed
154
155
    template <typename Ret = new_pixel_type>
    std::enable_if_t<accessible::value, Ret> new_pixel_at(point_type p)
Edwin Carlinet's avatar
Edwin Carlinet committed
156
157
158
    {
      return this->base().new_pixel_at(p);
    }
Michaël Roynard's avatar
Michaël Roynard committed
159
160
161
    /// \}


Michaël Roynard's avatar
Michaël Roynard committed
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
    /// IndexableAndAccessible-image related methods
    /// \{
    template <typename dummy = I>
    std::enable_if_t<(indexable::value && accessible::value), image_index_t<dummy>> index_of_point(point_type p) const
    {
      return this->base().index_of_point(p);
    }

    template <typename dummy = I>
    point_type point_at_index(std::enable_if_t<(indexable::value && accessible::value), image_index_t<dummy>> i) const
    {
      return this->base().point_at_index(i);
    }

    template <typename dummy = I>
    std::enable_if_t<(indexable::value && accessible::value), image_index_t<dummy>> delta_index(point_type p) const
    {
      return this->base().delta_index(p);
    }
    /// \}


Michaël Roynard's avatar
Michaël Roynard committed
184
185
186
187
188
189
    /// Raw-image related methods
    /// \{
    auto data() const           = delete;
    auto data()                 = delete;
    auto strides(int dim) const = delete;
    /// \}
Edwin Carlinet's avatar
Edwin Carlinet committed
190
191
192
193
194
195
196
197
  };


  namespace view
  {
    template <class I, class P>
    filter_view<I, P> filter(I ima, P predicate)
    {
Michaël Roynard's avatar
Michaël Roynard committed
198
      static_assert(mln::is_a<I, experimental::Image>());
Edwin Carlinet's avatar
Edwin Carlinet committed
199
200
      static_assert(std::is_invocable_r<bool, P, image_reference_t<I>>());

Michaël Roynard's avatar
Michaël Roynard committed
201
      return {std::move(ima), std::move(predicate)};
Edwin Carlinet's avatar
Edwin Carlinet committed
202
    }
Michaël Roynard's avatar
Michaël Roynard committed
203
  } // namespace view
Edwin Carlinet's avatar
Edwin Carlinet committed
204

Michaël Roynard's avatar
Michaël Roynard committed
205
} // namespace mln