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 { std::copy(src,src+n, dst); }
193};
194
196template <typename IL, typename O> // IL Models ConstPixelLocatorConcept, O Models PixelIteratorConcept
198 using diff_t = typename std::iterator_traits<iterator_from_2d<IL>>::difference_type;
199 BOOST_FORCEINLINE void operator()(iterator_from_2d<IL> src, diff_t n, O dst) const {
200 gil_function_requires<PixelLocatorConcept<IL>>();
201 gil_function_requires<MutablePixelIteratorConcept<O>>();
202 while (n>0) {
203 diff_t l=src.width()-src.x_pos();
204 diff_t numToCopy=(n<l ? n:l);
205 detail::copy_n(src.x(), numToCopy, dst);
206 dst+=numToCopy;
207 src+=numToCopy;
208 n-=numToCopy;
209 }
210 }
211};
212
214template <typename I, typename OL> // I Models ConstPixelIteratorConcept, OL Models PixelLocatorConcept
216 using diff_t = typename std::iterator_traits<I>::difference_type;
217 BOOST_FORCEINLINE void operator()(I src, diff_t n, iterator_from_2d<OL> dst) const {
218 gil_function_requires<PixelIteratorConcept<I>>();
219 gil_function_requires<MutablePixelLocatorConcept<OL>>();
220 while (n>0) {
221 diff_t l=dst.width()-dst.x_pos();
222 diff_t numToCopy=(n<l ? n:l);
223 detail::copy_n(src, numToCopy, dst.x());
224 dst+=numToCopy;
225 src+=numToCopy;
226 n-=numToCopy;
227 }
228 }
229};
230
232template <typename IL, typename OL>
234 using diff_t = typename iterator_from_2d<IL>::difference_type;
235 BOOST_FORCEINLINE void operator()(iterator_from_2d<IL> src, diff_t n, iterator_from_2d<OL> dst) const {
236 gil_function_requires<PixelLocatorConcept<IL>>();
237 gil_function_requires<MutablePixelLocatorConcept<OL>>();
238 if (src.x_pos()!=dst.x_pos() || src.width()!=dst.width()) {
239 while(n-->0) {
240 *dst++=*src++;
241 }
242 }
243 while (n>0) {
244 diff_t l=dst.width()-dst.x_pos();
245 diff_t numToCopy=(n<l ? n : l);
246 detail::copy_n(src.x(), numToCopy, dst.x());
247 dst+=numToCopy;
248 src+=numToCopy;
249 n-=numToCopy;
250 }
251 }
252};
253
254template <typename SrcIterator, typename DstIterator>
255BOOST_FORCEINLINE auto copy_with_2d_iterators(SrcIterator first, SrcIterator last, DstIterator dst) -> DstIterator {
256 using src_x_iterator = typename SrcIterator::x_iterator;
257 using dst_x_iterator = typename DstIterator::x_iterator;
258
259 typename SrcIterator::difference_type n = last - first;
260
261 if (first.is_1d_traversable()) {
262 if (dst.is_1d_traversable())
263 copier_n<src_x_iterator,dst_x_iterator>()(first.x(),n, dst.x());
264 else
265 copier_n<src_x_iterator,DstIterator >()(first.x(),n, dst);
266 } else {
267 if (dst.is_1d_traversable())
268 copier_n<SrcIterator,dst_x_iterator>()(first,n, dst.x());
269 else
270 copier_n<SrcIterator,DstIterator>()(first,n,dst);
271 }
272 return dst+n;
273}
274} // namespace detail
275} } // namespace boost::gil
276
277namespace std {
280template <typename IL, typename OL>
282{
283 return boost::gil::detail::copy_with_2d_iterators(first,last,dst);
284}
285
286} // namespace std
287
288namespace boost { namespace gil {
291template <typename View1, typename View2> BOOST_FORCEINLINE
292void copy_pixels(const View1& src, const View2& dst)
293{
294 BOOST_ASSERT(src.dimensions() == dst.dimensions());
295 detail::copy_with_2d_iterators(src.begin(),src.end(),dst.begin());
296}
297
299// copy_and_convert_pixels
301
307
308namespace detail {
309template <typename CC>
310class copy_and_convert_pixels_fn : public binary_operation_obj<copy_and_convert_pixels_fn<CC>>
311{
312private:
313 CC _cc;
314public:
315 using result_type = typename binary_operation_obj<copy_and_convert_pixels_fn<default_color_converter>>::result_type;
316 copy_and_convert_pixels_fn() {}
317 copy_and_convert_pixels_fn(CC cc_in) : _cc(cc_in) {}
318 // when the two color spaces are incompatible, a color conversion is performed
319 template <typename V1, typename V2> BOOST_FORCEINLINE
320 auto apply_incompatible(const V1& src, const V2& dst) const -> result_type {
321 copy_pixels(color_converted_view<typename V2::value_type>(src,_cc),dst);
322 }
323
324 // If the two color spaces are compatible, copy_and_convert is just copy
325 template <typename V1, typename V2> BOOST_FORCEINLINE
326 auto apply_compatible(const V1& src, const V2& dst) const -> result_type {
327 copy_pixels(src,dst);
328 }
329};
330} // namespace detail
331
333template <typename V1, typename V2,typename CC>
334BOOST_FORCEINLINE
335void copy_and_convert_pixels(const V1& src, const V2& dst,CC cc) {
336 detail::copy_and_convert_pixels_fn<CC> ccp(cc);
337 ccp(src,dst);
338}
339
340struct default_color_converter;
341
343template <typename View1, typename View2>
344BOOST_FORCEINLINE
345void copy_and_convert_pixels(const View1& src, const View2& dst) {
346 detail::copy_and_convert_pixels_fn<default_color_converter> ccp;
347 ccp(src,dst);
348}
349} } // namespace boost::gil
350
352// std::fill and gil::fill_pixels
354
358
359namespace std {
368template <typename IL, typename V>
370 boost::gil::gil_function_requires<boost::gil::MutablePixelLocatorConcept<IL>>();
371 if (first.is_1d_traversable()) {
372 std::fill(first.x(), last.x(), val);
373 } else {
374 // fill row by row
375 std::ptrdiff_t n=last-first;
376 while (n>0) {
377 std::ptrdiff_t numToDo=std::min<const std::ptrdiff_t>(n,(std::ptrdiff_t)(first.width()-first.x_pos()));
378 std::fill_n(first.x(), numToDo, val);
379 first+=numToDo;
380 n-=numToDo;
381 }
382 }
383}
384} // namespace std
385
386namespace boost { namespace gil {
387
388namespace detail {
389
392 template <typename It, typename P>
393 void operator()(It first, It last, const P& p_in) {
394 std::fill(first,last,p_in);
395 }
396};
397
399template <typename It, typename P>
400BOOST_FORCEINLINE
401void fill_aux(It first, It last, P const& p, std::true_type)
402{
403 static_for_each(first, last, p, std_fill_t());
404}
405
407template <typename It, typename P>
408BOOST_FORCEINLINE
409void fill_aux(It first, It last, P const& p, std::false_type)
410{
411 std::fill(first, last, p);
412}
413
414} // namespace detail
415
418template <typename View, typename Value>
419BOOST_FORCEINLINE
420void fill_pixels(View const& view, Value const& value)
421{
422 if (view.is_1d_traversable())
423 {
424 detail::fill_aux(
425 view.begin().x(), view.end().x(), value, is_planar<View>());
426 }
427 else
428 {
429 for (std::ptrdiff_t y = 0; y < view.height(); ++y)
430 detail::fill_aux(
431 view.row_begin(y), view.row_end(y), value, is_planar<View>());
432 }
433}
434
436// destruct_pixels
438
442
443namespace detail {
444template <typename Iterator>
445BOOST_FORCEINLINE
446void destruct_range_impl(Iterator first, Iterator last,
447 typename std::enable_if
448 <
449 mp11::mp_and
450 <
451 std::is_pointer<Iterator>,
452 mp11::mp_not
453 <
454 detail::is_trivially_destructible<typename std::iterator_traits<Iterator>::value_type>
455 >
456 >::value
457 >::type* /*ptr*/ = 0)
458{
459 while (first != last)
460 {
461 first->~value_t();
462 ++first;
463 }
464}
465
466template <typename Iterator>
467BOOST_FORCEINLINE
468void destruct_range_impl(Iterator /*first*/, Iterator /*last*/,
469 typename std::enable_if
470 <
471 mp11::mp_or
472 <
473 mp11::mp_not<std::is_pointer<Iterator>>,
474 detail::is_trivially_destructible<typename std::iterator_traits<Iterator>::value_type>
475 >::value
476 >::type* /* ptr */ = nullptr)
477{
478}
479
480template <typename Iterator>
481BOOST_FORCEINLINE
482void destruct_range(Iterator first, Iterator last)
483{
484 destruct_range_impl(first, last);
485}
486
487struct std_destruct_t
488{
489 template <typename Iterator>
490 void operator()(Iterator first, Iterator last) const
491 {
492 destruct_range(first,last);
493 }
494};
495
497template <typename It>
498BOOST_FORCEINLINE
499void destruct_aux(It first, It last, std::true_type)
500{
501 static_for_each(first,last,std_destruct_t());
502}
503
505template <typename It>
506BOOST_FORCEINLINE
507void destruct_aux(It first, It last, std::false_type)
508{
509 destruct_range(first,last);
510}
511
512} // namespace detail
513
516template <typename View>
517BOOST_FORCEINLINE
518void destruct_pixels(View const& view)
519{
520 if (view.is_1d_traversable())
521 {
522 detail::destruct_aux(
523 view.begin().x(), view.end().x(), is_planar<View>());
524 }
525 else
526 {
527 for (std::ptrdiff_t y = 0; y < view.height(); ++y)
528 detail::destruct_aux(
529 view.row_begin(y), view.row_end(y), is_planar<View>());
530 }
531}
532
534// uninitialized_fill_pixels
536
540
541namespace detail {
542
545template <typename It, typename P>
546BOOST_FORCEINLINE
547void uninitialized_fill_aux(It first, It last, P const& p, std::true_type)
548{
549 std::size_t channel = 0;
550 try
551 {
552 using pixel_t = typename std::iterator_traits<It>::value_type;
553 while (channel < num_channels<pixel_t>::value)
554 {
555 std::uninitialized_fill(
556 dynamic_at_c(first,channel),
557 dynamic_at_c(last,channel),
558 dynamic_at_c(p,channel));
559
560 ++channel;
561 }
562 }
563 catch (...)
564 {
565 for (std::size_t c = 0; c < channel; ++c)
566 destruct_range(dynamic_at_c(first, c), dynamic_at_c(last, c));
567 throw;
568 }
569}
570
573template <typename It, typename P>
574BOOST_FORCEINLINE
575void uninitialized_fill_aux(It first, It last, P const& p, std::false_type)
576{
577 std::uninitialized_fill(first,last,p);
578}
579
580} // namespace detail
581
586template <typename View, typename Value>
587void uninitialized_fill_pixels(const View& view, const Value& val) {
588 if (view.is_1d_traversable())
589 detail::uninitialized_fill_aux(view.begin().x(), view.end().x(),
590 val,is_planar<View>());
591 else {
592 typename View::y_coord_t y = 0;
593 try {
594 for (y=0; y<view.height(); ++y)
595 detail::uninitialized_fill_aux(view.row_begin(y),view.row_end(y),
596 val,is_planar<View>());
597 } catch(...) {
598 for (typename View::y_coord_t y0=0; y0<y; ++y0)
599 detail::destruct_aux(view.row_begin(y0),view.row_end(y0), is_planar<View>());
600 throw;
601 }
602 }
603}
604
606// default_construct_pixels
608
612
613namespace detail {
614template <typename It> BOOST_FORCEINLINE
615void default_construct_range_impl(It first, It last, std::true_type)
616{
617 It first1 = first;
618 try
619 {
620 using value_t = typename std::iterator_traits<It>::value_type;
621 while (first != last)
622 {
623 new (first) value_t();
624 ++first;
625 }
626 }
627 catch (...)
628 {
629 destruct_range(first1, first);
630 throw;
631 }
632}
633
634template <typename It>
635BOOST_FORCEINLINE
636void default_construct_range_impl(It, It, std::false_type) {}
637
638template <typename It>
639BOOST_FORCEINLINE
640void default_construct_range(It first, It last)
641{
642 default_construct_range_impl(first, last, typename std::is_pointer<It>::type());
643}
644
646template <typename It>
647BOOST_FORCEINLINE
648void default_construct_aux(It first, It last, std::true_type)
649{
650 std::size_t channel = 0;
651 try
652 {
653 using pixel_t = typename std::iterator_traits<It>::value_type;
654 while (channel < num_channels<pixel_t>::value)
655 {
656 default_construct_range(dynamic_at_c(first, channel), dynamic_at_c(last, channel));
657 ++channel;
658 }
659 }
660 catch (...)
661 {
662 for (std::size_t c = 0; c < channel; ++c)
663 destruct_range(dynamic_at_c(first, c), dynamic_at_c(last, c));
664 throw;
665 }
666}
667
669template <typename It>
670BOOST_FORCEINLINE
671void default_construct_aux(It first, It last, std::false_type)
672{
673 default_construct_range(first, last);
674}
675
676template <typename View, bool IsPlanar>
677struct has_trivial_pixel_constructor
678 : detail::is_trivially_default_constructible<typename View::value_type>
679{};
680
681template <typename View>
682struct has_trivial_pixel_constructor<View, true>
683 : detail::is_trivially_default_constructible<typename channel_type<View>::type>
684{};
685
686template<typename View, bool IsTriviallyConstructible>
687BOOST_FORCEINLINE
688void default_construct_pixels_impl(
689 View const& view,
690 std::enable_if<!IsTriviallyConstructible>* /*ptr*/ = nullptr)
691{
692 if (view.is_1d_traversable())
693 {
694 detail::default_construct_aux(
695 view.begin().x(), view.end().x(), is_planar<View>());
696 }
697 else
698 {
699 typename View::y_coord_t y = 0;
700 try
701 {
702 for( y = 0; y < view.height(); ++y )
703 detail::default_construct_aux(
704 view.row_begin(y), view.row_end(y), is_planar<View>());
705 }
706 catch(...)
707 {
708 for (typename View::y_coord_t y0 = 0; y0 < y; ++y0 )
709 detail::destruct_aux(
710 view.row_begin(y0), view.row_end(y0), is_planar<View>());
711
712 throw;
713 }
714 }
715}
716
717} // namespace detail
718
723template <typename View>
725{
726 detail::default_construct_pixels_impl
727 <
728 View,
729 detail::has_trivial_pixel_constructor
730 <
731 View,
732 is_planar<View>::value
733 >::value
734 >(view);
735}
736
738// uninitialized_copy_pixels
740
744
745namespace detail {
746
747enum class copy_planarity_condition
748{
749 planar_to_planar,
750 interleaved_to_planar,
751 mixed_to_interleaved
752};
753
754using planar_to_planar_type =
755 std::integral_constant
756 <
757 copy_planarity_condition, copy_planarity_condition::planar_to_planar
758 >;
759using interleaved_to_planar_type =
760 std::integral_constant
761 <
762 copy_planarity_condition, copy_planarity_condition::interleaved_to_planar
763 >;
764using mixed_to_interleaved_type =
765 std::integral_constant
766 <
767 copy_planarity_condition, copy_planarity_condition::mixed_to_interleaved
768 >;
769
771template <typename It1, typename It2>
772BOOST_FORCEINLINE
773void uninitialized_copy_aux(It1 first1, It1 last1, It2 first2, It2 last2, planar_to_planar_type)
774{
775 std::size_t channel=0;
776 try {
777 using pixel_t = typename std::iterator_traits<It1>::value_type;
778 while (channel < num_channels<pixel_t>::value)
779 {
780 std::uninitialized_copy(
781 dynamic_at_c(first1, channel),
782 dynamic_at_c(last1, channel),
783 dynamic_at_c(first2, channel));
784 ++channel;
785 }
786 }
787 catch (...)
788 {
789 It2 last2 = first2;
790 std::advance(last2, std::distance(first1, last1));
791 for (std::size_t c = 0; c < channel; ++c)
792 destruct_range(dynamic_at_c(first2, c), dynamic_at_c(last2, c));
793 throw;
794 }
795}
796
798template <typename It1, typename It2>
799BOOST_FORCEINLINE
800void uninitialized_copy_aux(It1 first1, It1 last1, It2 first2, It2, mixed_to_interleaved_type)
801{
802 std::uninitialized_copy(first1, last1, first2);
803}
804
806template <typename It1, typename It2>
807BOOST_FORCEINLINE
808void uninitialized_copy_aux(It1 first1, It1, It2 first2, It2 last2,
809interleaved_to_planar_type)
810{
811 default_construct_aux(first2, last2, std::true_type());
812
813 typename It2::difference_type n = last2 - first2;
814 copier_n<It1,It2>()(first1, n, first2);
815}
816} // namespace detail
817
822template <typename View1, typename View2>
823void uninitialized_copy_pixels(View1 const& view1, View2 const& view2)
824{
825 using copy_planarity_condition = detail::copy_planarity_condition;
826 using copy_planarity_condition_type =
827 std::integral_constant
828 <
829 copy_planarity_condition,
830 !is_planar<View2>::value
831 ? copy_planarity_condition::mixed_to_interleaved
832 : (is_planar<View1>::value
833 ? copy_planarity_condition::planar_to_planar
834 : copy_planarity_condition::interleaved_to_planar)
835 >;
836 BOOST_ASSERT(view1.dimensions() == view2.dimensions());
837
838 if (view1.is_1d_traversable() && view2.is_1d_traversable())
839 {
840 detail::uninitialized_copy_aux(
841 view1.begin().x(), view1.end().x(), view2.begin().x(), view2.end().x(),
842 copy_planarity_condition_type());
843 }
844 else
845 {
846 typename View1::y_coord_t y = 0;
847 try
848 {
849 for (y = 0; y < view1.height(); ++y)
850 detail::uninitialized_copy_aux(
851 view1.row_begin(y), view1.row_end(y), view2.row_begin(y), view2.row_end(y),
852 copy_planarity_condition_type());
853 }
854 catch(...)
855 {
856 for (typename View1::y_coord_t y0 = 0; y0 < y; ++y0)
857 detail::destruct_aux(view2.row_begin(y0), view2.row_end(y0), is_planar<View2>());
858 throw;
859 }
860 }
861}
862
864// for_each_pixel
866
875
877template <typename View, typename F>
878F for_each_pixel(View const& view, F fun)
879{
880 if (view.is_1d_traversable())
881 {
882 return std::for_each(view.begin().x(), view.end().x(), fun);
883 }
884 else
885 {
886 for (std::ptrdiff_t y = 0; y < view.height(); ++y)
887 for (auto begin = view.row_begin(y), end = view.row_end(y); begin != end; ++begin)
888 fun(*begin);
889 return fun;
890 }
891}
892
896
898template <typename View, typename F>
899F for_each_pixel_position(View const& view, F fun)
900{
901 typename View::xy_locator loc = view.xy_at(0, 0);
902 for (std::ptrdiff_t y = 0; y < view.height(); ++y)
903 {
904 for (std::ptrdiff_t x = 0; x < view.width(); ++x, ++loc.x())
905 fun(loc);
906 loc.x() -= view.width(); ++loc.y();
907 }
908 return fun;
909}
910
912// generate_pixels
914
918
921template <typename View, typename F>
922void generate_pixels(View const& view, F fun)
923{
924 if (view.is_1d_traversable())
925 {
926 std::generate(view.begin().x(), view.end().x(), fun);
927 }
928 else
929 {
930 for (std::ptrdiff_t y = 0; y < view.height(); ++y)
931 std::generate(view.row_begin(y), view.row_end(y), fun);
932 }
933}
934
936// std::equal and gil::equal_pixels for GIL constructs
938
942
943template <typename I1, typename I2>
944BOOST_FORCEINLINE
945bool equal_n(I1 i1, std::ptrdiff_t n, I2 i2);
946
947namespace detail {
948
949template <typename I1, typename I2>
950struct equal_n_fn
951{
952 BOOST_FORCEINLINE
953 bool operator()(I1 i1, std::ptrdiff_t n, I2 i2) const
954 {
955 return std::equal(i1, i1 + n, i2);
956 }
957};
958
961template<typename T, typename CS>
962struct equal_n_fn<pixel<T, CS> const*, pixel<T, CS> const*>
963{
964 BOOST_FORCEINLINE
965 bool operator()(pixel<T, CS> const* i1, std::ptrdiff_t n, pixel<T, CS> const* i2) const
966 {
967 return memcmp(i1, i2, n * sizeof(pixel<T, CS>)) == 0;
968 }
969};
970
971template<typename T, typename CS>
972struct equal_n_fn<pixel<T, CS>*, pixel<T, CS>*>
973 : equal_n_fn<pixel<T, CS> const*, pixel<T, CS> const*>
974{};
975
979template<typename IC, typename CS>
980struct equal_n_fn<planar_pixel_iterator<IC, CS>, planar_pixel_iterator<IC, CS>>
981{
982 BOOST_FORCEINLINE
983 bool operator()(planar_pixel_iterator<IC, CS> const i1, std::ptrdiff_t n, planar_pixel_iterator<IC, CS> const i2) const
984 {
985 // FIXME: ptrdiff_t vs size_t
986 constexpr std::ptrdiff_t byte_size = n * sizeof(typename std::iterator_traits<IC>::value_type);
987 for (std::ptrdiff_t i = 0; i < mp11::mp_size<CS>::value; ++i)
988 {
989 if (memcmp(dynamic_at_c(i1, i), dynamic_at_c(i2, i), byte_size) != 0)
990 return false;
991 }
992 return true;
993 }
994};
995
999template <typename Loc, typename It>
1000struct equal_n_fn<boost::gil::iterator_from_2d<Loc>, It>
1001{
1002 BOOST_FORCEINLINE
1003 bool operator()(boost::gil::iterator_from_2d<Loc> i1, std::ptrdiff_t n, It i2) const
1004 {
1005 gil_function_requires<boost::gil::PixelLocatorConcept<Loc>>();
1006 gil_function_requires<boost::gil::PixelIteratorConcept<It>>();
1007 while (n > 0)
1008 {
1009 std::ptrdiff_t const num = std::min<std::ptrdiff_t>(n, i1.width() - i1.x_pos());
1010 if (!equal_n(i1.x(), num, i2))
1011 return false;
1012 i1 += num;
1013 i2 += num;
1014 n -= num;
1015 }
1016 return true;
1017 }
1018};
1019
1023template <typename It, typename Loc>
1024struct equal_n_fn<It, boost::gil::iterator_from_2d<Loc>>
1025{
1026 BOOST_FORCEINLINE
1027 bool operator()(It i1, std::ptrdiff_t n, boost::gil::iterator_from_2d<Loc> i2) const
1028 {
1029 gil_function_requires<boost::gil::PixelIteratorConcept<It>>();
1030 gil_function_requires<boost::gil::PixelLocatorConcept<Loc>>();
1031 while (n > 0)
1032 {
1033 std::ptrdiff_t const num = std::min<std::ptrdiff_t>(n, i2.width() - i2.x_pos());
1034 if (!equal_n(i1, num, i2.x()))
1035 return false;
1036 i1 += num;
1037 i2 += num;
1038 n -= num;
1039 }
1040 return true;
1041 }
1042};
1043
1045template <typename Loc1, typename Loc2>
1047 BOOST_FORCEINLINE bool operator()(boost::gil::iterator_from_2d<Loc1> i1, std::ptrdiff_t n, boost::gil::iterator_from_2d<Loc2> i2) const {
1048 gil_function_requires<boost::gil::PixelLocatorConcept<Loc1>>();
1049 gil_function_requires<boost::gil::PixelLocatorConcept<Loc2>>();
1050 if (i1.x_pos()!=i2.x_pos() || i1.width()!=i2.width()) {
1051 while(n-->0) {
1052 if (*i1++!=*i2++) return false;
1053 }
1054 }
1055 while (n>0) {
1056 std::ptrdiff_t num=std::min<const std::ptrdiff_t>(n,i2.width()-i2.x_pos());
1057 if (!equal_n(i1.x(), num, i2.x()))
1058 return false;
1059 i1+=num;
1060 i2+=num;
1061 n-=num;
1062 }
1063 return true;
1064 }
1065};
1066} // namespace detail
1067
1068template <typename I1, typename I2> BOOST_FORCEINLINE
1069bool equal_n(I1 i1, std::ptrdiff_t n, I2 i2) {
1070 return detail::equal_n_fn<I1,I2>()(i1,n,i2);
1071}
1072} } // namespace boost::gil
1073
1074namespace std {
1086template <typename Loc1, typename Loc2> BOOST_FORCEINLINE
1088 boost::gil::gil_function_requires<boost::gil::PixelLocatorConcept<Loc1>>();
1089 boost::gil::gil_function_requires<boost::gil::PixelLocatorConcept<Loc2>>();
1090 std::ptrdiff_t n=last-first;
1091 if (first.is_1d_traversable()) {
1092 if (first2.is_1d_traversable())
1093 return boost::gil::detail::equal_n_fn<typename Loc1::x_iterator,typename Loc2::x_iterator>()(first.x(),n, first2.x());
1094 else
1095 return boost::gil::detail::equal_n_fn<typename Loc1::x_iterator,boost::gil::iterator_from_2d<Loc2>>()(first.x(),n, first2);
1096 } else {
1097 if (first2.is_1d_traversable())
1098 return boost::gil::detail::equal_n_fn<boost::gil::iterator_from_2d<Loc1>,typename Loc2::x_iterator>()(first,n, first2.x());
1099 else
1100 return boost::gil::detail::equal_n_fn<boost::gil::iterator_from_2d<Loc1>,boost::gil::iterator_from_2d<Loc2>>()(first,n,first2);
1101 }
1102}
1103} // namespace std
1104
1105namespace boost { namespace gil {
1108template <typename View1, typename View2> BOOST_FORCEINLINE
1109bool equal_pixels(const View1& v1, const View2& v2) {
1110 BOOST_ASSERT(v1.dimensions() == v2.dimensions());
1111 return std::equal(v1.begin(),v1.end(),v2.begin()); // std::equal has overloads with GIL iterators for optimal performance
1112}
1113
1119
1123
1126template <typename View1, typename View2, typename F> BOOST_FORCEINLINE
1127F transform_pixels(const View1& src,const View2& dst, F fun) {
1128 BOOST_ASSERT(src.dimensions() == dst.dimensions());
1129 for (std::ptrdiff_t y=0; y<src.height(); ++y) {
1130 typename View1::x_iterator srcIt=src.row_begin(y);
1131 typename View2::x_iterator dstIt=dst.row_begin(y);
1132 for (std::ptrdiff_t x=0; x<src.width(); ++x)
1133 dstIt[x]=fun(srcIt[x]);
1134 }
1135 return fun;
1136}
1137
1140template <typename View1, typename View2, typename View3, typename F> BOOST_FORCEINLINE
1141F transform_pixels(const View1& src1, const View2& src2,const View3& dst, F fun) {
1142 for (std::ptrdiff_t y=0; y<dst.height(); ++y) {
1143 typename View1::x_iterator srcIt1=src1.row_begin(y);
1144 typename View2::x_iterator srcIt2=src2.row_begin(y);
1145 typename View3::x_iterator dstIt=dst.row_begin(y);
1146 for (std::ptrdiff_t x=0; x<dst.width(); ++x)
1147 dstIt[x]=fun(srcIt1[x],srcIt2[x]);
1148 }
1149 return fun;
1150}
1151
1155
1158template <typename View1, typename View2, typename F> BOOST_FORCEINLINE
1159F transform_pixel_positions(const View1& src,const View2& dst, F fun) {
1160 BOOST_ASSERT(src.dimensions() == dst.dimensions());
1161 typename View1::xy_locator loc=src.xy_at(0,0);
1162 for (std::ptrdiff_t y=0; y<src.height(); ++y) {
1163 typename View2::x_iterator dstIt=dst.row_begin(y);
1164 for (std::ptrdiff_t x=0; x<src.width(); ++x, ++loc.x())
1165 dstIt[x]=fun(loc);
1166 loc.x()-=src.width(); ++loc.y();
1167 }
1168 return fun;
1169}
1170
1173template <typename View1, typename View2, typename View3, typename F> BOOST_FORCEINLINE
1174F transform_pixel_positions(const View1& src1,const View2& src2,const View3& dst, F fun) {
1175 BOOST_ASSERT(src1.dimensions() == dst.dimensions());
1176 BOOST_ASSERT(src2.dimensions() == dst.dimensions());
1177 typename View1::xy_locator loc1=src1.xy_at(0,0);
1178 typename View2::xy_locator loc2=src2.xy_at(0,0);
1179 for (std::ptrdiff_t y=0; y<src1.height(); ++y) {
1180 typename View3::x_iterator dstIt=dst.row_begin(y);
1181 for (std::ptrdiff_t x=0; x<src1.width(); ++x, ++loc1.x(), ++loc2.x())
1182 dstIt[x]=fun(loc1,loc2);
1183 loc1.x()-=src1.width(); ++loc1.y();
1184 loc2.x()-=src2.width(); ++loc2.y();
1185 }
1186 return fun;
1187}
1188
1189
1190// Code below this line is moved here from <boost/gil/extension/numeric/algorithm.hpp>
1191
1196template <typename T>
1197struct pixel_proxy : std::remove_reference<typename T::reference> {};
1198
1200template <typename Iterator1, typename Iterator2, typename BinaryFunction>
1201BinaryFunction for_each(Iterator1 first1, Iterator1 last1, Iterator2 first2, BinaryFunction f)
1202{
1203 while (first1 != last1)
1204 f(*first1++, *first2++);
1205 return f;
1206}
1207
1208template <typename SrcIterator, typename DstIterator>
1209inline
1210auto assign_pixels(SrcIterator src, SrcIterator src_end, DstIterator dst) -> DstIterator
1211{
1212 for_each(src, src_end, dst,
1213 pixel_assigns_t
1214 <
1215 typename pixel_proxy<typename std::iterator_traits<SrcIterator>::value_type>::type,
1216 typename pixel_proxy<typename std::iterator_traits<DstIterator>::value_type>::type
1217 >());
1218 return dst + (src_end - src);
1219}
1220
1221namespace detail {
1222
1223template <std::size_t Size>
1224struct inner_product_k_t
1225{
1226 template
1227 <
1228 class InputIterator1,
1229 class InputIterator2,
1230 class T,
1231 class BinaryOperation1,
1232 class BinaryOperation2
1233 >
1234 static T apply(
1235 InputIterator1 first1,
1236 InputIterator2 first2, T init,
1237 BinaryOperation1 binary_op1,
1238 BinaryOperation2 binary_op2)
1239 {
1240 init = binary_op1(init, binary_op2(*first1, *first2));
1241 return inner_product_k_t<Size - 1>::template apply(
1242 first1 + 1, first2 + 1, init, binary_op1, binary_op2);
1243 }
1244};
1245
1246template <>
1247struct inner_product_k_t<0>
1248{
1249 template
1250 <
1251 class InputIterator1,
1252 class InputIterator2,
1253 class T,
1254 class BinaryOperation1,
1255 class BinaryOperation2
1256 >
1257 static T apply(
1258 InputIterator1 first1,
1259 InputIterator2 first2,
1260 T init,
1261 BinaryOperation1 binary_op1,
1262 BinaryOperation2 binary_op2)
1263 {
1264 return init;
1265 }
1266};
1267
1268} // namespace detail
1269
1271template
1272<
1273 std::size_t Size,
1274 class InputIterator1,
1275 class InputIterator2,
1276 class T,
1277 class BinaryOperation1,
1278 class BinaryOperation2
1279>
1280BOOST_FORCEINLINE
1281T inner_product_k(
1282 InputIterator1 first1,
1283 InputIterator2 first2,
1284 T init,
1285 BinaryOperation1 binary_op1,
1286 BinaryOperation2 binary_op2)
1287{
1288 return detail::inner_product_k_t<Size>::template apply(
1289 first1, first2, init, binary_op1, binary_op2);
1290}
1291
1293template
1294<
1295 typename PixelAccum,
1296 typename SrcIterator,
1297 typename KernelIterator,
1298 typename Size,
1299 typename DstIterator
1300>
1301inline
1302auto correlate_pixels_n(
1303 SrcIterator src_begin,
1304 SrcIterator src_end,
1305 KernelIterator kernel_begin,
1306 Size kernel_size,
1307 DstIterator dst_begin)
1308 -> DstIterator
1309{
1310 using src_pixel_ref_t = typename pixel_proxy
1311 <
1312 typename std::iterator_traits<SrcIterator>::value_type
1313 >::type;
1314 using dst_pixel_ref_t = typename pixel_proxy
1315 <
1316 typename std::iterator_traits<DstIterator>::value_type
1317 >::type;
1318 using kernel_value_t = typename std::iterator_traits<KernelIterator>::value_type;
1319
1320 PixelAccum accum_zero;
1321 pixel_zeros_t<PixelAccum>()(accum_zero);
1322 while (src_begin != src_end)
1323 {
1324 pixel_assigns_t<PixelAccum, dst_pixel_ref_t>()(
1325 std::inner_product(
1326 src_begin,
1327 src_begin + kernel_size,
1328 kernel_begin,
1329 accum_zero,
1330 pixel_plus_t<PixelAccum, PixelAccum, PixelAccum>(),
1331 pixel_multiplies_scalar_t<src_pixel_ref_t, kernel_value_t, PixelAccum>()),
1332 *dst_begin);
1333
1334 ++src_begin;
1335 ++dst_begin;
1336 }
1337 return dst_begin;
1338}
1339
1341template
1342<
1343 std::size_t Size,
1344 typename PixelAccum,
1345 typename SrcIterator,
1346 typename KernelIterator,
1347 typename DstIterator
1348>
1349inline
1350auto correlate_pixels_k(
1351 SrcIterator src_begin,
1352 SrcIterator src_end,
1353 KernelIterator kernel_begin,
1354 DstIterator dst_begin)
1355 -> DstIterator
1356{
1357 using src_pixel_ref_t = typename pixel_proxy
1358 <
1359 typename std::iterator_traits<SrcIterator>::value_type
1360 >::type;
1361 using dst_pixel_ref_t = typename pixel_proxy
1362 <
1363 typename std::iterator_traits<DstIterator>::value_type
1364 >::type;
1365 using kernel_type = typename std::iterator_traits<KernelIterator>::value_type;
1366
1367 PixelAccum accum_zero;
1368 pixel_zeros_t<PixelAccum>()(accum_zero);
1369 while (src_begin != src_end)
1370 {
1371 pixel_assigns_t<PixelAccum, dst_pixel_ref_t>()(
1372 inner_product_k<Size>(
1373 src_begin,
1374 kernel_begin,
1375 accum_zero,
1376 pixel_plus_t<PixelAccum, PixelAccum, PixelAccum>(),
1377 pixel_multiplies_scalar_t<src_pixel_ref_t, kernel_type, PixelAccum>()),
1378 *dst_begin);
1379
1380 ++src_begin;
1381 ++dst_begin;
1382 }
1383 return dst_begin;
1384}
1385
1390template <typename PixelAccum, typename SrcView, typename Scalar, typename DstView>
1391inline
1392void view_multiplies_scalar(SrcView const& src_view, Scalar const& scalar, DstView const& dst_view)
1393{
1394 static_assert(std::is_scalar<Scalar>::value, "Scalar is not scalar");
1395 BOOST_ASSERT(src_view.dimensions() == dst_view.dimensions());
1396 using src_pixel_ref_t = typename pixel_proxy<typename SrcView::value_type>::type;
1397 using dst_pixel_ref_t = typename pixel_proxy<typename DstView::value_type>::type;
1398 using y_coord_t = typename SrcView::y_coord_t;
1399
1400 y_coord_t const height = src_view.height();
1401 for (y_coord_t y = 0; y < height; ++y)
1402 {
1403 typename SrcView::x_iterator it_src = src_view.row_begin(y);
1404 typename DstView::x_iterator it_dst = dst_view.row_begin(y);
1405 typename SrcView::x_iterator it_src_end = src_view.row_end(y);
1406 while (it_src != it_src_end)
1407 {
1408 pixel_assigns_t<PixelAccum, dst_pixel_ref_t>()(
1409 pixel_multiplies_scalar_t<src_pixel_ref_t, Scalar, PixelAccum>()(*it_src, scalar),
1410 *it_dst);
1411
1412 ++it_src;
1413 ++it_dst;
1414 }
1415 }
1416}
1417
1418
1421enum class boundary_option
1422{
1423 output_ignore,
1424 output_zero,
1425 extend_padded,
1426 extend_zero,
1427 extend_constant
1428};
1429
1430namespace detail
1431{
1432
1433template <typename SrcView, typename RltView>
1434void extend_row_impl(
1435 SrcView const& src_view,
1436 RltView result_view,
1437 std::size_t extend_count,
1438 boundary_option option)
1439{
1440 std::ptrdiff_t extend_count_ = static_cast<std::ptrdiff_t>(extend_count);
1441
1442 if (option == boundary_option::extend_constant)
1443 {
1444 for (std::ptrdiff_t i = 0; i < result_view.height(); i++)
1445 {
1446 if(i >= extend_count_ && i < extend_count_ + src_view.height())
1447 {
1448 assign_pixels(
1449 src_view.row_begin(i - extend_count_),
1450 src_view.row_end(i - extend_count_),
1451 result_view.row_begin(i)
1452 );
1453 }
1454 else if(i < extend_count_)
1455 {
1456 assign_pixels(src_view.row_begin(0), src_view.row_end(0), result_view.row_begin(i));
1457 }
1458 else
1459 {
1460 assign_pixels(
1461 src_view.row_begin(src_view.height() - 1),
1462 src_view.row_end(src_view.height() - 1),
1463 result_view.row_begin(i)
1464 );
1465 }
1466
1467 }
1468 }
1469 else if (option == boundary_option::extend_zero)
1470 {
1471 typename SrcView::value_type acc_zero;
1472 pixel_zeros_t<typename SrcView::value_type>()(acc_zero);
1473
1474 for (std::ptrdiff_t i = 0; i < result_view.height(); i++)
1475 {
1476 if (i >= extend_count_ && i < extend_count_ + src_view.height())
1477 {
1478 assign_pixels(
1479 src_view.row_begin(i - extend_count_),
1480 src_view.row_end(i - extend_count_),
1481 result_view.row_begin(i)
1482 );
1483 }
1484 else
1485 {
1486 std::fill_n(result_view.row_begin(i), result_view.width(), acc_zero);
1487 }
1488 }
1489 }
1490 else if (option == boundary_option::extend_padded)
1491 {
1492 auto original_view = subimage_view(
1493 src_view,
1494 0,
1495 -extend_count,
1496 src_view.width(),
1497 src_view.height() + (2 * extend_count)
1498 );
1499 for (std::ptrdiff_t i = 0; i < result_view.height(); i++)
1500 {
1501 assign_pixels(
1502 original_view.row_begin(i),
1503 original_view.row_end(i),
1504 result_view.row_begin(i)
1505 );
1506 }
1507 }
1508 else
1509 {
1510 BOOST_ASSERT_MSG(false, "Invalid boundary option");
1511 }
1512}
1513
1514} //namespace detail
1515
1516
1523template <typename SrcView>
1524auto extend_row(
1525 SrcView const& src_view,
1526 std::size_t extend_count,
1527 boundary_option option
1528) -> typename gil::image<typename SrcView::value_type>
1529{
1530 typename gil::image<typename SrcView::value_type>
1531 result_img(src_view.width(), src_view.height() + (2 * extend_count));
1532
1533 auto result_view = view(result_img);
1534 detail::extend_row_impl(src_view, result_view, extend_count, option);
1535 return result_img;
1536}
1537
1538
1545template <typename SrcView>
1546auto extend_col(
1547 SrcView const& src_view,
1548 std::size_t extend_count,
1549 boundary_option option
1550) -> typename gil::image<typename SrcView::value_type>
1551{
1552 auto src_view_rotate = rotated90cw_view(src_view);
1553
1554 typename gil::image<typename SrcView::value_type>
1555 result_img(src_view.width() + (2 * extend_count), src_view.height());
1556
1557 auto result_view = rotated90cw_view(view(result_img));
1558 detail::extend_row_impl(src_view_rotate, result_view, extend_count, option);
1559 return result_img;
1560}
1561
1568template <typename SrcView>
1569auto extend_boundary(
1570 SrcView const& src_view,
1571 std::size_t extend_count,
1572 boundary_option option
1573) -> typename gil::image<typename SrcView::value_type>
1574{
1575 if (option == boundary_option::extend_padded)
1576 {
1577 typename gil::image<typename SrcView::value_type>
1578 result_img(src_view.width()+(2 * extend_count), src_view.height()+(2 * extend_count));
1579 typename gil::image<typename SrcView::value_type>::view_t result_view = view(result_img);
1580
1581 auto original_view = subimage_view(
1582 src_view,
1583 -extend_count,
1584 -extend_count,
1585 src_view.width() + (2 * extend_count),
1586 src_view.height() + (2 * extend_count)
1587 );
1588
1589 for (std::ptrdiff_t i = 0; i < result_view.height(); i++)
1590 {
1591 assign_pixels(
1592 original_view.row_begin(i),
1593 original_view.row_end(i),
1594 result_view.row_begin(i)
1595 );
1596 }
1597
1598 return result_img;
1599 }
1600
1601 auto auxilary_img = extend_col(src_view, extend_count, option);
1602 return extend_row(view(auxilary_img), extend_count, option);
1603}
1604
1605} } // namespace boost::gil
1606
1607#endif
Provides 1D random-access navigation to the pixels of the image. Models: PixelIteratorConcept,...
Definition iterator_from_2d.hpp:46
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:292
void default_construct_pixels(View const &view)
Invokes the in-place default constructor on every pixel of the (uninitialized) view....
Definition algorithm.hpp:724
BOOST_FORCEINLINE void destruct_pixels(View const &view)
Invokes the in-place destructor on every pixel of the view.
Definition algorithm.hpp:518
BOOST_FORCEINLINE bool equal_pixels(const View1 &v1, const View2 &v2)
std::equal for image views
Definition algorithm.hpp:1109
BOOST_FORCEINLINE void fill_pixels(View const &view, Value const &value)
std::fill for image views
Definition algorithm.hpp:420
void generate_pixels(View const &view, F fun)
std::generate for image views
Definition algorithm.hpp:922
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:1159
BOOST_FORCEINLINE F transform_pixels(const View1 &src, const View2 &dst, F fun)
std::transform for image views
Definition algorithm.hpp:1127
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:823
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:587
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:369
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:1087
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:281
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:391
Reference proxy associated with a type that has a "reference" member type alias.
Definition algorithm.hpp:1197
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:58
Returns whether two views are compatible.
Definition concepts/image_view.hpp:524