]>
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> | |
20effc67 | 24 | #include <stdexcept> |
92f5a8d4 TL |
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 | ||
41 | explicit kernel_1d_adaptor(std::size_t center) | |
42 | : center_(center) | |
43 | { | |
44 | BOOST_ASSERT(center_ < this->size()); | |
45 | } | |
46 | ||
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 | ||
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 | ||
61 | kernel_1d_adaptor& operator=(kernel_1d_adaptor const& other) | |
62 | { | |
63 | Core::operator=(other); | |
64 | center_ = other.center_; | |
65 | return *this; | |
66 | } | |
67 | ||
68 | std::size_t left_size() const | |
69 | { | |
70 | BOOST_ASSERT(center_ < this->size()); | |
71 | return center_; | |
72 | } | |
73 | ||
74 | std::size_t right_size() const | |
75 | { | |
76 | BOOST_ASSERT(center_ < this->size()); | |
77 | return this->size() - center_ - 1; | |
78 | } | |
79 | ||
80 | auto center() -> std::size_t& | |
81 | { | |
82 | BOOST_ASSERT(center_ < this->size()); | |
83 | return center_; | |
84 | } | |
85 | ||
86 | 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; | |
106 | kernel_1d(std::size_t size, std::size_t center) : parent_t(size, center) {} | |
107 | ||
108 | template <typename FwdIterator> | |
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 | ||
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; | |
130 | explicit kernel_1d_fixed(std::size_t center) : parent_t(center) {} | |
131 | ||
132 | template <typename FwdIterator> | |
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 | ||
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> | |
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 | ||
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 | ||
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 | ||
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 | ||
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 | ||
196 | std::size_t upper_size() const | |
197 | { | |
198 | BOOST_ASSERT(center_.y < this->size()); | |
199 | return center_.y; | |
200 | } | |
201 | ||
202 | std::size_t lower_size() const | |
203 | { | |
204 | BOOST_ASSERT(center_.y < this->size()); | |
205 | return this->size() - center_.y - 1; | |
206 | } | |
207 | ||
208 | std::size_t left_size() const | |
209 | { | |
210 | BOOST_ASSERT(center_.x < this->size()); | |
211 | return center_.x; | |
212 | } | |
213 | ||
214 | std::size_t right_size() const | |
215 | { | |
216 | BOOST_ASSERT(center_.x < this->size()); | |
217 | return this->size() - center_.x - 1; | |
218 | } | |
219 | ||
220 | auto center_y() -> std::size_t& | |
221 | { | |
222 | BOOST_ASSERT(center_.y < this->size()); | |
223 | return center_.y; | |
224 | } | |
225 | ||
226 | auto center_y() const -> std::size_t const& | |
227 | { | |
228 | BOOST_ASSERT(center_.y < this->size()); | |
229 | return center_.y; | |
230 | } | |
231 | ||
232 | auto center_x() -> std::size_t& | |
233 | { | |
234 | BOOST_ASSERT(center_.x < this->size()); | |
235 | return center_.x; | |
236 | } | |
237 | ||
238 | auto center_x() const -> std::size_t const& | |
239 | { | |
240 | BOOST_ASSERT(center_.x < this->size()); | |
241 | return center_.x; | |
242 | } | |
243 | ||
244 | std::size_t size() const | |
245 | { | |
246 | return square_size; | |
247 | } | |
248 | ||
249 | 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; | |
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> | |
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 | ||
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 | ||
304 | kernel_2d_fixed() | |
305 | { | |
306 | this->square_size = Size; | |
307 | } | |
308 | ||
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> | |
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 | ||
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 | ||
20effc67 TL |
332 | template <typename 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 | } | |
92f5a8d4 | 341 | |
20effc67 TL |
342 | |
343 | /// \brief reverse a kernel_2d | |
344 | template<typename T, typename Allocator> | |
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> | |
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 | |
92f5a8d4 TL |
358 | |
359 | }} // namespace boost::gil | |
360 | ||
361 | #endif |