Generic Image Library: kernel.hpp Source File

###  | #  |

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