2 // Copyright 2005-2007 Adobe Systems Incorporated
3 // Copyright 2019 Miral Shah <miralshah2211@gmail.com>
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
10 #ifndef BOOST_GIL_EXTENSION_NUMERIC_KERNEL_HPP
11 #define BOOST_GIL_EXTENSION_NUMERIC_KERNEL_HPP
13 #include <boost/gil/utilities.hpp>
14 #include <boost/gil/point.hpp>
16 #include <boost/assert.hpp>
26 namespace boost { namespace gil {
28 // Definitions of 1D fixed-size and variable-size kernels and related operations
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
39 kernel_1d_adaptor() = default;
41 explicit kernel_1d_adaptor(std::size_t center)
44 BOOST_ASSERT(center_ < this->size());
47 kernel_1d_adaptor(std::size_t size, std::size_t center)
48 : Core(size) , center_(center)
50 BOOST_ASSERT(this->size() > 0);
51 BOOST_ASSERT(center_ < this->size()); // also implies `size() > 0`
54 kernel_1d_adaptor(kernel_1d_adaptor const& other)
55 : Core(other), center_(other.center_)
57 BOOST_ASSERT(this->size() > 0);
58 BOOST_ASSERT(center_ < this->size()); // also implies `size() > 0`
61 kernel_1d_adaptor& operator=(kernel_1d_adaptor const& other)
63 Core::operator=(other);
64 center_ = other.center_;
68 std::size_t left_size() const
70 BOOST_ASSERT(center_ < this->size());
74 std::size_t right_size() const
76 BOOST_ASSERT(center_ < this->size());
77 return this->size() - center_ - 1;
80 auto center() -> std::size_t&
82 BOOST_ASSERT(center_ < this->size());
86 auto center() const -> std::size_t const&
88 BOOST_ASSERT(center_ < this->size());
93 std::size_t center_{0};
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>>
102 using parent_t = detail::kernel_1d_adaptor<std::vector<T, Allocator>>;
105 kernel_1d() = default;
106 kernel_1d(std::size_t size, std::size_t center) : parent_t(size, center) {}
108 template <typename FwdIterator>
109 kernel_1d(FwdIterator elements, std::size_t size, std::size_t center)
110 : parent_t(size, center)
112 detail::copy_n(elements, size, this->begin());
115 kernel_1d(kernel_1d const& other) : parent_t(other) {}
116 kernel_1d& operator=(kernel_1d const& other) = default;
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>>
123 using parent_t = detail::kernel_1d_adaptor<std::array<T, Size>>;
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");
129 kernel_1d_fixed() = default;
130 explicit kernel_1d_fixed(std::size_t center) : parent_t(center) {}
132 template <typename FwdIterator>
133 explicit kernel_1d_fixed(FwdIterator elements, std::size_t center)
136 detail::copy_n(elements, Size, this->begin());
139 kernel_1d_fixed(kernel_1d_fixed const& other) : parent_t(other) {}
140 kernel_1d_fixed& operator=(kernel_1d_fixed const& other) = default;
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;
148 /// \brief reverse a kernel
149 template <typename Kernel>
150 inline Kernel reverse_kernel(Kernel const& kernel)
152 Kernel result(kernel);
153 result.center() = kernel.right_size();
154 std::reverse(result.begin(), result.end());
161 template <typename Core>
162 class kernel_2d_adaptor : public Core
165 kernel_2d_adaptor() = default;
167 explicit kernel_2d_adaptor(std::size_t center_y, std::size_t center_x)
168 : center_(center_x, center_y)
170 BOOST_ASSERT(center_.y < this->size() && center_.x < this->size());
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)
176 BOOST_ASSERT(this->size() > 0);
177 BOOST_ASSERT(center_.y < this->size() && center_.x < this->size()); // implies `size() > 0`
180 kernel_2d_adaptor(kernel_2d_adaptor const& other)
181 : Core(other), square_size(other.square_size), center_(other.center_.x, other.center_.y)
183 BOOST_ASSERT(this->size() > 0);
184 BOOST_ASSERT(center_.y < this->size() && center_.x < this->size()); // implies `size() > 0`
187 kernel_2d_adaptor& operator=(kernel_2d_adaptor const& other)
189 Core::operator=(other);
190 center_.y = other.center_.y;
191 center_.x = other.center_.x;
192 square_size = other.square_size;
196 std::size_t upper_size() const
198 BOOST_ASSERT(center_.y < this->size());
202 std::size_t lower_size() const
204 BOOST_ASSERT(center_.y < this->size());
205 return this->size() - center_.y - 1;
208 std::size_t left_size() const
210 BOOST_ASSERT(center_.x < this->size());
214 std::size_t right_size() const
216 BOOST_ASSERT(center_.x < this->size());
217 return this->size() - center_.x - 1;
220 auto center_y() -> std::size_t&
222 BOOST_ASSERT(center_.y < this->size());
226 auto center_y() const -> std::size_t const&
228 BOOST_ASSERT(center_.y < this->size());
232 auto center_x() -> std::size_t&
234 BOOST_ASSERT(center_.x < this->size());
238 auto center_x() const -> std::size_t const&
240 BOOST_ASSERT(center_.x < this->size());
244 std::size_t size() const
249 typename Core::value_type at(std::size_t x, std::size_t y) const
251 if (x >= this->size() || y >= this->size())
253 throw std::out_of_range("Index out of range");
255 return this->begin()[y * this->size() + x];
259 std::size_t square_size{0};
262 point<std::size_t> center_{0, 0};
265 /// \brief variable-size kernel
269 typename Allocator = std::allocator<T>
271 class kernel_2d : public detail::kernel_2d_adaptor<std::vector<T, Allocator>>
273 using parent_t = detail::kernel_2d_adaptor<std::vector<T, Allocator>>;
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)
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)
286 detail::copy_n(elements, size, this->begin());
289 kernel_2d(kernel_2d const& other) : parent_t(other) {}
290 kernel_2d& operator=(kernel_2d const& other) = default;
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>>
298 using parent_t = detail::kernel_2d_adaptor<std::array<T, Size * Size>>;
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");
306 this->square_size = Size;
309 explicit kernel_2d_fixed(std::size_t center_y, std::size_t center_x) :
310 parent_t(center_y, center_x)
312 this->square_size = Size;
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)
319 this->square_size = Size;
320 detail::copy_n(elements, Size * Size, this->begin());
323 kernel_2d_fixed(kernel_2d_fixed const& other) : parent_t(other) {}
324 kernel_2d_fixed& operator=(kernel_2d_fixed const& other) = default;
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;
332 template <typename Kernel>
333 inline Kernel reverse_kernel_2d(Kernel const& kernel)
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());
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)
347 return reverse_kernel_2d(kernel);
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)
354 return reverse_kernel_2d(kernel);
359 }} // namespace boost::gil