| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608 |
- //
- // Copyright 2005-2007 Adobe Systems Incorporated
- // Copyright 2021 Pranam Lashkari <plashkari628@gmail.com>
- //
- // Distributed under the Boost Software License, Version 1.0
- // See accompanying file LICENSE_1_0.txt or copy at
- // http://www.boost.org/LICENSE_1_0.txt
- //
- #ifndef BOOST_GIL_ALGORITHM_HPP
- #define BOOST_GIL_ALGORITHM_HPP
- #include <boost/gil/metafunctions.hpp>
- #include <boost/gil/pixel_iterator.hpp>
- #include <boost/gil/pixel_numeric_operations.hpp>
- #include <boost/gil/image.hpp>
- #include <boost/gil/bit_aligned_pixel_iterator.hpp>
- #include <boost/gil/color_base_algorithm.hpp>
- #include <boost/gil/concepts.hpp>
- #include <boost/gil/image_view.hpp>
- #include <boost/gil/image_view_factory.hpp>
- #include <boost/gil/detail/mp11.hpp>
- #include <boost/gil/detail/type_traits.hpp>
- #include <boost/assert.hpp>
- #include <boost/config.hpp>
- #include <algorithm>
- #include <cstddef>
- #include <cstring>
- #include <iterator>
- #include <memory>
- #include <type_traits>
- #include <typeinfo>
- #include <numeric>
- namespace boost { namespace gil {
- //forward declarations
- template <typename ChannelPtr, typename ColorSpace>
- struct planar_pixel_iterator;
- template <typename Iterator>
- class memory_based_step_iterator;
- template <typename StepIterator>
- class memory_based_2d_locator;
- // a tag denoting incompatible arguments
- struct error_t {};
- /// \defgroup ImageViewSTLAlgorithms STL-like Algorithms
- /// \ingroup ImageViewAlgorithm
- /// \brief Image view-equivalents of STL algorithms
- ///
- /// Image views provide 1D iteration of their pixels via \p begin() and \p end() methods,
- /// which makes it possible to use STL algorithms with them. However, using nested loops
- /// over X and Y is in many cases more efficient. The algorithms in this section resemble
- /// STL algorithms, but they abstract away the nested loops and take views (as opposed to ranges) as input.
- ///
- /// Most algorithms check whether the image views are 1D-traversable. A 1D-traversable image view has no gaps
- /// at the end of the rows. In other words, if an x_iterator of that view is advanced past the last pixel in a row
- /// it will move to the first pixel of the next row. When image views are 1D-traversable, the algorithms use
- /// a single loop and run more efficiently. If one or more of the input views are not 1D-traversable, the algorithms
- /// fall-back to an X-loop nested inside a Y-loop.
- ///
- /// The algorithms typically delegate the work to their corresponding STL algorithms. For example, \p copy_pixels calls
- /// \p std::copy either for each row, or, when the images are 1D-traversable, once for all pixels.
- ///
- /// In addition, overloads are sometimes provided for the STL algorithms. For example, std::copy for planar iterators
- /// is overloaded to perform \p std::copy for each of the planes. \p std::copy over bitwise-copiable pixels results in
- /// std::copy over unsigned char, which STL typically implements via \p memmove.
- ///
- /// As a result \p copy_pixels may result in a single call to \p memmove for interleaved 1D-traversable views,
- /// or one per each plane of planar 1D-traversable views, or one per each row of interleaved non-1D-traversable images, etc.
- /// \defgroup STLOptimizations Performance overloads of STL algorithms
- /// \ingroup ImageViewAlgorithm
- /// \brief overloads of STL algorithms allowing more efficient implementation when used with GIL constructs
- /// \brief A generic binary operation on views
- /// \ingroup ImageViewSTLAlgorithms
- ///
- /// Use this class as a convenience superclass when defining an operation for any image views.
- /// Many operations have different behavior when the two views are compatible. This class checks
- /// for compatibility and invokes apply_compatible(V1,V2) or apply_incompatible(V1,V2) of the subclass.
- /// You must provide apply_compatible(V1,V2) method in your subclass, but apply_incompatible(V1,V2)
- /// is not required and the default throws std::bad_cast.
- template <typename Derived, typename Result=void>
- struct binary_operation_obj
- {
- using result_type = Result;
- template <typename V1, typename V2> BOOST_FORCEINLINE
- auto operator()(const std::pair<const V1*,const V2*>& p) const -> result_type {
- return apply(*p.first, *p.second, typename views_are_compatible<V1,V2>::type());
- }
- template <typename V1, typename V2> BOOST_FORCEINLINE
- auto operator()(const V1& v1, const V2& v2) const -> result_type {
- return apply(v1, v2, typename views_are_compatible<V1,V2>::type());
- }
- auto operator()(const error_t&) const -> result_type { throw std::bad_cast(); }
- private:
- // dispatch from apply overload to a function with distinct name
- template <typename V1, typename V2>
- BOOST_FORCEINLINE
- auto apply(V1 const& v1, V2 const& v2, std::false_type) const -> result_type
- {
- return ((const Derived*)this)->apply_incompatible(v1, v2);
- }
- // dispatch from apply overload to a function with distinct name
- template <typename V1, typename V2>
- BOOST_FORCEINLINE
- auto apply(V1 const& v1, V2 const& v2, std::true_type) const -> result_type
- {
- return ((const Derived*)this)->apply_compatible(v1, v2);
- }
- // function with distinct name - it can be overloaded by subclasses
- template <typename V1, typename V2>
- BOOST_FORCEINLINE
- auto apply_incompatible(V1 const& /*v1*/, V2 const& /*v2*/) const -> result_type
- {
- throw std::bad_cast();
- }
- };
- }} // namespace boost::gil
- //////////////////////////////////////////////////////////////////////////////////////
- // std::copy and gil::copy_pixels
- //////////////////////////////////////////////////////////////////////////////////////
- /// \defgroup ImageViewSTLAlgorithmsCopyPixels copy_pixels
- /// \ingroup ImageViewSTLAlgorithms
- /// \brief std::copy for image views
- namespace std {
- /// \ingroup STLOptimizations
- /// \brief Copy when both src and dst are interleaved and of the same type can be just memmove
- template<typename T, typename CS>
- BOOST_FORCEINLINE
- auto copy(
- boost::gil::pixel<T, CS>* first,
- boost::gil::pixel<T, CS>* last,
- boost::gil::pixel<T, CS>* dst)
- -> boost::gil::pixel<T, CS>*
- {
- auto p = std::copy((unsigned char*)first, (unsigned char*)last, (unsigned char*)dst);
- return reinterpret_cast<boost::gil::pixel<T, CS>*>(p);
- }
- /// \ingroup STLOptimizations
- /// \brief Copy when both src and dst are interleaved and of the same type can be just memmove
- template<typename T, typename CS>
- BOOST_FORCEINLINE
- auto copy(const boost::gil::pixel<T,CS>* first, const boost::gil::pixel<T,CS>* last,
- boost::gil::pixel<T,CS>* dst) -> boost::gil::pixel<T,CS>*
- {
- return (boost::gil::pixel<T,CS>*)std::copy((unsigned char*)first,(unsigned char*)last, (unsigned char*)dst);
- }
- } // namespace std
- namespace boost { namespace gil {
- namespace detail {
- template <typename I, typename O> struct copy_fn {
- BOOST_FORCEINLINE I operator()(I first, I last, O dst) const { return std::copy(first,last,dst); }
- };
- } // namespace detail
- } } // namespace boost::gil
- namespace std {
- /// \ingroup STLOptimizations
- /// \brief Copy when both src and dst are planar pointers is copy for each channel
- template<typename CS, typename IC1, typename IC2> BOOST_FORCEINLINE
- auto copy(boost::gil::planar_pixel_iterator<IC1,CS> first, boost::gil::planar_pixel_iterator<IC1,CS> last, boost::gil::planar_pixel_iterator<IC2,CS> dst) -> boost::gil::planar_pixel_iterator<IC2,CS>
- {
- boost::gil::gil_function_requires<boost::gil::ChannelsCompatibleConcept<typename std::iterator_traits<IC1>::value_type,typename std::iterator_traits<IC2>::value_type>>();
- static_for_each(first,last,dst,boost::gil::detail::copy_fn<IC1,IC2>());
- return dst+(last-first);
- }
- } // namespace std
- namespace boost { namespace gil {
- namespace detail {
- /// Does a copy-n. If the inputs contain image iterators, performs a copy at each row using the row iterators
- /// \ingroup CopyPixels
- template <typename I, typename O>
- struct copier_n {
- BOOST_FORCEINLINE void operator()(I src, typename std::iterator_traits<I>::difference_type n, O dst) const { std::copy(src,src+n, dst); }
- };
- /// Source range is delimited by image iterators
- template <typename IL, typename O> // IL Models ConstPixelLocatorConcept, O Models PixelIteratorConcept
- struct copier_n<iterator_from_2d<IL>,O> {
- using diff_t = typename std::iterator_traits<iterator_from_2d<IL>>::difference_type;
- BOOST_FORCEINLINE void operator()(iterator_from_2d<IL> src, diff_t n, O dst) const {
- gil_function_requires<PixelLocatorConcept<IL>>();
- gil_function_requires<MutablePixelIteratorConcept<O>>();
- while (n>0) {
- diff_t l=src.width()-src.x_pos();
- diff_t numToCopy=(n<l ? n:l);
- detail::copy_n(src.x(), numToCopy, dst);
- dst+=numToCopy;
- src+=numToCopy;
- n-=numToCopy;
- }
- }
- };
- /// Destination range is delimited by image iterators
- template <typename I, typename OL> // I Models ConstPixelIteratorConcept, OL Models PixelLocatorConcept
- struct copier_n<I,iterator_from_2d<OL>> {
- using diff_t = typename std::iterator_traits<I>::difference_type;
- BOOST_FORCEINLINE void operator()(I src, diff_t n, iterator_from_2d<OL> dst) const {
- gil_function_requires<PixelIteratorConcept<I>>();
- gil_function_requires<MutablePixelLocatorConcept<OL>>();
- while (n>0) {
- diff_t l=dst.width()-dst.x_pos();
- diff_t numToCopy=(n<l ? n:l);
- detail::copy_n(src, numToCopy, dst.x());
- dst+=numToCopy;
- src+=numToCopy;
- n-=numToCopy;
- }
- }
- };
- /// Both source and destination ranges are delimited by image iterators
- template <typename IL, typename OL>
- struct copier_n<iterator_from_2d<IL>,iterator_from_2d<OL>> {
- using diff_t = typename iterator_from_2d<IL>::difference_type;
- BOOST_FORCEINLINE void operator()(iterator_from_2d<IL> src, diff_t n, iterator_from_2d<OL> dst) const {
- gil_function_requires<PixelLocatorConcept<IL>>();
- gil_function_requires<MutablePixelLocatorConcept<OL>>();
- if (src.x_pos()!=dst.x_pos() || src.width()!=dst.width()) {
- while(n-->0) {
- *dst++=*src++;
- }
- }
- while (n>0) {
- diff_t l=dst.width()-dst.x_pos();
- diff_t numToCopy=(n<l ? n : l);
- detail::copy_n(src.x(), numToCopy, dst.x());
- dst+=numToCopy;
- src+=numToCopy;
- n-=numToCopy;
- }
- }
- };
- template <typename SrcIterator, typename DstIterator>
- BOOST_FORCEINLINE auto copy_with_2d_iterators(SrcIterator first, SrcIterator last, DstIterator dst) -> DstIterator {
- using src_x_iterator = typename SrcIterator::x_iterator;
- using dst_x_iterator = typename DstIterator::x_iterator;
- typename SrcIterator::difference_type n = last - first;
- if (first.is_1d_traversable()) {
- if (dst.is_1d_traversable())
- copier_n<src_x_iterator,dst_x_iterator>()(first.x(),n, dst.x());
- else
- copier_n<src_x_iterator,DstIterator >()(first.x(),n, dst);
- } else {
- if (dst.is_1d_traversable())
- copier_n<SrcIterator,dst_x_iterator>()(first,n, dst.x());
- else
- copier_n<SrcIterator,DstIterator>()(first,n,dst);
- }
- return dst+n;
- }
- } // namespace detail
- } } // namespace boost::gil
- namespace std {
- /// \ingroup STLOptimizations
- /// \brief std::copy(I1,I1,I2) with I1 and I2 being a iterator_from_2d
- template <typename IL, typename OL>
- BOOST_FORCEINLINE auto copy1(boost::gil::iterator_from_2d<IL> first, boost::gil::iterator_from_2d<IL> last, boost::gil::iterator_from_2d<OL> dst) -> boost::gil::iterator_from_2d<OL>
- {
- return boost::gil::detail::copy_with_2d_iterators(first,last,dst);
- }
- } // namespace std
- namespace boost { namespace gil {
- /// \ingroup ImageViewSTLAlgorithmsCopyPixels
- /// \brief std::copy for image views
- template <typename View1, typename View2> BOOST_FORCEINLINE
- void copy_pixels(const View1& src, const View2& dst)
- {
- BOOST_ASSERT(src.dimensions() == dst.dimensions());
- detail::copy_with_2d_iterators(src.begin(),src.end(),dst.begin());
- }
- //////////////////////////////////////////////////////////////////////////////////////
- // copy_and_convert_pixels
- //////////////////////////////////////////////////////////////////////////////////////
- /// \defgroup ImageViewSTLAlgorithmsCopyAndConvertPixels copy_and_convert_pixels
- /// \ingroup ImageViewSTLAlgorithms
- /// \brief copies src view into dst view, color converting if necessary.
- ///
- /// Versions taking static and runtime views are provided. Versions taking user-defined color convered are provided.
- namespace detail {
- template <typename CC>
- class copy_and_convert_pixels_fn : public binary_operation_obj<copy_and_convert_pixels_fn<CC>>
- {
- private:
- CC _cc;
- public:
- using result_type = typename binary_operation_obj<copy_and_convert_pixels_fn<default_color_converter>>::result_type;
- copy_and_convert_pixels_fn() {}
- copy_and_convert_pixels_fn(CC cc_in) : _cc(cc_in) {}
- // when the two color spaces are incompatible, a color conversion is performed
- template <typename V1, typename V2> BOOST_FORCEINLINE
- auto apply_incompatible(const V1& src, const V2& dst) const -> result_type {
- copy_pixels(color_converted_view<typename V2::value_type>(src,_cc),dst);
- }
- // If the two color spaces are compatible, copy_and_convert is just copy
- template <typename V1, typename V2> BOOST_FORCEINLINE
- auto apply_compatible(const V1& src, const V2& dst) const -> result_type {
- copy_pixels(src,dst);
- }
- };
- } // namespace detail
- /// \ingroup ImageViewSTLAlgorithmsCopyAndConvertPixels
- template <typename V1, typename V2,typename CC>
- BOOST_FORCEINLINE
- void copy_and_convert_pixels(const V1& src, const V2& dst,CC cc) {
- detail::copy_and_convert_pixels_fn<CC> ccp(cc);
- ccp(src,dst);
- }
- struct default_color_converter;
- /// \ingroup ImageViewSTLAlgorithmsCopyAndConvertPixels
- template <typename View1, typename View2>
- BOOST_FORCEINLINE
- void copy_and_convert_pixels(const View1& src, const View2& dst) {
- detail::copy_and_convert_pixels_fn<default_color_converter> ccp;
- ccp(src,dst);
- }
- } } // namespace boost::gil
- //////////////////////////////////////////////////////////////////////////////////////
- // std::fill and gil::fill_pixels
- //////////////////////////////////////////////////////////////////////////////////////
- /// \defgroup ImageViewSTLAlgorithmsFillPixels fill_pixels
- /// \ingroup ImageViewSTLAlgorithms
- /// \brief std::fill for image views
- namespace std {
- /// \ingroup STLOptimizations
- /// \brief std::fill(I,I,V) with I being a iterator_from_2d
- ///
- /// Invoked when one calls std::fill(I,I,V) with I being a iterator_from_2d (which is
- /// a 1D iterator over the pixels in an image). For contiguous images (i.e. images that have
- /// no alignment gap at the end of each row) it is more efficient to use the underlying
- /// pixel iterator that does not check for the end of rows. For non-contiguous images fill
- /// resolves to fill of each row using the underlying pixel iterator, which is still faster
- template <typename IL, typename V>
- void fill(boost::gil::iterator_from_2d<IL> first, boost::gil::iterator_from_2d<IL> last, const V& val) {
- boost::gil::gil_function_requires<boost::gil::MutablePixelLocatorConcept<IL>>();
- if (first.is_1d_traversable()) {
- std::fill(first.x(), last.x(), val);
- } else {
- // fill row by row
- std::ptrdiff_t n=last-first;
- while (n>0) {
- std::ptrdiff_t numToDo=std::min<const std::ptrdiff_t>(n,(std::ptrdiff_t)(first.width()-first.x_pos()));
- std::fill_n(first.x(), numToDo, val);
- first+=numToDo;
- n-=numToDo;
- }
- }
- }
- } // namespace std
- namespace boost { namespace gil {
- namespace detail {
- /// struct to do std::fill
- struct std_fill_t {
- template <typename It, typename P>
- void operator()(It first, It last, const P& p_in) {
- std::fill(first,last,p_in);
- }
- };
- /// std::fill for planar iterators
- template <typename It, typename P>
- BOOST_FORCEINLINE
- void fill_aux(It first, It last, P const& p, std::true_type)
- {
- static_for_each(first, last, p, std_fill_t());
- }
- /// std::fill for interleaved iterators
- template <typename It, typename P>
- BOOST_FORCEINLINE
- void fill_aux(It first, It last, P const& p, std::false_type)
- {
- std::fill(first, last, p);
- }
- } // namespace detail
- /// \ingroup ImageViewSTLAlgorithmsFillPixels
- /// \brief std::fill for image views
- template <typename View, typename Value>
- BOOST_FORCEINLINE
- void fill_pixels(View const& view, Value const& value)
- {
- if (view.is_1d_traversable())
- {
- detail::fill_aux(
- view.begin().x(), view.end().x(), value, is_planar<View>());
- }
- else
- {
- for (std::ptrdiff_t y = 0; y < view.height(); ++y)
- detail::fill_aux(
- view.row_begin(y), view.row_end(y), value, is_planar<View>());
- }
- }
- //////////////////////////////////////////////////////////////////////////////////////
- // destruct_pixels
- //////////////////////////////////////////////////////////////////////////////////////
- /// \defgroup ImageViewSTLAlgorithmsDestructPixels destruct_pixels
- /// \ingroup ImageViewSTLAlgorithms
- /// \brief invokes the destructor on every pixel of an image view
- namespace detail {
- template <typename Iterator>
- BOOST_FORCEINLINE
- void destruct_range_impl(Iterator first, Iterator last,
- typename std::enable_if
- <
- mp11::mp_and
- <
- std::is_pointer<Iterator>,
- mp11::mp_not
- <
- detail::is_trivially_destructible<typename std::iterator_traits<Iterator>::value_type>
- >
- >::value
- >::type* /*ptr*/ = 0)
- {
- while (first != last)
- {
- first->~value_t();
- ++first;
- }
- }
- template <typename Iterator>
- BOOST_FORCEINLINE
- void destruct_range_impl(Iterator /*first*/, Iterator /*last*/,
- typename std::enable_if
- <
- mp11::mp_or
- <
- mp11::mp_not<std::is_pointer<Iterator>>,
- detail::is_trivially_destructible<typename std::iterator_traits<Iterator>::value_type>
- >::value
- >::type* /* ptr */ = nullptr)
- {
- }
- template <typename Iterator>
- BOOST_FORCEINLINE
- void destruct_range(Iterator first, Iterator last)
- {
- destruct_range_impl(first, last);
- }
- struct std_destruct_t
- {
- template <typename Iterator>
- void operator()(Iterator first, Iterator last) const
- {
- destruct_range(first,last);
- }
- };
- /// destruct for planar iterators
- template <typename It>
- BOOST_FORCEINLINE
- void destruct_aux(It first, It last, std::true_type)
- {
- static_for_each(first,last,std_destruct_t());
- }
- /// destruct for interleaved iterators
- template <typename It>
- BOOST_FORCEINLINE
- void destruct_aux(It first, It last, std::false_type)
- {
- destruct_range(first,last);
- }
- } // namespace detail
- /// \ingroup ImageViewSTLAlgorithmsDestructPixels
- /// \brief Invokes the in-place destructor on every pixel of the view
- template <typename View>
- BOOST_FORCEINLINE
- void destruct_pixels(View const& view)
- {
- if (view.is_1d_traversable())
- {
- detail::destruct_aux(
- view.begin().x(), view.end().x(), is_planar<View>());
- }
- else
- {
- for (std::ptrdiff_t y = 0; y < view.height(); ++y)
- detail::destruct_aux(
- view.row_begin(y), view.row_end(y), is_planar<View>());
- }
- }
- //////////////////////////////////////////////////////////////////////////////////////
- // uninitialized_fill_pixels
- //////////////////////////////////////////////////////////////////////////////////////
- /// \defgroup ImageViewSTLAlgorithmsUninitializedFillPixels uninitialized_fill_pixels
- /// \ingroup ImageViewSTLAlgorithms
- /// \brief std::uninitialized_fill for image views
- namespace detail {
- /// std::uninitialized_fill for planar iterators
- /// If an exception is thrown destructs any in-place copy-constructed objects
- template <typename It, typename P>
- BOOST_FORCEINLINE
- void uninitialized_fill_aux(It first, It last, P const& p, std::true_type)
- {
- std::size_t channel = 0;
- try
- {
- using pixel_t = typename std::iterator_traits<It>::value_type;
- while (channel < num_channels<pixel_t>::value)
- {
- std::uninitialized_fill(
- dynamic_at_c(first,channel),
- dynamic_at_c(last,channel),
- dynamic_at_c(p,channel));
- ++channel;
- }
- }
- catch (...)
- {
- for (std::size_t c = 0; c < channel; ++c)
- destruct_range(dynamic_at_c(first, c), dynamic_at_c(last, c));
- throw;
- }
- }
- /// std::uninitialized_fill for interleaved iterators
- /// If an exception is thrown destructs any in-place copy-constructed objects
- template <typename It, typename P>
- BOOST_FORCEINLINE
- void uninitialized_fill_aux(It first, It last, P const& p, std::false_type)
- {
- std::uninitialized_fill(first,last,p);
- }
- } // namespace detail
- /// \ingroup ImageViewSTLAlgorithmsUninitializedFillPixels
- /// \brief std::uninitialized_fill for image views.
- /// Does not support planar heterogeneous views.
- /// If an exception is thrown destructs any in-place copy-constructed pixels
- template <typename View, typename Value>
- void uninitialized_fill_pixels(const View& view, const Value& val) {
- if (view.is_1d_traversable())
- detail::uninitialized_fill_aux(view.begin().x(), view.end().x(),
- val,is_planar<View>());
- else {
- typename View::y_coord_t y = 0;
- try {
- for (y=0; y<view.height(); ++y)
- detail::uninitialized_fill_aux(view.row_begin(y),view.row_end(y),
- val,is_planar<View>());
- } catch(...) {
- for (typename View::y_coord_t y0=0; y0<y; ++y0)
- detail::destruct_aux(view.row_begin(y0),view.row_end(y0), is_planar<View>());
- throw;
- }
- }
- }
- //////////////////////////////////////////////////////////////////////////////////////
- // default_construct_pixels
- //////////////////////////////////////////////////////////////////////////////////////
- /// \defgroup ImageViewSTLAlgorithmsDefaultConstructPixels default_construct_pixels
- /// \ingroup ImageViewSTLAlgorithms
- /// \brief invokes the default constructor on every pixel of an image view
- namespace detail {
- template <typename It> BOOST_FORCEINLINE
- void default_construct_range_impl(It first, It last, std::true_type)
- {
- It first1 = first;
- try
- {
- using value_t = typename std::iterator_traits<It>::value_type;
- while (first != last)
- {
- new (first) value_t();
- ++first;
- }
- }
- catch (...)
- {
- destruct_range(first1, first);
- throw;
- }
- }
- template <typename It>
- BOOST_FORCEINLINE
- void default_construct_range_impl(It, It, std::false_type) {}
- template <typename It>
- BOOST_FORCEINLINE
- void default_construct_range(It first, It last)
- {
- default_construct_range_impl(first, last, typename std::is_pointer<It>::type());
- }
- /// uninitialized_default_construct for planar iterators
- template <typename It>
- BOOST_FORCEINLINE
- void default_construct_aux(It first, It last, std::true_type)
- {
- std::size_t channel = 0;
- try
- {
- using pixel_t = typename std::iterator_traits<It>::value_type;
- while (channel < num_channels<pixel_t>::value)
- {
- default_construct_range(dynamic_at_c(first, channel), dynamic_at_c(last, channel));
- ++channel;
- }
- }
- catch (...)
- {
- for (std::size_t c = 0; c < channel; ++c)
- destruct_range(dynamic_at_c(first, c), dynamic_at_c(last, c));
- throw;
- }
- }
- /// uninitialized_default_construct for interleaved iterators
- template <typename It>
- BOOST_FORCEINLINE
- void default_construct_aux(It first, It last, std::false_type)
- {
- default_construct_range(first, last);
- }
- template <typename View, bool IsPlanar>
- struct has_trivial_pixel_constructor
- : detail::is_trivially_default_constructible<typename View::value_type>
- {};
- template <typename View>
- struct has_trivial_pixel_constructor<View, true>
- : detail::is_trivially_default_constructible<typename channel_type<View>::type>
- {};
- template<typename View, bool IsTriviallyConstructible>
- BOOST_FORCEINLINE
- void default_construct_pixels_impl(
- View const& view,
- std::enable_if<!IsTriviallyConstructible>* /*ptr*/ = nullptr)
- {
- if (view.is_1d_traversable())
- {
- detail::default_construct_aux(
- view.begin().x(), view.end().x(), is_planar<View>());
- }
- else
- {
- typename View::y_coord_t y = 0;
- try
- {
- for( y = 0; y < view.height(); ++y )
- detail::default_construct_aux(
- view.row_begin(y), view.row_end(y), is_planar<View>());
- }
- catch(...)
- {
- for (typename View::y_coord_t y0 = 0; y0 < y; ++y0 )
- detail::destruct_aux(
- view.row_begin(y0), view.row_end(y0), is_planar<View>());
- throw;
- }
- }
- }
- } // namespace detail
- /// \ingroup ImageViewSTLAlgorithmsDefaultConstructPixels
- /// \brief Invokes the in-place default constructor on every pixel of the (uninitialized) view.
- /// Does not support planar heterogeneous views.
- /// If an exception is thrown destructs any in-place default-constructed pixels
- template <typename View>
- void default_construct_pixels(View const& view)
- {
- detail::default_construct_pixels_impl
- <
- View,
- detail::has_trivial_pixel_constructor
- <
- View,
- is_planar<View>::value
- >::value
- >(view);
- }
- //////////////////////////////////////////////////////////////////////////////////////
- // uninitialized_copy_pixels
- //////////////////////////////////////////////////////////////////////////////////////
- /// \defgroup ImageViewSTLAlgorithmsUninitializedCopyPixels uninitialized_copy_pixels
- /// \ingroup ImageViewSTLAlgorithms
- /// \brief std::uninitialized_copy for image views
- namespace detail {
- enum class copy_planarity_condition
- {
- planar_to_planar,
- interleaved_to_planar,
- mixed_to_interleaved
- };
- using planar_to_planar_type =
- std::integral_constant
- <
- copy_planarity_condition, copy_planarity_condition::planar_to_planar
- >;
- using interleaved_to_planar_type =
- std::integral_constant
- <
- copy_planarity_condition, copy_planarity_condition::interleaved_to_planar
- >;
- using mixed_to_interleaved_type =
- std::integral_constant
- <
- copy_planarity_condition, copy_planarity_condition::mixed_to_interleaved
- >;
- /// std::uninitialized_copy for pairs of planar iterators
- template <typename It1, typename It2>
- BOOST_FORCEINLINE
- void uninitialized_copy_aux(It1 first1, It1 last1, It2 first2, It2 last2, planar_to_planar_type)
- {
- std::size_t channel=0;
- try {
- using pixel_t = typename std::iterator_traits<It1>::value_type;
- while (channel < num_channels<pixel_t>::value)
- {
- std::uninitialized_copy(
- dynamic_at_c(first1, channel),
- dynamic_at_c(last1, channel),
- dynamic_at_c(first2, channel));
- ++channel;
- }
- }
- catch (...)
- {
- It2 last2 = first2;
- std::advance(last2, std::distance(first1, last1));
- for (std::size_t c = 0; c < channel; ++c)
- destruct_range(dynamic_at_c(first2, c), dynamic_at_c(last2, c));
- throw;
- }
- }
- /// std::uninitialized_copy for interleaved or mixed(planar into interleaved) iterators
- template <typename It1, typename It2>
- BOOST_FORCEINLINE
- void uninitialized_copy_aux(It1 first1, It1 last1, It2 first2, It2, mixed_to_interleaved_type)
- {
- std::uninitialized_copy(first1, last1, first2);
- }
- /// std::uninitialized_copy for interleaved to planar iterators
- template <typename It1, typename It2>
- BOOST_FORCEINLINE
- void uninitialized_copy_aux(It1 first1, It1, It2 first2, It2 last2,
- interleaved_to_planar_type)
- {
- default_construct_aux(first2, last2, std::true_type());
- typename It2::difference_type n = last2 - first2;
- copier_n<It1,It2>()(first1, n, first2);
- }
- } // namespace detail
- /// \ingroup ImageViewSTLAlgorithmsUninitializedCopyPixels
- /// \brief std::uninitialized_copy for image views.
- /// Does not support planar heterogeneous views.
- /// If an exception is thrown destructs any in-place copy-constructed objects
- template <typename View1, typename View2>
- void uninitialized_copy_pixels(View1 const& view1, View2 const& view2)
- {
- using copy_planarity_condition = detail::copy_planarity_condition;
- using copy_planarity_condition_type =
- std::integral_constant
- <
- copy_planarity_condition,
- !is_planar<View2>::value
- ? copy_planarity_condition::mixed_to_interleaved
- : (is_planar<View1>::value
- ? copy_planarity_condition::planar_to_planar
- : copy_planarity_condition::interleaved_to_planar)
- >;
- BOOST_ASSERT(view1.dimensions() == view2.dimensions());
- if (view1.is_1d_traversable() && view2.is_1d_traversable())
- {
- detail::uninitialized_copy_aux(
- view1.begin().x(), view1.end().x(), view2.begin().x(), view2.end().x(),
- copy_planarity_condition_type());
- }
- else
- {
- typename View1::y_coord_t y = 0;
- try
- {
- for (y = 0; y < view1.height(); ++y)
- detail::uninitialized_copy_aux(
- view1.row_begin(y), view1.row_end(y), view2.row_begin(y), view2.row_end(y),
- copy_planarity_condition_type());
- }
- catch(...)
- {
- for (typename View1::y_coord_t y0 = 0; y0 < y; ++y0)
- detail::destruct_aux(view2.row_begin(y0), view2.row_end(y0), is_planar<View2>());
- throw;
- }
- }
- }
- //////////////////////////////////////////////////////////////////////////////////////
- // for_each_pixel
- //////////////////////////////////////////////////////////////////////////////////////
- /// \defgroup ImageViewSTLAlgorithmsForEachPixel for_each_pixel
- /// \ingroup ImageViewSTLAlgorithms
- /// \brief std::for_each for image views
- ///
- /// For contiguous images (i.e. images that have no alignment gap at the end of each row) it is
- /// more efficient to use the underlying pixel iterator that does not check for the end of rows.
- /// For non-contiguous images for_each_pixel resolves to for_each of each row using the underlying
- /// pixel iterator, which is still faster
- /// \ingroup ImageViewSTLAlgorithmsForEachPixel
- template <typename View, typename F>
- F for_each_pixel(View const& view, F fun)
- {
- if (view.is_1d_traversable())
- {
- return std::for_each(view.begin().x(), view.end().x(), fun);
- }
- else
- {
- for (std::ptrdiff_t y = 0; y < view.height(); ++y)
- for (auto begin = view.row_begin(y), end = view.row_end(y); begin != end; ++begin)
- fun(*begin);
- return fun;
- }
- }
- /// \defgroup ImageViewSTLAlgorithmsForEachPixelPosition for_each_pixel_position
- /// \ingroup ImageViewSTLAlgorithms
- /// \brief adobe::for_each_position for image views (passes locators, instead of pixel references, to the function object)
- /// \ingroup ImageViewSTLAlgorithmsForEachPixelPosition
- template <typename View, typename F>
- F for_each_pixel_position(View const& view, F fun)
- {
- typename View::xy_locator loc = view.xy_at(0, 0);
- for (std::ptrdiff_t y = 0; y < view.height(); ++y)
- {
- for (std::ptrdiff_t x = 0; x < view.width(); ++x, ++loc.x())
- fun(loc);
- loc.x() -= view.width(); ++loc.y();
- }
- return fun;
- }
- //////////////////////////////////////////////////////////////////////////////////////
- // generate_pixels
- //////////////////////////////////////////////////////////////////////////////////////
- /// \defgroup ImageViewSTLAlgorithmsGeneratePixels generate_pixels
- /// \ingroup ImageViewSTLAlgorithms
- /// \brief std::generate for image views
- /// \ingroup ImageViewSTLAlgorithmsGeneratePixels
- /// \brief std::generate for image views
- template <typename View, typename F>
- void generate_pixels(View const& view, F fun)
- {
- if (view.is_1d_traversable())
- {
- std::generate(view.begin().x(), view.end().x(), fun);
- }
- else
- {
- for (std::ptrdiff_t y = 0; y < view.height(); ++y)
- std::generate(view.row_begin(y), view.row_end(y), fun);
- }
- }
- //////////////////////////////////////////////////////////////////////////////////////
- // std::equal and gil::equal_pixels for GIL constructs
- //////////////////////////////////////////////////////////////////////////////////////
- /// \defgroup ImageViewSTLAlgorithmsEqualPixels equal_pixels
- /// \ingroup ImageViewSTLAlgorithms
- /// \brief std::equal for image views
- template <typename I1, typename I2>
- BOOST_FORCEINLINE
- bool equal_n(I1 i1, std::ptrdiff_t n, I2 i2);
- namespace detail {
- template <typename I1, typename I2>
- struct equal_n_fn
- {
- BOOST_FORCEINLINE
- bool operator()(I1 i1, std::ptrdiff_t n, I2 i2) const
- {
- return std::equal(i1, i1 + n, i2);
- }
- };
- /// Equal when both ranges are interleaved and of the same type.
- /// GIL pixels are bitwise comparable, so memcmp is used. User-defined pixels that are not bitwise comparable need to provide an overload
- template<typename T, typename CS>
- struct equal_n_fn<pixel<T, CS> const*, pixel<T, CS> const*>
- {
- BOOST_FORCEINLINE
- bool operator()(pixel<T, CS> const* i1, std::ptrdiff_t n, pixel<T, CS> const* i2) const
- {
- return memcmp(i1, i2, n * sizeof(pixel<T, CS>)) == 0;
- }
- };
- template<typename T, typename CS>
- struct equal_n_fn<pixel<T, CS>*, pixel<T, CS>*>
- : equal_n_fn<pixel<T, CS> const*, pixel<T, CS> const*>
- {};
- /// EqualPixels
- /// Equal when both ranges are planar pointers of the same type. memcmp is invoked for each channel plane
- /// User-defined channels that are not bitwise comparable need to provide an overload
- template<typename IC, typename CS>
- struct equal_n_fn<planar_pixel_iterator<IC, CS>, planar_pixel_iterator<IC, CS>>
- {
- BOOST_FORCEINLINE
- bool operator()(planar_pixel_iterator<IC, CS> const i1, std::ptrdiff_t n, planar_pixel_iterator<IC, CS> const i2) const
- {
- // FIXME: ptrdiff_t vs size_t
- constexpr std::ptrdiff_t byte_size = n * sizeof(typename std::iterator_traits<IC>::value_type);
- for (std::ptrdiff_t i = 0; i < mp11::mp_size<CS>::value; ++i)
- {
- if (memcmp(dynamic_at_c(i1, i), dynamic_at_c(i2, i), byte_size) != 0)
- return false;
- }
- return true;
- }
- };
- /// Source range is delimited by image iterators
- /// \tparam Loc Models ConstPixelLocatorConcept
- /// \tparam It Models PixelIteratorConcept
- template <typename Loc, typename It>
- struct equal_n_fn<boost::gil::iterator_from_2d<Loc>, It>
- {
- BOOST_FORCEINLINE
- bool operator()(boost::gil::iterator_from_2d<Loc> i1, std::ptrdiff_t n, It i2) const
- {
- gil_function_requires<boost::gil::PixelLocatorConcept<Loc>>();
- gil_function_requires<boost::gil::PixelIteratorConcept<It>>();
- while (n > 0)
- {
- std::ptrdiff_t const num = std::min<std::ptrdiff_t>(n, i1.width() - i1.x_pos());
- if (!equal_n(i1.x(), num, i2))
- return false;
- i1 += num;
- i2 += num;
- n -= num;
- }
- return true;
- }
- };
- /// Destination range is delimited by image iterators
- /// \tparam It Models PixelIteratorConcept
- /// \tparam Loc Models PixelLocatorConcept
- template <typename It, typename Loc>
- struct equal_n_fn<It, boost::gil::iterator_from_2d<Loc>>
- {
- BOOST_FORCEINLINE
- bool operator()(It i1, std::ptrdiff_t n, boost::gil::iterator_from_2d<Loc> i2) const
- {
- gil_function_requires<boost::gil::PixelIteratorConcept<It>>();
- gil_function_requires<boost::gil::PixelLocatorConcept<Loc>>();
- while (n > 0)
- {
- std::ptrdiff_t const num = std::min<std::ptrdiff_t>(n, i2.width() - i2.x_pos());
- if (!equal_n(i1, num, i2.x()))
- return false;
- i1 += num;
- i2 += num;
- n -= num;
- }
- return true;
- }
- };
- /// Both source and destination ranges are delimited by image iterators
- template <typename Loc1, typename Loc2>
- struct equal_n_fn<boost::gil::iterator_from_2d<Loc1>,boost::gil::iterator_from_2d<Loc2>> {
- BOOST_FORCEINLINE bool operator()(boost::gil::iterator_from_2d<Loc1> i1, std::ptrdiff_t n, boost::gil::iterator_from_2d<Loc2> i2) const {
- gil_function_requires<boost::gil::PixelLocatorConcept<Loc1>>();
- gil_function_requires<boost::gil::PixelLocatorConcept<Loc2>>();
- if (i1.x_pos()!=i2.x_pos() || i1.width()!=i2.width()) {
- while(n-->0) {
- if (*i1++!=*i2++) return false;
- }
- }
- while (n>0) {
- std::ptrdiff_t num=std::min<const std::ptrdiff_t>(n,i2.width()-i2.x_pos());
- if (!equal_n(i1.x(), num, i2.x()))
- return false;
- i1+=num;
- i2+=num;
- n-=num;
- }
- return true;
- }
- };
- } // namespace detail
- template <typename I1, typename I2> BOOST_FORCEINLINE
- bool equal_n(I1 i1, std::ptrdiff_t n, I2 i2) {
- return detail::equal_n_fn<I1,I2>()(i1,n,i2);
- }
- } } // namespace boost::gil
- namespace std {
- /// \ingroup STLOptimizations
- /// \brief std::equal(I1,I1,I2) with I1 and I2 being a iterator_from_2d
- ///
- /// Invoked when one calls std::equal(I1,I1,I2) with I1 and I2 being a iterator_from_2d (which is
- /// a 1D iterator over the pixels in an image). Attempts to demote the source and destination
- /// iterators to simpler/faster types if the corresponding range is contiguous.
- /// For contiguous images (i.e. images that have
- /// no alignment gap at the end of each row) it is more efficient to use the underlying
- /// pixel iterator that does not check for the end of rows. If the underlying pixel iterator
- /// happens to be a fundamental planar/interleaved pointer, the call may further resolve
- /// to memcmp. Otherwise it resolves to copying each row using the underlying pixel iterator
- template <typename Loc1, typename Loc2> BOOST_FORCEINLINE
- bool equal(boost::gil::iterator_from_2d<Loc1> first, boost::gil::iterator_from_2d<Loc1> last, boost::gil::iterator_from_2d<Loc2> first2) {
- boost::gil::gil_function_requires<boost::gil::PixelLocatorConcept<Loc1>>();
- boost::gil::gil_function_requires<boost::gil::PixelLocatorConcept<Loc2>>();
- std::ptrdiff_t n=last-first;
- if (first.is_1d_traversable()) {
- if (first2.is_1d_traversable())
- return boost::gil::detail::equal_n_fn<typename Loc1::x_iterator,typename Loc2::x_iterator>()(first.x(),n, first2.x());
- else
- return boost::gil::detail::equal_n_fn<typename Loc1::x_iterator,boost::gil::iterator_from_2d<Loc2>>()(first.x(),n, first2);
- } else {
- if (first2.is_1d_traversable())
- return boost::gil::detail::equal_n_fn<boost::gil::iterator_from_2d<Loc1>,typename Loc2::x_iterator>()(first,n, first2.x());
- else
- return boost::gil::detail::equal_n_fn<boost::gil::iterator_from_2d<Loc1>,boost::gil::iterator_from_2d<Loc2>>()(first,n,first2);
- }
- }
- } // namespace std
- namespace boost { namespace gil {
- /// \ingroup ImageViewSTLAlgorithmsEqualPixels
- /// \brief std::equal for image views
- template <typename View1, typename View2> BOOST_FORCEINLINE
- bool equal_pixels(const View1& v1, const View2& v2) {
- BOOST_ASSERT(v1.dimensions() == v2.dimensions());
- return std::equal(v1.begin(),v1.end(),v2.begin()); // std::equal has overloads with GIL iterators for optimal performance
- }
- //////////////////////////////////////////////////////////////////////////////////////
- ///
- /// transform_pixels
- ///
- //////////////////////////////////////////////////////////////////////////////////////
- /// \defgroup ImageViewSTLAlgorithmsTransformPixels transform_pixels
- /// \ingroup ImageViewSTLAlgorithms
- /// \brief std::transform for image views
- /// \ingroup ImageViewSTLAlgorithmsTransformPixels
- /// \brief std::transform for image views
- template <typename View1, typename View2, typename F> BOOST_FORCEINLINE
- F transform_pixels(const View1& src,const View2& dst, F fun) {
- BOOST_ASSERT(src.dimensions() == dst.dimensions());
- for (std::ptrdiff_t y=0; y<src.height(); ++y) {
- typename View1::x_iterator srcIt=src.row_begin(y);
- typename View2::x_iterator dstIt=dst.row_begin(y);
- for (std::ptrdiff_t x=0; x<src.width(); ++x)
- dstIt[x]=fun(srcIt[x]);
- }
- return fun;
- }
- /// \ingroup ImageViewSTLAlgorithmsTransformPixels
- /// \brief transform_pixels with two sources
- template <typename View1, typename View2, typename View3, typename F> BOOST_FORCEINLINE
- F transform_pixels(const View1& src1, const View2& src2,const View3& dst, F fun) {
- for (std::ptrdiff_t y=0; y<dst.height(); ++y) {
- typename View1::x_iterator srcIt1=src1.row_begin(y);
- typename View2::x_iterator srcIt2=src2.row_begin(y);
- typename View3::x_iterator dstIt=dst.row_begin(y);
- for (std::ptrdiff_t x=0; x<dst.width(); ++x)
- dstIt[x]=fun(srcIt1[x],srcIt2[x]);
- }
- return fun;
- }
- /// \defgroup ImageViewSTLAlgorithmsTransformPixelPositions transform_pixel_positions
- /// \ingroup ImageViewSTLAlgorithms
- /// \brief adobe::transform_positions for image views (passes locators, instead of pixel references, to the function object)
- /// \ingroup ImageViewSTLAlgorithmsTransformPixelPositions
- /// \brief Like transform_pixels but passes to the function object pixel locators instead of pixel references
- template <typename View1, typename View2, typename F> BOOST_FORCEINLINE
- F transform_pixel_positions(const View1& src,const View2& dst, F fun) {
- BOOST_ASSERT(src.dimensions() == dst.dimensions());
- typename View1::xy_locator loc=src.xy_at(0,0);
- for (std::ptrdiff_t y=0; y<src.height(); ++y) {
- typename View2::x_iterator dstIt=dst.row_begin(y);
- for (std::ptrdiff_t x=0; x<src.width(); ++x, ++loc.x())
- dstIt[x]=fun(loc);
- loc.x()-=src.width(); ++loc.y();
- }
- return fun;
- }
- /// \ingroup ImageViewSTLAlgorithmsTransformPixelPositions
- /// \brief transform_pixel_positions with two sources
- template <typename View1, typename View2, typename View3, typename F> BOOST_FORCEINLINE
- F transform_pixel_positions(const View1& src1,const View2& src2,const View3& dst, F fun) {
- BOOST_ASSERT(src1.dimensions() == dst.dimensions());
- BOOST_ASSERT(src2.dimensions() == dst.dimensions());
- typename View1::xy_locator loc1=src1.xy_at(0,0);
- typename View2::xy_locator loc2=src2.xy_at(0,0);
- for (std::ptrdiff_t y=0; y<src1.height(); ++y) {
- typename View3::x_iterator dstIt=dst.row_begin(y);
- for (std::ptrdiff_t x=0; x<src1.width(); ++x, ++loc1.x(), ++loc2.x())
- dstIt[x]=fun(loc1,loc2);
- loc1.x()-=src1.width(); ++loc1.y();
- loc2.x()-=src2.width(); ++loc2.y();
- }
- return fun;
- }
- // Code below this line is moved here from <boost/gil/extension/numeric/algorithm.hpp>
- /// \brief Reference proxy associated with a type that has a \p "reference" member type alias.
- ///
- /// The reference proxy is the reference type, but with stripped-out C++ reference.
- /// Models PixelConcept.
- template <typename T>
- struct pixel_proxy : std::remove_reference<typename T::reference> {};
- /// \brief std::for_each for a pair of iterators
- template <typename Iterator1, typename Iterator2, typename BinaryFunction>
- BinaryFunction for_each(Iterator1 first1, Iterator1 last1, Iterator2 first2, BinaryFunction f)
- {
- while (first1 != last1)
- f(*first1++, *first2++);
- return f;
- }
- template <typename SrcIterator, typename DstIterator>
- inline
- auto assign_pixels(SrcIterator src, SrcIterator src_end, DstIterator dst) -> DstIterator
- {
- for_each(src, src_end, dst,
- pixel_assigns_t
- <
- typename pixel_proxy<typename std::iterator_traits<SrcIterator>::value_type>::type,
- typename pixel_proxy<typename std::iterator_traits<DstIterator>::value_type>::type
- >());
- return dst + (src_end - src);
- }
- namespace detail {
- template <std::size_t Size>
- struct inner_product_k_t
- {
- template
- <
- class InputIterator1,
- class InputIterator2,
- class T,
- class BinaryOperation1,
- class BinaryOperation2
- >
- static T apply(
- InputIterator1 first1,
- InputIterator2 first2, T init,
- BinaryOperation1 binary_op1,
- BinaryOperation2 binary_op2)
- {
- init = binary_op1(init, binary_op2(*first1, *first2));
- return inner_product_k_t<Size - 1>::apply(
- first1 + 1, first2 + 1, init, binary_op1, binary_op2);
- }
- };
- template <>
- struct inner_product_k_t<0>
- {
- template
- <
- class InputIterator1,
- class InputIterator2,
- class T,
- class BinaryOperation1,
- class BinaryOperation2
- >
- static T apply(
- InputIterator1 first1,
- InputIterator2 first2,
- T init,
- BinaryOperation1 binary_op1,
- BinaryOperation2 binary_op2)
- {
- return init;
- }
- };
- } // namespace detail
- /// static version of std::inner_product
- template
- <
- std::size_t Size,
- class InputIterator1,
- class InputIterator2,
- class T,
- class BinaryOperation1,
- class BinaryOperation2
- >
- BOOST_FORCEINLINE
- T inner_product_k(
- InputIterator1 first1,
- InputIterator2 first2,
- T init,
- BinaryOperation1 binary_op1,
- BinaryOperation2 binary_op2)
- {
- return detail::inner_product_k_t<Size>::apply(
- first1, first2, init, binary_op1, binary_op2);
- }
- /// \brief 1D un-guarded cross-correlation with a variable-size kernel
- template
- <
- typename PixelAccum,
- typename SrcIterator,
- typename KernelIterator,
- typename Size,
- typename DstIterator
- >
- inline
- auto correlate_pixels_n(
- SrcIterator src_begin,
- SrcIterator src_end,
- KernelIterator kernel_begin,
- Size kernel_size,
- DstIterator dst_begin)
- -> DstIterator
- {
- using src_pixel_ref_t = typename pixel_proxy
- <
- typename std::iterator_traits<SrcIterator>::value_type
- >::type;
- using dst_pixel_ref_t = typename pixel_proxy
- <
- typename std::iterator_traits<DstIterator>::value_type
- >::type;
- using kernel_value_t = typename std::iterator_traits<KernelIterator>::value_type;
- PixelAccum accum_zero;
- pixel_zeros_t<PixelAccum>()(accum_zero);
- while (src_begin != src_end)
- {
- pixel_assigns_t<PixelAccum, dst_pixel_ref_t>()(
- std::inner_product(
- src_begin,
- src_begin + kernel_size,
- kernel_begin,
- accum_zero,
- pixel_plus_t<PixelAccum, PixelAccum, PixelAccum>(),
- pixel_multiplies_scalar_t<src_pixel_ref_t, kernel_value_t, PixelAccum>()),
- *dst_begin);
- ++src_begin;
- ++dst_begin;
- }
- return dst_begin;
- }
- /// \brief 1D un-guarded cross-correlation with a fixed-size kernel
- template
- <
- std::size_t Size,
- typename PixelAccum,
- typename SrcIterator,
- typename KernelIterator,
- typename DstIterator
- >
- inline
- auto correlate_pixels_k(
- SrcIterator src_begin,
- SrcIterator src_end,
- KernelIterator kernel_begin,
- DstIterator dst_begin)
- -> DstIterator
- {
- using src_pixel_ref_t = typename pixel_proxy
- <
- typename std::iterator_traits<SrcIterator>::value_type
- >::type;
- using dst_pixel_ref_t = typename pixel_proxy
- <
- typename std::iterator_traits<DstIterator>::value_type
- >::type;
- using kernel_type = typename std::iterator_traits<KernelIterator>::value_type;
- PixelAccum accum_zero;
- pixel_zeros_t<PixelAccum>()(accum_zero);
- while (src_begin != src_end)
- {
- pixel_assigns_t<PixelAccum, dst_pixel_ref_t>()(
- inner_product_k<Size>(
- src_begin,
- kernel_begin,
- accum_zero,
- pixel_plus_t<PixelAccum, PixelAccum, PixelAccum>(),
- pixel_multiplies_scalar_t<src_pixel_ref_t, kernel_type, PixelAccum>()),
- *dst_begin);
- ++src_begin;
- ++dst_begin;
- }
- return dst_begin;
- }
- /// \brief destination is set to be product of the source and a scalar
- /// \tparam PixelAccum - TODO
- /// \tparam SrcView Models ImageViewConcept
- /// \tparam DstView Models MutableImageViewConcept
- template <typename PixelAccum, typename SrcView, typename Scalar, typename DstView>
- inline
- void view_multiplies_scalar(SrcView const& src_view, Scalar const& scalar, DstView const& dst_view)
- {
- static_assert(std::is_scalar<Scalar>::value, "Scalar is not scalar");
- BOOST_ASSERT(src_view.dimensions() == dst_view.dimensions());
- using src_pixel_ref_t = typename pixel_proxy<typename SrcView::value_type>::type;
- using dst_pixel_ref_t = typename pixel_proxy<typename DstView::value_type>::type;
- using y_coord_t = typename SrcView::y_coord_t;
- y_coord_t const height = src_view.height();
- for (y_coord_t y = 0; y < height; ++y)
- {
- typename SrcView::x_iterator it_src = src_view.row_begin(y);
- typename DstView::x_iterator it_dst = dst_view.row_begin(y);
- typename SrcView::x_iterator it_src_end = src_view.row_end(y);
- while (it_src != it_src_end)
- {
- pixel_assigns_t<PixelAccum, dst_pixel_ref_t>()(
- pixel_multiplies_scalar_t<src_pixel_ref_t, Scalar, PixelAccum>()(*it_src, scalar),
- *it_dst);
- ++it_src;
- ++it_dst;
- }
- }
- }
- /// \ingroup ImageAlgorithms
- /// \brief Boundary options for image boundary extension
- enum class boundary_option
- {
- output_ignore, /// do nothing to the output
- output_zero, /// set the output to zero
- extend_padded, /// assume the source boundaries to be padded already
- extend_zero, /// assume the source boundaries to be zero
- extend_constant /// assume the source boundaries to be the boundary value
- };
- namespace detail
- {
- template <typename SrcView, typename RltView>
- void extend_row_impl(
- SrcView const& src_view,
- RltView result_view,
- std::size_t extend_count,
- boundary_option option)
- {
- std::ptrdiff_t extend_count_ = static_cast<std::ptrdiff_t>(extend_count);
- if (option == boundary_option::extend_constant)
- {
- for (std::ptrdiff_t i = 0; i < result_view.height(); i++)
- {
- if(i >= extend_count_ && i < extend_count_ + src_view.height())
- {
- assign_pixels(
- src_view.row_begin(i - extend_count_),
- src_view.row_end(i - extend_count_),
- result_view.row_begin(i)
- );
- }
- else if(i < extend_count_)
- {
- assign_pixels(src_view.row_begin(0), src_view.row_end(0), result_view.row_begin(i));
- }
- else
- {
- assign_pixels(
- src_view.row_begin(src_view.height() - 1),
- src_view.row_end(src_view.height() - 1),
- result_view.row_begin(i)
- );
- }
- }
- }
- else if (option == boundary_option::extend_zero)
- {
- typename SrcView::value_type acc_zero;
- pixel_zeros_t<typename SrcView::value_type>()(acc_zero);
- for (std::ptrdiff_t i = 0; i < result_view.height(); i++)
- {
- if (i >= extend_count_ && i < extend_count_ + src_view.height())
- {
- assign_pixels(
- src_view.row_begin(i - extend_count_),
- src_view.row_end(i - extend_count_),
- result_view.row_begin(i)
- );
- }
- else
- {
- std::fill_n(result_view.row_begin(i), result_view.width(), acc_zero);
- }
- }
- }
- else if (option == boundary_option::extend_padded)
- {
- auto original_view = subimage_view(
- src_view,
- 0,
- -extend_count,
- src_view.width(),
- src_view.height() + (2 * extend_count)
- );
- for (std::ptrdiff_t i = 0; i < result_view.height(); i++)
- {
- assign_pixels(
- original_view.row_begin(i),
- original_view.row_end(i),
- result_view.row_begin(i)
- );
- }
- }
- else
- {
- BOOST_ASSERT_MSG(false, "Invalid boundary option");
- }
- }
- } //namespace detail
- /// \brief adds new row at top and bottom.
- /// Image padding introduces new pixels around the edges of an image.
- /// The border provides space for annotations or acts as a boundary when using advanced filtering techniques.
- /// \tparam SrcView Models ImageViewConcept
- /// \tparam extend_count number of rows to be added each side
- /// \tparam option - TODO
- template <typename SrcView>
- auto extend_row(
- SrcView const& src_view,
- std::size_t extend_count,
- boundary_option option
- ) -> typename gil::image<typename SrcView::value_type>
- {
- typename gil::image<typename SrcView::value_type>
- result_img(src_view.width(), src_view.height() + (2 * extend_count));
- auto result_view = view(result_img);
- detail::extend_row_impl(src_view, result_view, extend_count, option);
- return result_img;
- }
- /// \brief adds new column at left and right.
- /// Image padding introduces new pixels around the edges of an image.
- /// The border provides space for annotations or acts as a boundary when using advanced filtering techniques.
- /// \tparam SrcView Models ImageViewConcept
- /// \tparam extend_count number of columns to be added each side
- /// \tparam option - TODO
- template <typename SrcView>
- auto extend_col(
- SrcView const& src_view,
- std::size_t extend_count,
- boundary_option option
- ) -> typename gil::image<typename SrcView::value_type>
- {
- auto src_view_rotate = rotated90cw_view(src_view);
- typename gil::image<typename SrcView::value_type>
- result_img(src_view.width() + (2 * extend_count), src_view.height());
- auto result_view = rotated90cw_view(view(result_img));
- detail::extend_row_impl(src_view_rotate, result_view, extend_count, option);
- return result_img;
- }
- /// \brief adds new row and column at all sides.
- /// Image padding introduces new pixels around the edges of an image.
- /// The border provides space for annotations or acts as a boundary when using advanced filtering techniques.
- /// \tparam SrcView Models ImageViewConcept
- /// \tparam extend_count number of rows/column to be added each side
- /// \tparam option - TODO
- template <typename SrcView>
- auto extend_boundary(
- SrcView const& src_view,
- std::size_t extend_count,
- boundary_option option
- ) -> typename gil::image<typename SrcView::value_type>
- {
- if (option == boundary_option::extend_padded)
- {
- typename gil::image<typename SrcView::value_type>
- result_img(src_view.width()+(2 * extend_count), src_view.height()+(2 * extend_count));
- typename gil::image<typename SrcView::value_type>::view_t result_view = view(result_img);
- auto original_view = subimage_view(
- src_view,
- -extend_count,
- -extend_count,
- src_view.width() + (2 * extend_count),
- src_view.height() + (2 * extend_count)
- );
- for (std::ptrdiff_t i = 0; i < result_view.height(); i++)
- {
- assign_pixels(
- original_view.row_begin(i),
- original_view.row_end(i),
- result_view.row_begin(i)
- );
- }
- return result_img;
- }
- auto auxilary_img = extend_col(src_view, extend_count, option);
- return extend_row(view(auxilary_img), extend_count, option);
- }
- } } // namespace boost::gil
- #endif
|