File indexing completed on 2025-12-16 09:51:52
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #ifndef BOOST_GIL_IMAGE_PROCESSING_KERNEL_HPP
0012 #define BOOST_GIL_IMAGE_PROCESSING_KERNEL_HPP
0013
0014 #include <boost/gil/utilities.hpp>
0015 #include <boost/gil/point.hpp>
0016
0017 #include <boost/assert.hpp>
0018
0019 #include <algorithm>
0020 #include <array>
0021 #include <cstddef>
0022 #include <memory>
0023 #include <vector>
0024 #include <cmath>
0025 #include <stdexcept>
0026
0027 namespace boost { namespace gil {
0028
0029
0030
0031 namespace detail {
0032
0033
0034
0035
0036 template <typename Core>
0037 class kernel_1d_adaptor : public Core
0038 {
0039 public:
0040 kernel_1d_adaptor() = default;
0041
0042 explicit kernel_1d_adaptor(std::size_t center)
0043 : center_(center)
0044 {
0045 BOOST_ASSERT(center_ < this->size());
0046 }
0047
0048 kernel_1d_adaptor(std::size_t size, std::size_t center)
0049 : Core(size) , center_(center)
0050 {
0051 BOOST_ASSERT(this->size() > 0);
0052 BOOST_ASSERT(center_ < this->size());
0053 }
0054
0055 kernel_1d_adaptor(kernel_1d_adaptor const& other)
0056 : Core(other), center_(other.center_)
0057 {
0058 BOOST_ASSERT(this->size() > 0);
0059 BOOST_ASSERT(center_ < this->size());
0060 }
0061
0062 kernel_1d_adaptor& operator=(kernel_1d_adaptor const& other)
0063 {
0064 Core::operator=(other);
0065 center_ = other.center_;
0066 return *this;
0067 }
0068
0069 std::size_t left_size() const
0070 {
0071 BOOST_ASSERT(center_ < this->size());
0072 return center_;
0073 }
0074
0075 std::size_t right_size() const
0076 {
0077 BOOST_ASSERT(center_ < this->size());
0078 return this->size() - center_ - 1;
0079 }
0080
0081 auto center() -> std::size_t&
0082 {
0083 BOOST_ASSERT(center_ < this->size());
0084 return center_;
0085 }
0086
0087 auto center() const -> std::size_t const&
0088 {
0089 BOOST_ASSERT(center_ < this->size());
0090 return center_;
0091 }
0092
0093 private:
0094 std::size_t center_{0};
0095 };
0096
0097 }
0098
0099
0100 template <typename T, typename Allocator = std::allocator<T> >
0101 class kernel_1d : public detail::kernel_1d_adaptor<std::vector<T, Allocator>>
0102 {
0103 using parent_t = detail::kernel_1d_adaptor<std::vector<T, Allocator>>;
0104 public:
0105
0106 kernel_1d() = default;
0107 kernel_1d(std::size_t size, std::size_t center) : parent_t(size, center) {}
0108
0109 template <typename FwdIterator>
0110 kernel_1d(FwdIterator elements, std::size_t size, std::size_t center)
0111 : parent_t(size, center)
0112 {
0113 detail::copy_n(elements, size, this->begin());
0114 }
0115
0116 kernel_1d(kernel_1d const& other) : parent_t(other) {}
0117 kernel_1d& operator=(kernel_1d const& other) = default;
0118 };
0119
0120
0121 template <typename T,std::size_t Size>
0122 class kernel_1d_fixed : public detail::kernel_1d_adaptor<std::array<T, Size>>
0123 {
0124 using parent_t = detail::kernel_1d_adaptor<std::array<T, Size>>;
0125 public:
0126 static constexpr std::size_t static_size = Size;
0127 static_assert(static_size > 0, "kernel must have size greater than 0");
0128 static_assert(static_size % 2 == 1, "kernel size must be odd to ensure validity at the center");
0129
0130 kernel_1d_fixed() = default;
0131 explicit kernel_1d_fixed(std::size_t center) : parent_t(center) {}
0132
0133 template <typename FwdIterator>
0134 explicit kernel_1d_fixed(FwdIterator elements, std::size_t center)
0135 : parent_t(center)
0136 {
0137 detail::copy_n(elements, Size, this->begin());
0138 }
0139
0140 kernel_1d_fixed(kernel_1d_fixed const& other) : parent_t(other) {}
0141 kernel_1d_fixed& operator=(kernel_1d_fixed const& other) = default;
0142 };
0143
0144
0145
0146 template <typename T,std::size_t Size>
0147 constexpr std::size_t kernel_1d_fixed<T, Size>::static_size;
0148
0149
0150 template <typename Kernel>
0151 inline Kernel reverse_kernel(Kernel const& kernel)
0152 {
0153 Kernel result(kernel);
0154 result.center() = kernel.right_size();
0155 std::reverse(result.begin(), result.end());
0156 return result;
0157 }
0158
0159
0160 namespace detail {
0161
0162 template <typename Core>
0163 class kernel_2d_adaptor : public Core
0164 {
0165 public:
0166 kernel_2d_adaptor() = default;
0167
0168 explicit kernel_2d_adaptor(std::size_t center_y, std::size_t center_x)
0169 : center_(center_x, center_y)
0170 {
0171 BOOST_ASSERT(center_.y < this->size() && center_.x < this->size());
0172 }
0173
0174 kernel_2d_adaptor(std::size_t size, std::size_t center_y, std::size_t center_x)
0175 : Core(size * size), square_size(size), center_(center_x, center_y)
0176 {
0177 BOOST_ASSERT(this->size() > 0);
0178 BOOST_ASSERT(center_.y < this->size() && center_.x < this->size());
0179 }
0180
0181 kernel_2d_adaptor(kernel_2d_adaptor const& other)
0182 : Core(other), square_size(other.square_size), center_(other.center_.x, other.center_.y)
0183 {
0184 BOOST_ASSERT(this->size() > 0);
0185 BOOST_ASSERT(center_.y < this->size() && center_.x < this->size());
0186 }
0187
0188 kernel_2d_adaptor& operator=(kernel_2d_adaptor const& other)
0189 {
0190 Core::operator=(other);
0191 center_.y = other.center_.y;
0192 center_.x = other.center_.x;
0193 square_size = other.square_size;
0194 return *this;
0195 }
0196
0197 std::size_t upper_size() const
0198 {
0199 BOOST_ASSERT(center_.y < this->size());
0200 return center_.y;
0201 }
0202
0203 std::size_t lower_size() const
0204 {
0205 BOOST_ASSERT(center_.y < this->size());
0206 return this->size() - center_.y - 1;
0207 }
0208
0209 std::size_t left_size() const
0210 {
0211 BOOST_ASSERT(center_.x < this->size());
0212 return center_.x;
0213 }
0214
0215 std::size_t right_size() const
0216 {
0217 BOOST_ASSERT(center_.x < this->size());
0218 return this->size() - center_.x - 1;
0219 }
0220
0221 auto center_y() -> std::size_t&
0222 {
0223 BOOST_ASSERT(center_.y < this->size());
0224 return center_.y;
0225 }
0226
0227 auto center_y() const -> std::size_t const&
0228 {
0229 BOOST_ASSERT(center_.y < this->size());
0230 return center_.y;
0231 }
0232
0233 auto center_x() -> std::size_t&
0234 {
0235 BOOST_ASSERT(center_.x < this->size());
0236 return center_.x;
0237 }
0238
0239 auto center_x() const -> std::size_t const&
0240 {
0241 BOOST_ASSERT(center_.x < this->size());
0242 return center_.x;
0243 }
0244
0245 std::size_t size() const
0246 {
0247 return square_size;
0248 }
0249
0250 typename Core::value_type at(std::size_t x, std::size_t y) const
0251 {
0252 if (x >= this->size() || y >= this->size())
0253 {
0254 throw std::out_of_range("Index out of range");
0255 }
0256 return this->begin()[y * this->size() + x];
0257 }
0258
0259 protected:
0260 std::size_t square_size{0};
0261
0262 private:
0263 point<std::size_t> center_{0, 0};
0264 };
0265
0266
0267 template
0268 <
0269 typename T,
0270 typename Allocator = std::allocator<T>
0271 >
0272 class kernel_2d : public detail::kernel_2d_adaptor<std::vector<T, Allocator>>
0273 {
0274 using parent_t = detail::kernel_2d_adaptor<std::vector<T, Allocator>>;
0275
0276 public:
0277
0278 kernel_2d() = default;
0279 kernel_2d(std::size_t size,std::size_t center_y, std::size_t center_x)
0280 : parent_t(size, center_y, center_x)
0281 {}
0282
0283 template <typename FwdIterator>
0284 kernel_2d(FwdIterator elements, std::size_t size, std::size_t center_y, std::size_t center_x)
0285 : parent_t(static_cast<int>(std::sqrt(size)), center_y, center_x)
0286 {
0287 detail::copy_n(elements, size, this->begin());
0288 }
0289
0290 kernel_2d(kernel_2d const& other) : parent_t(other) {}
0291 kernel_2d& operator=(kernel_2d const& other) = default;
0292 };
0293
0294
0295 template <typename T, std::size_t Size>
0296 class kernel_2d_fixed :
0297 public detail::kernel_2d_adaptor<std::array<T, Size * Size>>
0298 {
0299 using parent_t = detail::kernel_2d_adaptor<std::array<T, Size * Size>>;
0300 public:
0301 static constexpr std::size_t static_size = Size;
0302 static_assert(static_size > 0, "kernel must have size greater than 0");
0303 static_assert(static_size % 2 == 1, "kernel size must be odd to ensure validity at the center");
0304
0305 kernel_2d_fixed()
0306 {
0307 this->square_size = Size;
0308 }
0309
0310 explicit kernel_2d_fixed(std::size_t center_y, std::size_t center_x) :
0311 parent_t(center_y, center_x)
0312 {
0313 this->square_size = Size;
0314 }
0315
0316 template <typename FwdIterator>
0317 explicit kernel_2d_fixed(FwdIterator elements, std::size_t center_y, std::size_t center_x)
0318 : parent_t(center_y, center_x)
0319 {
0320 this->square_size = Size;
0321 detail::copy_n(elements, Size * Size, this->begin());
0322 }
0323
0324 kernel_2d_fixed(kernel_2d_fixed const& other) : parent_t(other) {}
0325 kernel_2d_fixed& operator=(kernel_2d_fixed const& other) = default;
0326 };
0327
0328
0329
0330 template <typename T, std::size_t Size>
0331 constexpr std::size_t kernel_2d_fixed<T, Size>::static_size;
0332
0333 template <typename Kernel>
0334 inline Kernel reverse_kernel_2d(Kernel const& kernel)
0335 {
0336 Kernel result(kernel);
0337 result.center_x() = kernel.lower_size();
0338 result.center_y() = kernel.right_size();
0339 std::reverse(result.begin(), result.end());
0340 return result;
0341 }
0342
0343
0344
0345 template<typename T, typename Allocator>
0346 inline kernel_2d<T, Allocator> reverse_kernel(kernel_2d<T, Allocator> const& kernel)
0347 {
0348 return reverse_kernel_2d(kernel);
0349 }
0350
0351
0352 template<typename T, std::size_t Size>
0353 inline kernel_2d_fixed<T, Size> reverse_kernel(kernel_2d_fixed<T, Size> const& kernel)
0354 {
0355 return reverse_kernel_2d(kernel);
0356 }
0357
0358 }
0359
0360 }}
0361
0362 #endif