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