kernel.hpp 9.4 KB

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