• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2005-2007 Adobe Systems Incorporated
3 // Copyright 2019 Miral Shah <miralshah2211@gmail.com>
4 //
5 // Distributed under the Boost Software License, Version 1.0
6 // See accompanying file LICENSE_1_0.txt or copy at
7 // http://www.boost.org/LICENSE_1_0.txt
8 //
9 
10 #ifndef BOOST_GIL_EXTENSION_NUMERIC_KERNEL_HPP
11 #define BOOST_GIL_EXTENSION_NUMERIC_KERNEL_HPP
12 
13 #include <boost/gil/utilities.hpp>
14 #include <boost/gil/point.hpp>
15 
16 #include <boost/assert.hpp>
17 
18 #include <algorithm>
19 #include <array>
20 #include <cstddef>
21 #include <memory>
22 #include <vector>
23 #include <cmath>
24 #include <stdexcept>
25 
26 namespace boost { namespace gil {
27 
28 // Definitions of 1D fixed-size and variable-size kernels and related operations
29 
30 namespace detail {
31 
32 /// \brief kernel adaptor for one-dimensional cores
33 /// Core needs to provide size(),begin(),end(),operator[],
34 /// value_type,iterator,const_iterator,reference,const_reference
35 template <typename Core>
36 class kernel_1d_adaptor : public Core
37 {
38 public:
39     kernel_1d_adaptor() = default;
40 
kernel_1d_adaptor(std::size_t center)41     explicit kernel_1d_adaptor(std::size_t center)
42         : center_(center)
43     {
44         BOOST_ASSERT(center_ < this->size());
45     }
46 
kernel_1d_adaptor(std::size_t size,std::size_t center)47     kernel_1d_adaptor(std::size_t size, std::size_t center)
48         : Core(size) , center_(center)
49     {
50         BOOST_ASSERT(this->size() > 0);
51         BOOST_ASSERT(center_ < this->size()); // also implies `size() > 0`
52     }
53 
kernel_1d_adaptor(kernel_1d_adaptor const & other)54     kernel_1d_adaptor(kernel_1d_adaptor const& other)
55         : Core(other), center_(other.center_)
56     {
57         BOOST_ASSERT(this->size() > 0);
58         BOOST_ASSERT(center_ < this->size()); // also implies `size() > 0`
59     }
60 
operator =(kernel_1d_adaptor const & other)61     kernel_1d_adaptor& operator=(kernel_1d_adaptor const& other)
62     {
63         Core::operator=(other);
64         center_ = other.center_;
65         return *this;
66     }
67 
left_size() const68     std::size_t left_size() const
69     {
70         BOOST_ASSERT(center_ < this->size());
71         return center_;
72     }
73 
right_size() const74     std::size_t right_size() const
75     {
76         BOOST_ASSERT(center_ < this->size());
77         return this->size() - center_ - 1;
78     }
79 
center()80     auto center() -> std::size_t&
81     {
82         BOOST_ASSERT(center_ < this->size());
83         return center_;
84     }
85 
center() const86     auto center() const -> std::size_t const&
87     {
88         BOOST_ASSERT(center_ < this->size());
89         return center_;
90     }
91 
92 private:
93     std::size_t center_{0};
94 };
95 
96 } // namespace detail
97 
98 /// \brief variable-size kernel
99 template <typename T, typename Allocator = std::allocator<T> >
100 class kernel_1d : public detail::kernel_1d_adaptor<std::vector<T, Allocator>>
101 {
102     using parent_t = detail::kernel_1d_adaptor<std::vector<T, Allocator>>;
103 public:
104 
105     kernel_1d() = default;
kernel_1d(std::size_t size,std::size_t center)106     kernel_1d(std::size_t size, std::size_t center) : parent_t(size, center) {}
107 
108     template <typename FwdIterator>
kernel_1d(FwdIterator elements,std::size_t size,std::size_t center)109     kernel_1d(FwdIterator elements, std::size_t size, std::size_t center)
110         : parent_t(size, center)
111     {
112         detail::copy_n(elements, size, this->begin());
113     }
114 
kernel_1d(kernel_1d const & other)115     kernel_1d(kernel_1d const& other) : parent_t(other) {}
116     kernel_1d& operator=(kernel_1d const& other) = default;
117 };
118 
119 /// \brief static-size kernel
120 template <typename T,std::size_t Size>
121 class kernel_1d_fixed : public detail::kernel_1d_adaptor<std::array<T, Size>>
122 {
123     using parent_t = detail::kernel_1d_adaptor<std::array<T, Size>>;
124 public:
125     static constexpr std::size_t static_size = Size;
126     static_assert(static_size > 0, "kernel must have size greater than 0");
127     static_assert(static_size % 2 == 1, "kernel size must be odd to ensure validity at the center");
128 
129     kernel_1d_fixed() = default;
kernel_1d_fixed(std::size_t center)130     explicit kernel_1d_fixed(std::size_t center) : parent_t(center) {}
131 
132     template <typename FwdIterator>
kernel_1d_fixed(FwdIterator elements,std::size_t center)133     explicit kernel_1d_fixed(FwdIterator elements, std::size_t center)
134         : parent_t(center)
135     {
136         detail::copy_n(elements, Size, this->begin());
137     }
138 
kernel_1d_fixed(kernel_1d_fixed const & other)139     kernel_1d_fixed(kernel_1d_fixed const& other) : parent_t(other) {}
140     kernel_1d_fixed& operator=(kernel_1d_fixed const& other) = default;
141 };
142 
143 // TODO: This data member is odr-used and definition at namespace scope
144 // is required by C++11. Redundant and deprecated in C++17.
145 template <typename T,std::size_t Size>
146 constexpr std::size_t kernel_1d_fixed<T, Size>::static_size;
147 
148 /// \brief reverse a kernel
149 template <typename Kernel>
reverse_kernel(Kernel const & kernel)150 inline Kernel reverse_kernel(Kernel const& kernel)
151 {
152     Kernel result(kernel);
153     result.center() = kernel.right_size();
154     std::reverse(result.begin(), result.end());
155     return result;
156 }
157 
158 
159 namespace detail {
160 
161 template <typename Core>
162 class kernel_2d_adaptor : public Core
163 {
164 public:
165     kernel_2d_adaptor() = default;
166 
kernel_2d_adaptor(std::size_t center_y,std::size_t center_x)167     explicit kernel_2d_adaptor(std::size_t center_y, std::size_t center_x)
168         : center_(center_x, center_y)
169     {
170         BOOST_ASSERT(center_.y < this->size() && center_.x < this->size());
171     }
172 
kernel_2d_adaptor(std::size_t size,std::size_t center_y,std::size_t center_x)173     kernel_2d_adaptor(std::size_t size, std::size_t center_y, std::size_t center_x)
174         : Core(size * size), square_size(size), center_(center_x, center_y)
175     {
176         BOOST_ASSERT(this->size() > 0);
177         BOOST_ASSERT(center_.y < this->size() && center_.x < this->size()); // implies `size() > 0`
178     }
179 
kernel_2d_adaptor(kernel_2d_adaptor const & other)180     kernel_2d_adaptor(kernel_2d_adaptor const& other)
181         : Core(other), square_size(other.square_size), center_(other.center_.x, other.center_.y)
182     {
183         BOOST_ASSERT(this->size() > 0);
184         BOOST_ASSERT(center_.y < this->size() && center_.x < this->size()); // implies `size() > 0`
185     }
186 
operator =(kernel_2d_adaptor const & other)187     kernel_2d_adaptor& operator=(kernel_2d_adaptor const& other)
188     {
189         Core::operator=(other);
190         center_.y = other.center_.y;
191         center_.x = other.center_.x;
192         square_size = other.square_size;
193         return *this;
194     }
195 
upper_size() const196     std::size_t upper_size() const
197     {
198         BOOST_ASSERT(center_.y < this->size());
199         return center_.y;
200     }
201 
lower_size() const202     std::size_t lower_size() const
203     {
204         BOOST_ASSERT(center_.y < this->size());
205         return this->size() - center_.y - 1;
206     }
207 
left_size() const208     std::size_t left_size() const
209     {
210         BOOST_ASSERT(center_.x < this->size());
211         return center_.x;
212     }
213 
right_size() const214     std::size_t right_size() const
215     {
216         BOOST_ASSERT(center_.x < this->size());
217         return this->size() - center_.x - 1;
218     }
219 
center_y()220     auto center_y() -> std::size_t&
221     {
222         BOOST_ASSERT(center_.y < this->size());
223         return center_.y;
224     }
225 
center_y() const226     auto center_y() const -> std::size_t const&
227     {
228         BOOST_ASSERT(center_.y < this->size());
229         return center_.y;
230     }
231 
center_x()232     auto center_x() -> std::size_t&
233     {
234         BOOST_ASSERT(center_.x < this->size());
235         return center_.x;
236     }
237 
center_x() const238     auto center_x() const -> std::size_t const&
239     {
240         BOOST_ASSERT(center_.x < this->size());
241         return center_.x;
242     }
243 
size() const244     std::size_t size() const
245     {
246         return square_size;
247     }
248 
at(std::size_t x,std::size_t y) const249     typename Core::value_type at(std::size_t x, std::size_t y) const
250     {
251         if (x >= this->size() || y >= this->size())
252         {
253             throw std::out_of_range("Index out of range");
254         }
255         return this->begin()[y * this->size() + x];
256     }
257 
258 protected:
259     std::size_t square_size{0};
260 
261 private:
262     point<std::size_t> center_{0, 0};
263 };
264 
265 /// \brief variable-size kernel
266 template
267 <
268     typename T,
269     typename Allocator = std::allocator<T>
270 >
271 class kernel_2d : public detail::kernel_2d_adaptor<std::vector<T, Allocator>>
272 {
273     using parent_t = detail::kernel_2d_adaptor<std::vector<T, Allocator>>;
274 
275 public:
276 
277     kernel_2d() = default;
kernel_2d(std::size_t size,std::size_t center_y,std::size_t center_x)278     kernel_2d(std::size_t size,std::size_t center_y, std::size_t center_x)
279         : parent_t(size, center_y, center_x)
280     {}
281 
282     template <typename FwdIterator>
kernel_2d(FwdIterator elements,std::size_t size,std::size_t center_y,std::size_t center_x)283     kernel_2d(FwdIterator elements, std::size_t size, std::size_t center_y, std::size_t center_x)
284         : parent_t(static_cast<int>(std::sqrt(size)), center_y, center_x)
285     {
286         detail::copy_n(elements, size, this->begin());
287     }
288 
kernel_2d(kernel_2d const & other)289     kernel_2d(kernel_2d const& other) : parent_t(other) {}
290     kernel_2d& operator=(kernel_2d const& other) = default;
291 };
292 
293 /// \brief static-size kernel
294 template <typename T, std::size_t Size>
295 class kernel_2d_fixed :
296     public detail::kernel_2d_adaptor<std::array<T, Size * Size>>
297 {
298     using parent_t = detail::kernel_2d_adaptor<std::array<T, Size * Size>>;
299 public:
300     static constexpr std::size_t static_size = Size;
301     static_assert(static_size > 0, "kernel must have size greater than 0");
302     static_assert(static_size % 2 == 1, "kernel size must be odd to ensure validity at the center");
303 
kernel_2d_fixed()304     kernel_2d_fixed()
305     {
306         this->square_size = Size;
307     }
308 
kernel_2d_fixed(std::size_t center_y,std::size_t center_x)309     explicit kernel_2d_fixed(std::size_t center_y, std::size_t center_x) :
310         parent_t(center_y, center_x)
311     {
312         this->square_size = Size;
313     }
314 
315     template <typename FwdIterator>
kernel_2d_fixed(FwdIterator elements,std::size_t center_y,std::size_t center_x)316     explicit kernel_2d_fixed(FwdIterator elements, std::size_t center_y, std::size_t center_x)
317         : parent_t(center_y, center_x)
318     {
319         this->square_size = Size;
320         detail::copy_n(elements, Size * Size, this->begin());
321     }
322 
kernel_2d_fixed(kernel_2d_fixed const & other)323     kernel_2d_fixed(kernel_2d_fixed const& other) : parent_t(other) {}
324     kernel_2d_fixed& operator=(kernel_2d_fixed const& other) = default;
325 };
326 
327 // TODO: This data member is odr-used and definition at namespace scope
328 // is required by C++11. Redundant and deprecated in C++17.
329 template <typename T, std::size_t Size>
330 constexpr std::size_t kernel_2d_fixed<T, Size>::static_size;
331 
332 template <typename Kernel>
reverse_kernel_2d(Kernel const & kernel)333 inline Kernel reverse_kernel_2d(Kernel const& kernel)
334 {
335     Kernel result(kernel);
336     result.center_x() = kernel.lower_size();
337     result.center_y() = kernel.right_size();
338     std::reverse(result.begin(), result.end());
339     return result;
340 }
341 
342 
343 /// \brief reverse a kernel_2d
344 template<typename T, typename Allocator>
reverse_kernel(kernel_2d<T,Allocator> const & kernel)345 inline kernel_2d<T, Allocator>  reverse_kernel(kernel_2d<T, Allocator> const& kernel)
346 {
347    return reverse_kernel_2d(kernel);
348 }
349 
350 /// \brief reverse a kernel_2d
351 template<typename T, std::size_t Size>
reverse_kernel(kernel_2d_fixed<T,Size> const & kernel)352 inline kernel_2d_fixed<T, Size> reverse_kernel(kernel_2d_fixed<T, Size> const& kernel)
353 {
354    return reverse_kernel_2d(kernel);
355 }
356 
357 } //namespace detail
358 
359 }} // namespace boost::gil
360 
361 #endif
362