Boost GIL


algorithm.hpp
1//
2// Copyright 2005-2007 Adobe Systems Incorporated
3// Copyright 2021 Pranam Lashkari <plashkari628@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_ALGORITHM_HPP
10#define BOOST_GIL_ALGORITHM_HPP
11
12#include <boost/gil/metafunctions.hpp>
13#include <boost/gil/pixel_iterator.hpp>
14#include <boost/gil/pixel_numeric_operations.hpp>
15#include <boost/gil/image.hpp>
16#include <boost/gil/bit_aligned_pixel_iterator.hpp>
17#include <boost/gil/color_base_algorithm.hpp>
18#include <boost/gil/concepts.hpp>
19#include <boost/gil/image_view.hpp>
20#include <boost/gil/image_view_factory.hpp>
21#include <boost/gil/detail/mp11.hpp>
22#include <boost/gil/detail/type_traits.hpp>
23
24#include <boost/assert.hpp>
25#include <boost/config.hpp>
26
27#include <algorithm>
28#include <cstddef>
29#include <cstring>
30#include <iterator>
31#include <memory>
32#include <type_traits>
33#include <typeinfo>
34#include <numeric>
35
36namespace boost { namespace gil {
37
38//forward declarations
39template <typename ChannelPtr, typename ColorSpace>
40struct planar_pixel_iterator;
41template <typename Iterator>
42class memory_based_step_iterator;
43template <typename StepIterator>
44class memory_based_2d_locator;
45
46// a tag denoting incompatible arguments
47struct error_t {};
48
73
77
86template <typename Derived, typename Result=void>
88{
89 using result_type = Result;
90
91 template <typename V1, typename V2> BOOST_FORCEINLINE
92 auto operator()(const std::pair<const V1*,const V2*>& p) const -> result_type {
93 return apply(*p.first, *p.second, typename views_are_compatible<V1,V2>::type());
94 }
95
96 template <typename V1, typename V2> BOOST_FORCEINLINE
97 auto operator()(const V1& v1, const V2& v2) const -> result_type {
98 return apply(v1, v2, typename views_are_compatible<V1,V2>::type());
99 }
100
101 auto operator()(const error_t&) const -> result_type { throw std::bad_cast(); }
102private:
103
104 // dispatch from apply overload to a function with distinct name
105 template <typename V1, typename V2>
106 BOOST_FORCEINLINE
107 auto apply(V1 const& v1, V2 const& v2, std::false_type) const -> result_type
108 {
109 return ((const Derived*)this)->apply_incompatible(v1, v2);
110 }
111
112 // dispatch from apply overload to a function with distinct name
113 template <typename V1, typename V2>
114 BOOST_FORCEINLINE
115 auto apply(V1 const& v1, V2 const& v2, std::true_type) const -> result_type
116 {
117 return ((const Derived*)this)->apply_compatible(v1, v2);
118 }
119
120 // function with distinct name - it can be overloaded by subclasses
121 template <typename V1, typename V2>
122 BOOST_FORCEINLINE
123 auto apply_incompatible(V1 const& /*v1*/, V2 const& /*v2*/) const -> result_type
124 {
125 throw std::bad_cast();
126 }
127};
128
129}} // namespace boost::gil
130
132// std::copy and gil::copy_pixels
134
138
139namespace std {
140
143template<typename T, typename CS>
144BOOST_FORCEINLINE
145auto copy(
150{
151 auto p = std::copy((unsigned char*)first, (unsigned char*)last, (unsigned char*)dst);
152 return reinterpret_cast<boost::gil::pixel<T, CS>*>(p);
153}
154
157template<typename T, typename CS>
158BOOST_FORCEINLINE
159auto copy(const boost::gil::pixel<T,CS>* first, const boost::gil::pixel<T,CS>* last,
161{
162 return (boost::gil::pixel<T,CS>*)std::copy((unsigned char*)first,(unsigned char*)last, (unsigned char*)dst);
163}
164} // namespace std
165
166namespace boost { namespace gil {
167namespace detail {
168template <typename I, typename O> struct copy_fn {
169 BOOST_FORCEINLINE I operator()(I first, I last, O dst) const { return std::copy(first,last,dst); }
170};
171} // namespace detail
172} } // namespace boost::gil
173
174namespace std {
177template<typename CS, typename IC1, typename IC2> BOOST_FORCEINLINE
179{
180 boost::gil::gil_function_requires<boost::gil::ChannelsCompatibleConcept<typename std::iterator_traits<IC1>::value_type,typename std::iterator_traits<IC2>::value_type>>();
181 static_for_each(first,last,dst,boost::gil::detail::copy_fn<IC1,IC2>());
182 return dst+(last-first);
183}
184} // namespace std
185
186namespace boost { namespace gil {
187namespace detail {
190template <typename I, typename O>
191struct copier_n {
192 BOOST_FORCEINLINE void operator()(I src, typename std::iterator_traits<I>::difference_type n, O dst) const {
193 if (n < 0)
194 return;
195 std::copy(src, src + n, dst);
196 }
197};
198
200template <typename IL, typename O> // IL Models ConstPixelLocatorConcept, O Models PixelIteratorConcept
202 using diff_t = typename std::iterator_traits<iterator_from_2d<IL>>::difference_type;
203 BOOST_FORCEINLINE void operator()(iterator_from_2d<IL> src, diff_t n, O dst) const {
204 gil_function_requires<PixelLocatorConcept<IL>>();
205 gil_function_requires<MutablePixelIteratorConcept<O>>();
206 while (n>0) {
207 diff_t l=src.width()-src.x_pos();
208 diff_t numToCopy=(n<l ? n:l);
209 detail::copy_n(src.x(), numToCopy, dst);
210 dst+=numToCopy;
211 src+=numToCopy;
212 n-=numToCopy;
213 }
214 }
215};
216
218template <typename I, typename OL> // I Models ConstPixelIteratorConcept, OL Models PixelLocatorConcept
220 using diff_t = typename std::iterator_traits<I>::difference_type;
221 BOOST_FORCEINLINE void operator()(I src, diff_t n, iterator_from_2d<OL> dst) const {
222 gil_function_requires<PixelIteratorConcept<I>>();
223 gil_function_requires<MutablePixelLocatorConcept<OL>>();
224 while (n>0) {
225 diff_t l=dst.width()-dst.x_pos();
226 diff_t numToCopy=(n<l ? n:l);
227 detail::copy_n(src, numToCopy, dst.x());
228 dst+=numToCopy;
229 src+=numToCopy;
230 n-=numToCopy;
231 }
232 }
233};
234
236template <typename IL, typename OL>
238 using diff_t = typename iterator_from_2d<IL>::difference_type;
239 BOOST_FORCEINLINE void operator()(iterator_from_2d<IL> src, diff_t n, iterator_from_2d<OL> dst) const {
240 gil_function_requires<PixelLocatorConcept<IL>>();
241 gil_function_requires<MutablePixelLocatorConcept<OL>>();
242 if (src.x_pos()!=dst.x_pos() || src.width()!=dst.width()) {
243 while(n-->0) {
244 *dst++=*src++;
245 }
246 }
247 while (n>0) {
248 diff_t l=dst.width()-dst.x_pos();
249 diff_t numToCopy=(n<l ? n : l);
250 detail::copy_n(src.x(), numToCopy, dst.x());
251 dst+=numToCopy;
252 src+=numToCopy;
253 n-=numToCopy;
254 }
255 }
256};
257
258template <typename SrcIterator, typename DstIterator>
259BOOST_FORCEINLINE auto copy_with_2d_iterators(SrcIterator first, SrcIterator last, DstIterator dst) -> DstIterator {
260 using src_x_iterator = typename SrcIterator::x_iterator;
261 using dst_x_iterator = typename DstIterator::x_iterator;
262
263 typename SrcIterator::difference_type n = last - first;
264
265 if (first.is_1d_traversable()) {
266 if (dst.is_1d_traversable())
267 copier_n<src_x_iterator,dst_x_iterator>()(first.x(),n, dst.x());
268 else
269 copier_n<src_x_iterator,DstIterator >()(first.x(),n, dst);
270 } else {
271 if (dst.is_1d_traversable())
272 copier_n<SrcIterator,dst_x_iterator>()(first,n, dst.x());
273 else
274 copier_n<SrcIterator,DstIterator>()(first,n,dst);
275 }
276 return dst+n;
277}
278} // namespace detail
279} } // namespace boost::gil
280
281namespace std {
284template <typename IL, typename OL>
286{
287 return boost::gil::detail::copy_with_2d_iterators(first,last,dst);
288}
289
290} // namespace std
291
292namespace boost { namespace gil {
295template <typename View1, typename View2> BOOST_FORCEINLINE
296void copy_pixels(const View1& src, const View2& dst)
297{
298 BOOST_ASSERT(src.dimensions() == dst.dimensions());
299 detail::copy_with_2d_iterators(src.begin(),src.end(),dst.begin());
300}
301
303// copy_and_convert_pixels
305
311
312namespace detail {
313template <typename CC>
314class copy_and_convert_pixels_fn : public binary_operation_obj<copy_and_convert_pixels_fn<CC>>
315{
316private:
317 CC _cc;
318public:
319 using result_type = typename binary_operation_obj<copy_and_convert_pixels_fn<default_color_converter>>::result_type;
320 copy_and_convert_pixels_fn() {}
321 copy_and_convert_pixels_fn(CC cc_in) : _cc(cc_in) {}
322 // when the two color spaces are incompatible, a color conversion is performed
323 template <typename V1, typename V2> BOOST_FORCEINLINE
324 auto apply_incompatible(const V1& src, const V2& dst) const -> result_type {
325 copy_pixels(color_converted_view<typename V2::value_type>(src,_cc),dst);
326 }
327
328 // If the two color spaces are compatible, copy_and_convert is just copy
329 template <typename V1, typename V2> BOOST_FORCEINLINE
330 auto apply_compatible(const V1& src, const V2& dst) const -> result_type {
331 copy_pixels(src,dst);
332 }
333};
334} // namespace detail
335
337template <typename V1, typename V2,typename CC>
338BOOST_FORCEINLINE
339void copy_and_convert_pixels(const V1& src, const V2& dst,CC cc) {
340 detail::copy_and_convert_pixels_fn<CC> ccp(cc);
341 ccp(src,dst);
342}
343
344struct default_color_converter;
345
347template <typename View1, typename View2>
348BOOST_FORCEINLINE
349void copy_and_convert_pixels(const View1& src, const View2& dst) {
350 detail::copy_and_convert_pixels_fn<default_color_converter> ccp;
351 ccp(src,dst);
352}
353} } // namespace boost::gil
354
356// std::fill and gil::fill_pixels
358
362
363namespace std {
372template <typename IL, typename V>
374 boost::gil::gil_function_requires<boost::gil::MutablePixelLocatorConcept<IL>>();
375 if (first.is_1d_traversable()) {
376 std::fill(first.x(), last.x(), val);
377 } else {
378 // fill row by row
379 std::ptrdiff_t n=last-first;
380 while (n>0) {
381 std::ptrdiff_t numToDo=std::min<const std::ptrdiff_t>(n,(std::ptrdiff_t)(first.width()-first.x_pos()));
382 std::fill_n(first.x(), numToDo, val);
383 first+=numToDo;
384 n-=numToDo;
385 }
386 }
387}
388} // namespace std
389
390namespace boost { namespace gil {
391
392namespace detail {
393
396 template <typename It, typename P>
397 void operator()(It first, It last, const P& p_in) {
398 std::fill(first,last,p_in);
399 }
400};
401
403template <typename It, typename P>
404BOOST_FORCEINLINE
405void fill_aux(It first, It last, P const& p, std::true_type)
406{
407 static_for_each(first, last, p, std_fill_t());
408}
409
411template <typename It, typename P>
412BOOST_FORCEINLINE
413void fill_aux(It first, It last, P const& p, std::false_type)
414{
415 std::fill(first, last, p);
416}
417
418} // namespace detail
419
422template <typename View, typename Value>
423BOOST_FORCEINLINE
424void fill_pixels(View const& view, Value const& value)
425{
426 if (view.is_1d_traversable())
427 {
428 detail::fill_aux(
429 view.begin().x(), view.end().x(), value, is_planar<View>());
430 }
431 else
432 {
433 for (std::ptrdiff_t y = 0; y < view.height(); ++y)
434 detail::fill_aux(
435 view.row_begin(y), view.row_end(y), value, is_planar<View>());
436 }
437}
438
440// destruct_pixels
442
446
447namespace detail {
448template <typename Iterator>
449BOOST_FORCEINLINE
450void destruct_range_impl(Iterator first, Iterator last,
451 typename std::enable_if
452 <
453 mp11::mp_and
454 <
455 std::is_pointer<Iterator>,
456 mp11::mp_not
457 <
458 detail::is_trivially_destructible<typename std::iterator_traits<Iterator>::value_type>
459 >
460 >::value
461 >::type* /*ptr*/ = 0)
462{
463 while (first != last)
464 {
465 first->~value_t();
466 ++first;
467 }
468}
469
470template <typename Iterator>
471BOOST_FORCEINLINE
472void destruct_range_impl(Iterator /*first*/, Iterator /*last*/,
473 typename std::enable_if
474 <
475 mp11::mp_or
476 <
477 mp11::mp_not<std::is_pointer<Iterator>>,
478 detail::is_trivially_destructible<typename std::iterator_traits<Iterator>::value_type>
479 >::value
480 >::type* /* ptr */ = nullptr)
481{
482}
483
484template <typename Iterator>
485BOOST_FORCEINLINE
486void destruct_range(Iterator first, Iterator last)
487{
488 destruct_range_impl(first, last);
489}
490
491struct std_destruct_t
492{
493 template <typename Iterator>
494 void operator()(Iterator first, Iterator last) const
495 {
496 destruct_range(first,last);
497 }
498};
499
501template <typename It>
502BOOST_FORCEINLINE
503void destruct_aux(It first, It last, std::true_type)
504{
505 static_for_each(first,last,std_destruct_t());
506}
507
509template <typename It>
510BOOST_FORCEINLINE
511void destruct_aux(It first, It last, std::false_type)
512{
513 destruct_range(first,last);
514}
515
516} // namespace detail
517
520template <typename View>
521BOOST_FORCEINLINE
522void destruct_pixels(View const& view)
523{
524 if (view.is_1d_traversable())
525 {
526 detail::destruct_aux(
527 view.begin().x(), view.end().x(), is_planar<View>());
528 }
529 else
530 {
531 for (std::ptrdiff_t y = 0; y < view.height(); ++y)
532 detail::destruct_aux(
533 view.row_begin(y), view.row_end(y), is_planar<View>());
534 }
535}
536
538// uninitialized_fill_pixels
540
544
545namespace detail {
546
549template <typename It, typename P>
550BOOST_FORCEINLINE
551void uninitialized_fill_aux(It first, It last, P const& p, std::true_type)
552{
553 std::size_t channel = 0;
554 try
555 {
556 using pixel_t = typename std::iterator_traits<It>::value_type;
557 while (channel < num_channels<pixel_t>::value)
558 {
559 std::uninitialized_fill(
560 dynamic_at_c(first,channel),
561 dynamic_at_c(last,channel),
562 dynamic_at_c(p,channel));
563
564 ++channel;
565 }
566 }
567 catch (...)
568 {
569 for (std::size_t c = 0; c < channel; ++c)
570 destruct_range(dynamic_at_c(first, c), dynamic_at_c(last, c));
571 throw;
572 }
573}
574
577template <typename It, typename P>
578BOOST_FORCEINLINE
579void uninitialized_fill_aux(It first, It last, P const& p, std::false_type)
580{
581 std::uninitialized_fill(first,last,p);
582}
583
584} // namespace detail
585
590template <typename View, typename Value>
591void uninitialized_fill_pixels(const View& view, const Value& val) {
592 if (view.is_1d_traversable())
593 detail::uninitialized_fill_aux(view.begin().x(), view.end().x(),
594 val,is_planar<View>());
595 else {
596 typename View::y_coord_t y = 0;
597 try {
598 for (y=0; y<view.height(); ++y)
599 detail::uninitialized_fill_aux(view.row_begin(y),view.row_end(y),
600 val,is_planar<View>());
601 } catch(...) {
602 for (typename View::y_coord_t y0=0; y0<y; ++y0)
603 detail::destruct_aux(view.row_begin(y0),view.row_end(y0), is_planar<View>());
604 throw;
605 }
606 }
607}
608
610// default_construct_pixels
612
616
617namespace detail {
618template <typename It> BOOST_FORCEINLINE
619void default_construct_range_impl(It first, It last, std::true_type)
620{
621 It first1 = first;
622 try
623 {
624 using value_t = typename std::iterator_traits<It>::value_type;
625 while (first != last)
626 {
627 new (first) value_t();
628 ++first;
629 }
630 }
631 catch (...)
632 {
633 destruct_range(first1, first);
634 throw;
635 }
636}
637
638template <typename It>
639BOOST_FORCEINLINE
640void default_construct_range_impl(It, It, std::false_type) {}
641
642template <typename It>
643BOOST_FORCEINLINE
644void default_construct_range(It first, It last)
645{
646 default_construct_range_impl(first, last, typename std::is_pointer<It>::type());
647}
648
650template <typename It>
651BOOST_FORCEINLINE
652void default_construct_aux(It first, It last, std::true_type)
653{
654 std::size_t channel = 0;
655 try
656 {
657 using pixel_t = typename std::iterator_traits<It>::value_type;
658 while (channel < num_channels<pixel_t>::value)
659 {
660 default_construct_range(dynamic_at_c(first, channel), dynamic_at_c(last, channel));
661 ++channel;
662 }
663 }
664 catch (...)
665 {
666 for (std::size_t c = 0; c < channel; ++c)
667 destruct_range(dynamic_at_c(first, c), dynamic_at_c(last, c));
668 throw;
669 }
670}
671
673template <typename It>
674BOOST_FORCEINLINE
675void default_construct_aux(It first, It last, std::false_type)
676{
677 default_construct_range(first, last);
678}
679
680template <typename View, bool IsPlanar>
681struct has_trivial_pixel_constructor
682 : detail::is_trivially_default_constructible<typename View::value_type>
683{};
684
685template <typename View>
686struct has_trivial_pixel_constructor<View, true>
687 : detail::is_trivially_default_constructible<typename channel_type<View>::type>
688{};
689
690template<typename View, bool IsTriviallyConstructible>
691BOOST_FORCEINLINE
692void default_construct_pixels_impl(
693 View const& view,
694 std::enable_if<!IsTriviallyConstructible>* /*ptr*/ = nullptr)
695{
696 if (view.is_1d_traversable())
697 {
698 detail::default_construct_aux(
699 view.begin().x(), view.end().x(), is_planar<View>());
700 }
701 else
702 {
703 typename View::y_coord_t y = 0;
704 try
705 {
706 for( y = 0; y < view.height(); ++y )
707 detail::default_construct_aux(
708 view.row_begin(y), view.row_end(y), is_planar<View>());
709 }
710 catch(...)
711 {
712 for (typename View::y_coord_t y0 = 0; y0 < y; ++y0 )
713 detail::destruct_aux(
714 view.row_begin(y0), view.row_end(y0), is_planar<View>());
715
716 throw;
717 }
718 }
719}
720
721} // namespace detail
722
727template <typename View>
729{
730 detail::default_construct_pixels_impl
731 <
732 View,
733 detail::has_trivial_pixel_constructor
734 <
735 View,
736 is_planar<View>::value
737 >::value
738 >(view);
739}
740
742// uninitialized_copy_pixels
744
748
749namespace detail {
750
751enum class copy_planarity_condition
752{
753 planar_to_planar,
754 interleaved_to_planar,
755 mixed_to_interleaved
756};
757
758using planar_to_planar_type =
759 std::integral_constant
760 <
761 copy_planarity_condition, copy_planarity_condition::planar_to_planar
762 >;
763using interleaved_to_planar_type =
764 std::integral_constant
765 <
766 copy_planarity_condition, copy_planarity_condition::interleaved_to_planar
767 >;
768using mixed_to_interleaved_type =
769 std::integral_constant
770 <
771 copy_planarity_condition, copy_planarity_condition::mixed_to_interleaved
772 >;
773
775template <typename It1, typename It2>
776BOOST_FORCEINLINE
777void uninitialized_copy_aux(It1 first1, It1 last1, It2 first2, It2 last2, planar_to_planar_type)
778{
779 std::size_t channel=0;
780 try {
781 using pixel_t = typename std::iterator_traits<It1>::value_type;
782 while (channel < num_channels<pixel_t>::value)
783 {
784 std::uninitialized_copy(
785 dynamic_at_c(first1, channel),
786 dynamic_at_c(last1, channel),
787 dynamic_at_c(first2, channel));
788 ++channel;
789 }
790 }
791 catch (...)
792 {
793 It2 last2 = first2;
794 std::advance(last2, std::distance(first1, last1));
795 for (std::size_t c = 0; c < channel; ++c)
796 destruct_range(dynamic_at_c(first2, c), dynamic_at_c(last2, c));
797 throw;
798 }
799}
800
802template <typename It1, typename It2>
803BOOST_FORCEINLINE
804void uninitialized_copy_aux(It1 first1, It1 last1, It2 first2, It2, mixed_to_interleaved_type)
805{
806 std::uninitialized_copy(first1, last1, first2);
807}
808
810template <typename It1, typename It2>
811BOOST_FORCEINLINE
812void uninitialized_copy_aux(It1 first1, It1, It2 first2, It2 last2,
813interleaved_to_planar_type)
814{
815 default_construct_aux(first2, last2, std::true_type());
816
817 typename It2::difference_type n = last2 - first2;
818 copier_n<It1,It2>()(first1, n, first2);
819}
820} // namespace detail
821
826template <typename View1, typename View2>
827void uninitialized_copy_pixels(View1 const& view1, View2 const& view2)
828{
829 using copy_planarity_condition = detail::copy_planarity_condition;
830 using copy_planarity_condition_type =
831 std::integral_constant
832 <
833 copy_planarity_condition,
834 !is_planar<View2>::value
835 ? copy_planarity_condition::mixed_to_interleaved
836 : (is_planar<View1>::value
837 ? copy_planarity_condition::planar_to_planar
838 : copy_planarity_condition::interleaved_to_planar)
839 >;
840 BOOST_ASSERT(view1.dimensions() == view2.dimensions());
841
842 if (view1.is_1d_traversable() && view2.is_1d_traversable())
843 {
844 detail::uninitialized_copy_aux(
845 view1.begin().x(), view1.end().x(), view2.begin().x(), view2.end().x(),
846 copy_planarity_condition_type());
847 }
848 else
849 {
850 typename View1::y_coord_t y = 0;
851 try
852 {
853 for (y = 0; y < view1.height(); ++y)
854 detail::uninitialized_copy_aux(
855 view1.row_begin(y), view1.row_end(y), view2.row_begin(y), view2.row_end(y),
856 copy_planarity_condition_type());
857 }
858 catch(...)
859 {
860 for (typename View1::y_coord_t y0 = 0; y0 < y; ++y0)
861 detail::destruct_aux(view2.row_begin(y0), view2.row_end(y0), is_planar<View2>());
862 throw;
863 }
864 }
865}
866
868// for_each_pixel
870
879
881template <typename View, typename F>
882F for_each_pixel(View const& view, F fun)
883{
884 if (view.is_1d_traversable())
885 {
886 return std::for_each(view.begin().x(), view.end().x(), fun);
887 }
888 else
889 {
890 for (std::ptrdiff_t y = 0; y < view.height(); ++y)
891 for (auto begin = view.row_begin(y), end = view.row_end(y); begin != end; ++begin)
892 fun(*begin);
893 return fun;
894 }
895}
896
900
902template <typename View, typename F>
903F for_each_pixel_position(View const& view, F fun)
904{
905 typename View::xy_locator loc = view.xy_at(0, 0);
906 for (std::ptrdiff_t y = 0; y < view.height(); ++y)
907 {
908 for (std::ptrdiff_t x = 0; x < view.width(); ++x, ++loc.x())
909 fun(loc);
910 loc.x() -= view.width(); ++loc.y();
911 }
912 return fun;
913}
914
916// generate_pixels
918
922
925template <typename View, typename F>
926void generate_pixels(View const& view, F fun)
927{
928 if (view.is_1d_traversable())
929 {
930 std::generate(view.begin().x(), view.end().x(), fun);
931 }
932 else
933 {
934 for (std::ptrdiff_t y = 0; y < view.height(); ++y)
935 std::generate(view.row_begin(y), view.row_end(y), fun);
936 }
937}
938
940// std::equal and gil::equal_pixels for GIL constructs
942
946
947template <typename I1, typename I2>
948BOOST_FORCEINLINE
949bool equal_n(I1 i1, std::ptrdiff_t n, I2 i2);
950
951namespace detail {
952
953template <typename I1, typename I2>
954struct equal_n_fn
955{
956 BOOST_FORCEINLINE
957 bool operator()(I1 i1, std::ptrdiff_t n, I2 i2) const
958 {
959 return std::equal(i1, i1 + n, i2);
960 }
961};
962
965template<typename T, typename CS>
966struct equal_n_fn<pixel<T, CS> const*, pixel<T, CS> const*>
967{
968 BOOST_FORCEINLINE
969 bool operator()(pixel<T, CS> const* i1, std::ptrdiff_t n, pixel<T, CS> const* i2) const
970 {
971 return memcmp(i1, i2, n * sizeof(pixel<T, CS>)) == 0;
972 }
973};
974
975template<typename T, typename CS>
976struct equal_n_fn<pixel<T, CS>*, pixel<T, CS>*>
977 : equal_n_fn<pixel<T, CS> const*, pixel<T, CS> const*>
978{};
979
983template<typename IC, typename CS>
984struct equal_n_fn<planar_pixel_iterator<IC, CS>, planar_pixel_iterator<IC, CS>>
985{
986 BOOST_FORCEINLINE
987 bool operator()(planar_pixel_iterator<IC, CS> const i1, std::ptrdiff_t n, planar_pixel_iterator<IC, CS> const i2) const
988 {
989 // FIXME: ptrdiff_t vs size_t
990 constexpr std::ptrdiff_t byte_size = n * sizeof(typename std::iterator_traits<IC>::value_type);
991 for (std::ptrdiff_t i = 0; i < mp11::mp_size<CS>::value; ++i)
992 {
993 if (memcmp(dynamic_at_c(i1, i), dynamic_at_c(i2, i), byte_size) != 0)
994 return false;
995 }
996 return true;
997 }
998};
999
1003template <typename Loc, typename It>
1004struct equal_n_fn<boost::gil::iterator_from_2d<Loc>, It>
1005{
1006 BOOST_FORCEINLINE
1007 bool operator()(boost::gil::iterator_from_2d<Loc> i1, std::ptrdiff_t n, It i2) const
1008 {
1009 gil_function_requires<boost::gil::PixelLocatorConcept<Loc>>();
1010 gil_function_requires<boost::gil::PixelIteratorConcept<It>>();
1011 while (n > 0)
1012 {
1013 std::ptrdiff_t const num = std::min<std::ptrdiff_t>(n, i1.width() - i1.x_pos());
1014 if (!equal_n(i1.x(), num, i2))
1015 return false;
1016 i1 += num;
1017 i2 += num;
1018 n -= num;
1019 }
1020 return true;
1021 }
1022};
1023
1027template <typename It, typename Loc>
1028struct equal_n_fn<It, boost::gil::iterator_from_2d<Loc>>
1029{
1030 BOOST_FORCEINLINE
1031 bool operator()(It i1, std::ptrdiff_t n, boost::gil::iterator_from_2d<Loc> i2) const
1032 {
1033 gil_function_requires<boost::gil::PixelIteratorConcept<It>>();
1034 gil_function_requires<boost::gil::PixelLocatorConcept<Loc>>();
1035 while (n > 0)
1036 {
1037 std::ptrdiff_t const num = std::min<std::ptrdiff_t>(n, i2.width() - i2.x_pos());
1038 if (!equal_n(i1, num, i2.x()))
1039 return false;
1040 i1 += num;
1041 i2 += num;
1042 n -= num;
1043 }
1044 return true;
1045 }
1046};
1047
1049template <typename Loc1, typename Loc2>
1051 BOOST_FORCEINLINE bool operator()(boost::gil::iterator_from_2d<Loc1> i1, std::ptrdiff_t n, boost::gil::iterator_from_2d<Loc2> i2) const {
1052 gil_function_requires<boost::gil::PixelLocatorConcept<Loc1>>();
1053 gil_function_requires<boost::gil::PixelLocatorConcept<Loc2>>();
1054 if (i1.x_pos()!=i2.x_pos() || i1.width()!=i2.width()) {
1055 while(n-->0) {
1056 if (*i1++!=*i2++) return false;
1057 }
1058 }
1059 while (n>0) {
1060 std::ptrdiff_t num=std::min<const std::ptrdiff_t>(n,i2.width()-i2.x_pos());
1061 if (!equal_n(i1.x(), num, i2.x()))
1062 return false;
1063 i1+=num;
1064 i2+=num;
1065 n-=num;
1066 }
1067 return true;
1068 }
1069};
1070} // namespace detail
1071
1072template <typename I1, typename I2> BOOST_FORCEINLINE
1073bool equal_n(I1 i1, std::ptrdiff_t n, I2 i2) {
1074 return detail::equal_n_fn<I1,I2>()(i1,n,i2);
1075}
1076} } // namespace boost::gil
1077
1078namespace std {
1090template <typename Loc1, typename Loc2> BOOST_FORCEINLINE
1092 boost::gil::gil_function_requires<boost::gil::PixelLocatorConcept<Loc1>>();
1093 boost::gil::gil_function_requires<boost::gil::PixelLocatorConcept<Loc2>>();
1094 std::ptrdiff_t n=last-first;
1095 if (first.is_1d_traversable()) {
1096 if (first2.is_1d_traversable())
1097 return boost::gil::detail::equal_n_fn<typename Loc1::x_iterator,typename Loc2::x_iterator>()(first.x(),n, first2.x());
1098 else
1099 return boost::gil::detail::equal_n_fn<typename Loc1::x_iterator,boost::gil::iterator_from_2d<Loc2>>()(first.x(),n, first2);
1100 } else {
1101 if (first2.is_1d_traversable())
1102 return boost::gil::detail::equal_n_fn<boost::gil::iterator_from_2d<Loc1>,typename Loc2::x_iterator>()(first,n, first2.x());
1103 else
1104 return boost::gil::detail::equal_n_fn<boost::gil::iterator_from_2d<Loc1>,boost::gil::iterator_from_2d<Loc2>>()(first,n,first2);
1105 }
1106}
1107} // namespace std
1108
1109namespace boost { namespace gil {
1112template <typename View1, typename View2> BOOST_FORCEINLINE
1113bool equal_pixels(const View1& v1, const View2& v2) {
1114 BOOST_ASSERT(v1.dimensions() == v2.dimensions());
1115 return std::equal(v1.begin(),v1.end(),v2.begin()); // std::equal has overloads with GIL iterators for optimal performance
1116}
1117
1123
1127
1130template <typename View1, typename View2, typename F> BOOST_FORCEINLINE
1131F transform_pixels(const View1& src,const View2& dst, F fun) {
1132 BOOST_ASSERT(src.dimensions() == dst.dimensions());
1133 for (std::ptrdiff_t y=0; y<src.height(); ++y) {
1134 typename View1::x_iterator srcIt=src.row_begin(y);
1135 typename View2::x_iterator dstIt=dst.row_begin(y);
1136 for (std::ptrdiff_t x=0; x<src.width(); ++x)
1137 dstIt[x]=fun(srcIt[x]);
1138 }
1139 return fun;
1140}
1141
1144template <typename View1, typename View2, typename View3, typename F> BOOST_FORCEINLINE
1145F transform_pixels(const View1& src1, const View2& src2,const View3& dst, F fun) {
1146 for (std::ptrdiff_t y=0; y<dst.height(); ++y) {
1147 typename View1::x_iterator srcIt1=src1.row_begin(y);
1148 typename View2::x_iterator srcIt2=src2.row_begin(y);
1149 typename View3::x_iterator dstIt=dst.row_begin(y);
1150 for (std::ptrdiff_t x=0; x<dst.width(); ++x)
1151 dstIt[x]=fun(srcIt1[x],srcIt2[x]);
1152 }
1153 return fun;
1154}
1155
1159
1162template <typename View1, typename View2, typename F> BOOST_FORCEINLINE
1163F transform_pixel_positions(const View1& src,const View2& dst, F fun) {
1164 BOOST_ASSERT(src.dimensions() == dst.dimensions());
1165 typename View1::xy_locator loc=src.xy_at(0,0);
1166 for (std::ptrdiff_t y=0; y<src.height(); ++y) {
1167 typename View2::x_iterator dstIt=dst.row_begin(y);
1168 for (std::ptrdiff_t x=0; x<src.width(); ++x, ++loc.x())
1169 dstIt[x]=fun(loc);
1170 loc.x()-=src.width(); ++loc.y();
1171 }
1172 return fun;
1173}
1174
1177template <typename View1, typename View2, typename View3, typename F> BOOST_FORCEINLINE
1178F transform_pixel_positions(const View1& src1,const View2& src2,const View3& dst, F fun) {
1179 BOOST_ASSERT(src1.dimensions() == dst.dimensions());
1180 BOOST_ASSERT(src2.dimensions() == dst.dimensions());
1181 typename View1::xy_locator loc1=src1.xy_at(0,0);
1182 typename View2::xy_locator loc2=src2.xy_at(0,0);
1183 for (std::ptrdiff_t y=0; y<src1.height(); ++y) {
1184 typename View3::x_iterator dstIt=dst.row_begin(y);
1185 for (std::ptrdiff_t x=0; x<src1.width(); ++x, ++loc1.x(), ++loc2.x())
1186 dstIt[x]=fun(loc1,loc2);
1187 loc1.x()-=src1.width(); ++loc1.y();
1188 loc2.x()-=src2.width(); ++loc2.y();
1189 }
1190 return fun;
1191}
1192
1193
1194// Code below this line is moved here from <boost/gil/extension/numeric/algorithm.hpp>
1195
1200template <typename T>
1201struct pixel_proxy : std::remove_reference<typename T::reference> {};
1202
1204template <typename Iterator1, typename Iterator2, typename BinaryFunction>
1205BinaryFunction for_each(Iterator1 first1, Iterator1 last1, Iterator2 first2, BinaryFunction f)
1206{
1207 while (first1 != last1)
1208 f(*first1++, *first2++);
1209 return f;
1210}
1211
1212template <typename SrcIterator, typename DstIterator>
1213inline
1214auto assign_pixels(SrcIterator src, SrcIterator src_end, DstIterator dst) -> DstIterator
1215{
1216 for_each(src, src_end, dst,
1217 pixel_assigns_t
1218 <
1219 typename pixel_proxy<typename std::iterator_traits<SrcIterator>::value_type>::type,
1220 typename pixel_proxy<typename std::iterator_traits<DstIterator>::value_type>::type
1221 >());
1222 return dst + (src_end - src);
1223}
1224
1225namespace detail {
1226
1227template <std::size_t Size>
1228struct inner_product_k_t
1229{
1230 template
1231 <
1232 class InputIterator1,
1233 class InputIterator2,
1234 class T,
1235 class BinaryOperation1,
1236 class BinaryOperation2
1237 >
1238 static T apply(
1239 InputIterator1 first1,
1240 InputIterator2 first2, T init,
1241 BinaryOperation1 binary_op1,
1242 BinaryOperation2 binary_op2)
1243 {
1244 init = binary_op1(init, binary_op2(*first1, *first2));
1245 return inner_product_k_t<Size - 1>::apply(
1246 first1 + 1, first2 + 1, init, binary_op1, binary_op2);
1247 }
1248};
1249
1250template <>
1251struct inner_product_k_t<0>
1252{
1253 template
1254 <
1255 class InputIterator1,
1256 class InputIterator2,
1257 class T,
1258 class BinaryOperation1,
1259 class BinaryOperation2
1260 >
1261 static T apply(
1262 InputIterator1 first1,
1263 InputIterator2 first2,
1264 T init,
1265 BinaryOperation1 binary_op1,
1266 BinaryOperation2 binary_op2)
1267 {
1268 return init;
1269 }
1270};
1271
1272} // namespace detail
1273
1275template
1276<
1277 std::size_t Size,
1278 class InputIterator1,
1279 class InputIterator2,
1280 class T,
1281 class BinaryOperation1,
1282 class BinaryOperation2
1283>
1284BOOST_FORCEINLINE
1285T inner_product_k(
1286 InputIterator1 first1,
1287 InputIterator2 first2,
1288 T init,
1289 BinaryOperation1 binary_op1,
1290 BinaryOperation2 binary_op2)
1291{
1292 return detail::inner_product_k_t<Size>::apply(
1293 first1, first2, init, binary_op1, binary_op2);
1294}
1295
1297template
1298<
1299 typename PixelAccum,
1300 typename SrcIterator,
1301 typename KernelIterator,
1302 typename Size,
1303 typename DstIterator
1304>
1305inline
1306auto correlate_pixels_n(
1307 SrcIterator src_begin,
1308 SrcIterator src_end,
1309 KernelIterator kernel_begin,
1310 Size kernel_size,
1311 DstIterator dst_begin)
1312 -> DstIterator
1313{
1314 using src_pixel_ref_t = typename pixel_proxy
1315 <
1316 typename std::iterator_traits<SrcIterator>::value_type
1317 >::type;
1318 using dst_pixel_ref_t = typename pixel_proxy
1319 <
1320 typename std::iterator_traits<DstIterator>::value_type
1321 >::type;
1322 using kernel_value_t = typename std::iterator_traits<KernelIterator>::value_type;
1323
1324 PixelAccum accum_zero;
1325 pixel_zeros_t<PixelAccum>()(accum_zero);
1326 while (src_begin != src_end)
1327 {
1328 pixel_assigns_t<PixelAccum, dst_pixel_ref_t>()(
1329 std::inner_product(
1330 src_begin,
1331 src_begin + kernel_size,
1332 kernel_begin,
1333 accum_zero,
1334 pixel_plus_t<PixelAccum, PixelAccum, PixelAccum>(),
1335 pixel_multiplies_scalar_t<src_pixel_ref_t, kernel_value_t, PixelAccum>()),
1336 *dst_begin);
1337
1338 ++src_begin;
1339 ++dst_begin;
1340 }
1341 return dst_begin;
1342}
1343
1345template
1346<
1347 std::size_t Size,
1348 typename PixelAccum,
1349 typename SrcIterator,
1350 typename KernelIterator,
1351 typename DstIterator
1352>
1353inline
1354auto correlate_pixels_k(
1355 SrcIterator src_begin,
1356 SrcIterator src_end,
1357 KernelIterator kernel_begin,
1358 DstIterator dst_begin)
1359 -> DstIterator
1360{
1361 using src_pixel_ref_t = typename pixel_proxy
1362 <
1363 typename std::iterator_traits<SrcIterator>::value_type
1364 >::type;
1365 using dst_pixel_ref_t = typename pixel_proxy
1366 <
1367 typename std::iterator_traits<DstIterator>::value_type
1368 >::type;
1369 using kernel_type = typename std::iterator_traits<KernelIterator>::value_type;
1370
1371 PixelAccum accum_zero;
1372 pixel_zeros_t<PixelAccum>()(accum_zero);
1373 while (src_begin != src_end)
1374 {
1375 pixel_assigns_t<PixelAccum, dst_pixel_ref_t>()(
1376 inner_product_k<Size>(
1377 src_begin,
1378 kernel_begin,
1379 accum_zero,
1380 pixel_plus_t<PixelAccum, PixelAccum, PixelAccum>(),
1381 pixel_multiplies_scalar_t<src_pixel_ref_t, kernel_type, PixelAccum>()),
1382 *dst_begin);
1383
1384 ++src_begin;
1385 ++dst_begin;
1386 }
1387 return dst_begin;
1388}
1389
1394template <typename PixelAccum, typename SrcView, typename Scalar, typename DstView>
1395inline
1396void view_multiplies_scalar(SrcView const& src_view, Scalar const& scalar, DstView const& dst_view)
1397{
1398 static_assert(std::is_scalar<Scalar>::value, "Scalar is not scalar");
1399 BOOST_ASSERT(src_view.dimensions() == dst_view.dimensions());
1400 using src_pixel_ref_t = typename pixel_proxy<typename SrcView::value_type>::type;
1401 using dst_pixel_ref_t = typename pixel_proxy<typename DstView::value_type>::type;
1402 using y_coord_t = typename SrcView::y_coord_t;
1403
1404 y_coord_t const height = src_view.height();
1405 for (y_coord_t y = 0; y < height; ++y)
1406 {
1407 typename SrcView::x_iterator it_src = src_view.row_begin(y);
1408 typename DstView::x_iterator it_dst = dst_view.row_begin(y);
1409 typename SrcView::x_iterator it_src_end = src_view.row_end(y);
1410 while (it_src != it_src_end)
1411 {
1412 pixel_assigns_t<PixelAccum, dst_pixel_ref_t>()(
1413 pixel_multiplies_scalar_t<src_pixel_ref_t, Scalar, PixelAccum>()(*it_src, scalar),
1414 *it_dst);
1415
1416 ++it_src;
1417 ++it_dst;
1418 }
1419 }
1420}
1421
1422
1425enum class boundary_option
1426{
1427 output_ignore,
1428 output_zero,
1429 extend_padded,
1430 extend_zero,
1431 extend_constant
1432};
1433
1434namespace detail
1435{
1436
1437template <typename SrcView, typename RltView>
1438void extend_row_impl(
1439 SrcView const& src_view,
1440 RltView result_view,
1441 std::size_t extend_count,
1442 boundary_option option)
1443{
1444 std::ptrdiff_t extend_count_ = static_cast<std::ptrdiff_t>(extend_count);
1445
1446 if (option == boundary_option::extend_constant)
1447 {
1448 for (std::ptrdiff_t i = 0; i < result_view.height(); i++)
1449 {
1450 if(i >= extend_count_ && i < extend_count_ + src_view.height())
1451 {
1452 assign_pixels(
1453 src_view.row_begin(i - extend_count_),
1454 src_view.row_end(i - extend_count_),
1455 result_view.row_begin(i)
1456 );
1457 }
1458 else if(i < extend_count_)
1459 {
1460 assign_pixels(src_view.row_begin(0), src_view.row_end(0), result_view.row_begin(i));
1461 }
1462 else
1463 {
1464 assign_pixels(
1465 src_view.row_begin(src_view.height() - 1),
1466 src_view.row_end(src_view.height() - 1),
1467 result_view.row_begin(i)
1468 );
1469 }
1470
1471 }
1472 }
1473 else if (option == boundary_option::extend_zero)
1474 {
1475 typename SrcView::value_type acc_zero;
1476 pixel_zeros_t<typename SrcView::value_type>()(acc_zero);
1477
1478 for (std::ptrdiff_t i = 0; i < result_view.height(); i++)
1479 {
1480 if (i >= extend_count_ && i < extend_count_ + src_view.height())
1481 {
1482 assign_pixels(
1483 src_view.row_begin(i - extend_count_),
1484 src_view.row_end(i - extend_count_),
1485 result_view.row_begin(i)
1486 );
1487 }
1488 else
1489 {
1490 std::fill_n(result_view.row_begin(i), result_view.width(), acc_zero);
1491 }
1492 }
1493 }
1494 else if (option == boundary_option::extend_padded)
1495 {
1496 auto original_view = subimage_view(
1497 src_view,
1498 0,
1499 -extend_count,
1500 src_view.width(),
1501 src_view.height() + (2 * extend_count)
1502 );
1503 for (std::ptrdiff_t i = 0; i < result_view.height(); i++)
1504 {
1505 assign_pixels(
1506 original_view.row_begin(i),
1507 original_view.row_end(i),
1508 result_view.row_begin(i)
1509 );
1510 }
1511 }
1512 else
1513 {
1514 BOOST_ASSERT_MSG(false, "Invalid boundary option");
1515 }
1516}
1517
1518} //namespace detail
1519
1520
1527template <typename SrcView>
1528auto extend_row(
1529 SrcView const& src_view,
1530 std::size_t extend_count,
1531 boundary_option option
1532) -> typename gil::image<typename SrcView::value_type>
1533{
1534 typename gil::image<typename SrcView::value_type>
1535 result_img(src_view.width(), src_view.height() + (2 * extend_count));
1536
1537 auto result_view = view(result_img);
1538 detail::extend_row_impl(src_view, result_view, extend_count, option);
1539 return result_img;
1540}
1541
1542
1549template <typename SrcView>
1550auto extend_col(
1551 SrcView const& src_view,
1552 std::size_t extend_count,
1553 boundary_option option
1554) -> typename gil::image<typename SrcView::value_type>
1555{
1556 auto src_view_rotate = rotated90cw_view(src_view);
1557
1558 typename gil::image<typename SrcView::value_type>
1559 result_img(src_view.width() + (2 * extend_count), src_view.height());
1560
1561 auto result_view = rotated90cw_view(view(result_img));
1562 detail::extend_row_impl(src_view_rotate, result_view, extend_count, option);
1563 return result_img;
1564}
1565
1572template <typename SrcView>
1573auto extend_boundary(
1574 SrcView const& src_view,
1575 std::size_t extend_count,
1576 boundary_option option
1577) -> typename gil::image<typename SrcView::value_type>
1578{
1579 if (option == boundary_option::extend_padded)
1580 {
1581 typename gil::image<typename SrcView::value_type>
1582 result_img(src_view.width()+(2 * extend_count), src_view.height()+(2 * extend_count));
1583 typename gil::image<typename SrcView::value_type>::view_t result_view = view(result_img);
1584
1585 auto original_view = subimage_view(
1586 src_view,
1587 -extend_count,
1588 -extend_count,
1589 src_view.width() + (2 * extend_count),
1590 src_view.height() + (2 * extend_count)
1591 );
1592
1593 for (std::ptrdiff_t i = 0; i < result_view.height(); i++)
1594 {
1595 assign_pixels(
1596 original_view.row_begin(i),
1597 original_view.row_end(i),
1598 result_view.row_begin(i)
1599 );
1600 }
1601
1602 return result_img;
1603 }
1604
1605 auto auxilary_img = extend_col(src_view, extend_count, option);
1606 return extend_row(view(auxilary_img), extend_count, option);
1607}
1608
1609} } // namespace boost::gil
1610
1611#endif
Provides 1D random-access navigation to the pixels of the image. Models: PixelIteratorConcept,...
Definition iterator_from_2d.hpp:49
auto view(image< Pixel, IsPlanar, Alloc > &img) -> typename image< Pixel, IsPlanar, Alloc >::view_t const &
Returns the non-constant-pixel view of an image.
Definition image.hpp:565
BOOST_FORCEINLINE void copy_pixels(const View1 &src, const View2 &dst)
std::copy for image views
Definition algorithm.hpp:296
void default_construct_pixels(View const &view)
Invokes the in-place default constructor on every pixel of the (uninitialized) view....
Definition algorithm.hpp:728
BOOST_FORCEINLINE void destruct_pixels(View const &view)
Invokes the in-place destructor on every pixel of the view.
Definition algorithm.hpp:522
BOOST_FORCEINLINE bool equal_pixels(const View1 &v1, const View2 &v2)
std::equal for image views
Definition algorithm.hpp:1113
BOOST_FORCEINLINE void fill_pixels(View const &view, Value const &value)
std::fill for image views
Definition algorithm.hpp:424
void generate_pixels(View const &view, F fun)
std::generate for image views
Definition algorithm.hpp:926
BOOST_FORCEINLINE F transform_pixel_positions(const View1 &src, const View2 &dst, F fun)
Like transform_pixels but passes to the function object pixel locators instead of pixel references.
Definition algorithm.hpp:1163
BOOST_FORCEINLINE F transform_pixels(const View1 &src, const View2 &dst, F fun)
std::transform for image views
Definition algorithm.hpp:1131
void uninitialized_copy_pixels(View1 const &view1, View2 const &view2)
std::uninitialized_copy for image views. Does not support planar heterogeneous views....
Definition algorithm.hpp:827
void uninitialized_fill_pixels(const View &view, const Value &val)
std::uninitialized_fill for image views. Does not support planar heterogeneous views....
Definition algorithm.hpp:591
void fill(boost::gil::iterator_from_2d< IL > first, boost::gil::iterator_from_2d< IL > last, const V &val)
std::fill(I,I,V) with I being a iterator_from_2d
Definition algorithm.hpp:373
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)
std::equal(I1,I1,I2) with I1 and I2 being a iterator_from_2d
Definition algorithm.hpp:1091
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 >
std::copy(I1,I1,I2) with I1 and I2 being a iterator_from_2d
Definition algorithm.hpp:285
defined(BOOST_NO_CXX17_HDR_MEMORY_RESOURCE)
Definition algorithm.hpp:36
A generic binary operation on views.
Definition algorithm.hpp:88
Definition algorithm.hpp:191
struct to do std::fill
Definition algorithm.hpp:395
Reference proxy associated with a type that has a "reference" member type alias.
Definition algorithm.hpp:1201
Represents a pixel value (a container of channels). Models: HomogeneousColorBaseValueConcept,...
Definition pixel.hpp:106
An iterator over planar pixels. Models HomogeneousColorBaseConcept, PixelIteratorConcept,...
Definition planar_pixel_iterator.hpp:59
Returns whether two views are compatible.
Definition concepts/image_view.hpp:524