Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-12-16 09:51:52

0001 //
0002 // Copyright 2005-2007 Adobe Systems Incorporated
0003 // Copyright 2019 Miral Shah <miralshah2211@gmail.com>
0004 // Copyright 2022 Pranam Lashkari <plashkari628@gmail.com>
0005 //
0006 // Distributed under the Boost Software License, Version 1.0
0007 // See accompanying file LICENSE_1_0.txt or copy at
0008 // http://www.boost.org/LICENSE_1_0.txt
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 // Definitions of 1D fixed-size and variable-size kernels and related operations
0030 
0031 namespace detail {
0032 
0033 /// \brief kernel adaptor for one-dimensional cores
0034 /// Core needs to provide size(),begin(),end(),operator[],
0035 /// value_type,iterator,const_iterator,reference,const_reference
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()); // also implies `size() > 0`
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()); // also implies `size() > 0`
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 } // namespace detail
0098 
0099 /// \brief variable-size kernel
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 /// \brief static-size kernel
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 // TODO: This data member is odr-used and definition at namespace scope
0145 // is required by C++11. Redundant and deprecated in C++17.
0146 template <typename T,std::size_t Size>
0147 constexpr std::size_t kernel_1d_fixed<T, Size>::static_size;
0148 
0149 /// \brief reverse a kernel
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()); // implies `size() > 0`
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()); // implies `size() > 0`
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 /// \brief variable-size kernel
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 /// \brief static-size kernel
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 // TODO: This data member is odr-used and definition at namespace scope
0329 // is required by C++11. Redundant and deprecated in C++17.
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 /// \brief reverse a kernel_2d
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 /// \brief reverse a kernel_2d
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 } //namespace detail
0359 
0360 }} // namespace boost::gil
0361 
0362 #endif