2 // Copyright 2005-2007 Adobe Systems Incorporated
3 // Copyright 2019 Mateusz Loskot <mateusz at loskot dot net>
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
9 #ifndef BOOST_GIL_COLOR_BASE_ALGORITHM_HPP
10 #define BOOST_GIL_COLOR_BASE_ALGORITHM_HPP
12 #include <boost/gil/concepts.hpp>
13 #include <boost/gil/utilities.hpp>
14 #include <boost/gil/detail/mp11.hpp>
16 #include <boost/config.hpp>
19 #include <type_traits>
21 namespace boost { namespace gil {
23 ///////////////////////////////////////
24 /// size: Semantic channel size
25 ///////////////////////////////////////
28 \defgroup ColorBaseAlgorithmSize size
29 \ingroup ColorBaseAlgorithm
30 \brief Returns an integral constant type specifying the number of elements in a color base
34 static_assert(size<rgb8_pixel_t>::value == 3, "");
35 static_assert(size<cmyk8_planar_ptr_t>::value == 4, "");
39 /// \brief Returns an integral constant type specifying the number of elements in a color base
40 /// \ingroup ColorBaseAlgorithmSize
41 template <typename ColorBase>
42 struct size : public mp11::mp_size<typename ColorBase::layout_t::color_space_t> {};
44 ///////////////////////////////////////
45 /// semantic_at_c: Semantic channel accessors
46 ///////////////////////////////////////
49 \defgroup ColorBaseAlgorithmSemanticAtC kth_semantic_element_type, kth_semantic_element_reference_type, kth_semantic_element_const_reference_type, semantic_at_c
50 \ingroup ColorBaseAlgorithm
51 \brief Support for accessing the elements of a color base by semantic index
53 The semantic index of an element is the index of its color in the color space. Semantic indexing allows for proper pairing of elements of color bases
54 independent on their layout. For example, red is the first semantic element of a color base regardless of whether it has an RGB layout or a BGR layout.
55 All GIL color base algorithms taking multiple color bases use semantic indexing to access their elements.
59 // 16-bit BGR pixel, 4 bits for the blue, 3 bits for the green, 2 bits for the red channel and 7 unused bits
60 using bgr432_pixel_t = packed_pixel_type<uint16_t, mp11::mp_list_c<unsigned,4,3,2>, bgr_layout_t>::type;
62 // A reference to its red channel. Although the red channel is the third, its semantic index is 0 in the RGB color space
63 using red_channel_reference_t = kth_semantic_element_reference_type<bgr432_pixel_t, 0>::type;
65 // Initialize the pixel to black
66 bgr432_pixel_t red_pixel(0,0,0);
68 // Set the red channel to 100%
69 red_channel_reference_t red_channel = semantic_at_c<0>(red_pixel);
70 red_channel = channel_traits<red_channel_reference_t>::max_value();
74 /// \brief Specifies the type of the K-th semantic element of a color base
75 /// \ingroup ColorBaseAlgorithmSemanticAtC
76 template <typename ColorBase, int K>
77 struct kth_semantic_element_type
79 using channel_mapping_t = typename ColorBase::layout_t::channel_mapping_t;
80 static_assert(K < mp11::mp_size<channel_mapping_t>::value,
81 "K index should be less than size of channel_mapping_t sequence");
83 static constexpr int semantic_index = mp11::mp_at_c<channel_mapping_t, K>::type::value;
84 using type = typename kth_element_type<ColorBase, semantic_index>::type;
87 /// \brief Specifies the return type of the mutable semantic_at_c<K>(color_base);
88 /// \ingroup ColorBaseAlgorithmSemanticAtC
89 template <typename ColorBase, int K>
90 struct kth_semantic_element_reference_type
92 using channel_mapping_t = typename ColorBase::layout_t::channel_mapping_t;
93 static_assert(K < mp11::mp_size<channel_mapping_t>::value,
94 "K index should be less than size of channel_mapping_t sequence");
96 static constexpr int semantic_index = mp11::mp_at_c<channel_mapping_t, K>::type::value;
97 using type = typename kth_element_reference_type<ColorBase, semantic_index>::type;
98 static type get(ColorBase& cb) { return gil::at_c<semantic_index>(cb); }
101 /// \brief Specifies the return type of the constant semantic_at_c<K>(color_base);
102 /// \ingroup ColorBaseAlgorithmSemanticAtC
103 template <typename ColorBase, int K>
104 struct kth_semantic_element_const_reference_type
106 using channel_mapping_t = typename ColorBase::layout_t::channel_mapping_t;
107 static_assert(K < mp11::mp_size<channel_mapping_t>::value,
108 "K index should be less than size of channel_mapping_t sequence");
110 static constexpr int semantic_index = mp11::mp_at_c<channel_mapping_t, K>::type::value;
111 using type = typename kth_element_const_reference_type<ColorBase,semantic_index>::type;
112 static type get(const ColorBase& cb) { return gil::at_c<semantic_index>(cb); }
115 /// \brief A mutable accessor to the K-th semantic element of a color base
116 /// \ingroup ColorBaseAlgorithmSemanticAtC
117 template <int K, typename ColorBase>
119 auto semantic_at_c(ColorBase& p)
120 -> typename std::enable_if
122 !std::is_const<ColorBase>::value,
123 typename kth_semantic_element_reference_type<ColorBase, K>::type
126 return kth_semantic_element_reference_type<ColorBase, K>::get(p);
129 /// \brief A constant accessor to the K-th semantic element of a color base
130 /// \ingroup ColorBaseAlgorithmSemanticAtC
131 template <int K, typename ColorBase>
133 auto semantic_at_c(ColorBase const& p)
134 -> typename kth_semantic_element_const_reference_type<ColorBase, K>::type
136 return kth_semantic_element_const_reference_type<ColorBase, K>::get(p);
139 ///////////////////////////////////////
140 /// get_color: Named channel accessors
141 ///////////////////////////////////////
144 \defgroup ColorBaseAlgorithmColor color_element_type, color_element_reference_type, color_element_const_reference_type, get_color, contains_color
145 \ingroup ColorBaseAlgorithm
146 \brief Support for accessing the elements of a color base by color name
148 Example: A function that takes a generic pixel containing a red channel and sets it to 100%:
151 template <typename Pixel>
152 void set_red_to_max(Pixel& pixel) {
153 boost::function_requires<MutablePixelConcept<Pixel> >();
154 static_assert(contains_color<Pixel, red_t>::value, "");
156 using red_channel_t = typename color_element_type<Pixel, red_t>::type;
157 get_color(pixel, red_t()) = channel_traits<red_channel_t>::max_value();
162 /// \brief A predicate metafunction determining whether a given color base contains a given color
163 /// \ingroup ColorBaseAlgorithmColor
164 template <typename ColorBase, typename Color>
165 struct contains_color
166 : mp11::mp_contains<typename ColorBase::layout_t::color_space_t, Color>
169 template <typename ColorBase, typename Color>
170 struct color_index_type : public detail::type_to_index<typename ColorBase::layout_t::color_space_t,Color> {};
172 /// \brief Specifies the type of the element associated with a given color tag
173 /// \ingroup ColorBaseAlgorithmColor
174 template <typename ColorBase, typename Color>
175 struct color_element_type : public kth_semantic_element_type<ColorBase,color_index_type<ColorBase,Color>::value> {};
177 /// \brief Specifies the return type of the mutable element accessor by color name, get_color(color_base, Color());
178 /// \ingroup ColorBaseAlgorithmColor
179 template <typename ColorBase, typename Color>
180 struct color_element_reference_type : public kth_semantic_element_reference_type<ColorBase,color_index_type<ColorBase,Color>::value> {};
182 /// \brief Specifies the return type of the constant element accessor by color name, get_color(color_base, Color());
183 /// \ingroup ColorBaseAlgorithmColor
184 template <typename ColorBase, typename Color>
185 struct color_element_const_reference_type : public kth_semantic_element_const_reference_type<ColorBase,color_index_type<ColorBase,Color>::value> {};
187 /// \brief Mutable accessor to the element associated with a given color name
188 /// \ingroup ColorBaseAlgorithmColor
189 template <typename ColorBase, typename Color>
190 typename color_element_reference_type<ColorBase,Color>::type get_color(ColorBase& cb, Color=Color()) {
191 return color_element_reference_type<ColorBase,Color>::get(cb);
194 /// \brief Constant accessor to the element associated with a given color name
195 /// \ingroup ColorBaseAlgorithmColor
196 template <typename ColorBase, typename Color>
197 typename color_element_const_reference_type<ColorBase,Color>::type get_color(const ColorBase& cb, Color=Color()) {
198 return color_element_const_reference_type<ColorBase,Color>::get(cb);
201 ///////////////////////////////////////
203 /// element_type, element_reference_type, element_const_reference_type: Support for homogeneous color bases
205 ///////////////////////////////////////
208 \defgroup ColorBaseAlgorithmHomogeneous element_type, element_reference_type, element_const_reference_type
209 \ingroup ColorBaseAlgorithm
210 \brief Types for homogeneous color bases
214 using element_t = element_type<rgb8c_planar_ptr_t>::type;
215 static_assert(std::is_same<element_t, const uint8_t*>::value, "");
218 /// \brief Specifies the element type of a homogeneous color base
219 /// \ingroup ColorBaseAlgorithmHomogeneous
220 template <typename ColorBase>
221 struct element_type : public kth_element_type<ColorBase, 0> {};
223 /// \brief Specifies the return type of the mutable element accessor at_c of a homogeneous color base
224 /// \ingroup ColorBaseAlgorithmHomogeneous
225 template <typename ColorBase>
226 struct element_reference_type : public kth_element_reference_type<ColorBase, 0> {};
228 /// \brief Specifies the return type of the constant element accessor at_c of a homogeneous color base
229 /// \ingroup ColorBaseAlgorithmHomogeneous
230 template <typename ColorBase>
231 struct element_const_reference_type : public kth_element_const_reference_type<ColorBase, 0> {};
236 // compile-time recursion for per-element operations on color bases
238 struct element_recursion
241 #if defined(BOOST_GCC) && (BOOST_GCC >= 40900)
242 #pragma GCC diagnostic push
243 #pragma GCC diagnostic ignored "-Wconversion"
244 #pragma GCC diagnostic ignored "-Wfloat-equal"
247 template <typename P1,typename P2>
248 static bool static_equal(const P1& p1, const P2& p2)
250 return element_recursion<N-1>::static_equal(p1,p2) &&
251 semantic_at_c<N-1>(p1)==semantic_at_c<N-1>(p2);
254 template <typename P1,typename P2>
255 static void static_copy(const P1& p1, P2& p2)
257 element_recursion<N-1>::static_copy(p1,p2);
258 semantic_at_c<N-1>(p2)=semantic_at_c<N-1>(p1);
261 template <typename P,typename T2>
262 static void static_fill(P& p, T2 v)
264 element_recursion<N-1>::static_fill(p,v);
265 semantic_at_c<N-1>(p)=v;
268 template <typename Dst,typename Op>
269 static void static_generate(Dst& dst, Op op)
271 element_recursion<N-1>::static_generate(dst,op);
272 semantic_at_c<N-1>(dst)=op();
275 #if defined(BOOST_GCC) && (BOOST_GCC >= 40900)
276 #pragma GCC diagnostic pop
279 //static_for_each with one source
280 template <typename P1,typename Op>
281 static Op static_for_each(P1& p1, Op op) {
282 Op op2(element_recursion<N-1>::static_for_each(p1,op));
283 op2(semantic_at_c<N-1>(p1));
286 template <typename P1,typename Op>
287 static Op static_for_each(const P1& p1, Op op) {
288 Op op2(element_recursion<N-1>::static_for_each(p1,op));
289 op2(semantic_at_c<N-1>(p1));
292 //static_for_each with two sources
293 template <typename P1,typename P2,typename Op>
294 static Op static_for_each(P1& p1, P2& p2, Op op) {
295 Op op2(element_recursion<N-1>::static_for_each(p1,p2,op));
296 op2(semantic_at_c<N-1>(p1), semantic_at_c<N-1>(p2));
299 template <typename P1,typename P2,typename Op>
300 static Op static_for_each(P1& p1, const P2& p2, Op op) {
301 Op op2(element_recursion<N-1>::static_for_each(p1,p2,op));
302 op2(semantic_at_c<N-1>(p1), semantic_at_c<N-1>(p2));
305 template <typename P1,typename P2,typename Op>
306 static Op static_for_each(const P1& p1, P2& p2, Op op) {
307 Op op2(element_recursion<N-1>::static_for_each(p1,p2,op));
308 op2(semantic_at_c<N-1>(p1), semantic_at_c<N-1>(p2));
311 template <typename P1,typename P2,typename Op>
312 static Op static_for_each(const P1& p1, const P2& p2, Op op) {
313 Op op2(element_recursion<N-1>::static_for_each(p1,p2,op));
314 op2(semantic_at_c<N-1>(p1), semantic_at_c<N-1>(p2));
317 //static_for_each with three sources
318 template <typename P1,typename P2,typename P3,typename Op>
319 static Op static_for_each(P1& p1, P2& p2, P3& p3, Op op) {
320 Op op2(element_recursion<N-1>::static_for_each(p1,p2,p3,op));
321 op2(semantic_at_c<N-1>(p1), semantic_at_c<N-1>(p2), semantic_at_c<N-1>(p3));
324 template <typename P1,typename P2,typename P3,typename Op>
325 static Op static_for_each(P1& p1, P2& p2, const P3& p3, Op op) {
326 Op op2(element_recursion<N-1>::static_for_each(p1,p2,p3,op));
327 op2(semantic_at_c<N-1>(p1), semantic_at_c<N-1>(p2), semantic_at_c<N-1>(p3));
330 template <typename P1,typename P2,typename P3,typename Op>
331 static Op static_for_each(P1& p1, const P2& p2, P3& p3, Op op) {
332 Op op2(element_recursion<N-1>::static_for_each(p1,p2,p3,op));
333 op2(semantic_at_c<N-1>(p1), semantic_at_c<N-1>(p2), semantic_at_c<N-1>(p3));
336 template <typename P1,typename P2,typename P3,typename Op>
337 static Op static_for_each(P1& p1, const P2& p2, const P3& p3, Op op) {
338 Op op2(element_recursion<N-1>::static_for_each(p1,p2,p3,op));
339 op2(semantic_at_c<N-1>(p1), semantic_at_c<N-1>(p2), semantic_at_c<N-1>(p3));
342 template <typename P1,typename P2,typename P3,typename Op>
343 static Op static_for_each(const P1& p1, P2& p2, P3& p3, Op op) {
344 Op op2(element_recursion<N-1>::static_for_each(p1,p2,p3,op));
345 op2(semantic_at_c<N-1>(p1), semantic_at_c<N-1>(p2), semantic_at_c<N-1>(p3));
348 template <typename P1,typename P2,typename P3,typename Op>
349 static Op static_for_each(const P1& p1, P2& p2, const P3& p3, Op op) {
350 Op op2(element_recursion<N-1>::static_for_each(p1,p2,p3,op));
351 op2(semantic_at_c<N-1>(p1), semantic_at_c<N-1>(p2), semantic_at_c<N-1>(p3));
354 template <typename P1,typename P2,typename P3,typename Op>
355 static Op static_for_each(const P1& p1, const P2& p2, P3& p3, Op op) {
356 Op op2(element_recursion<N-1>::static_for_each(p1,p2,p3,op));
357 op2(semantic_at_c<N-1>(p1), semantic_at_c<N-1>(p2), semantic_at_c<N-1>(p3));
360 template <typename P1,typename P2,typename P3,typename Op>
361 static Op static_for_each(const P1& p1, const P2& p2, const P3& p3, Op op) {
362 Op op2(element_recursion<N-1>::static_for_each(p1,p2,p3,op));
363 op2(semantic_at_c<N-1>(p1), semantic_at_c<N-1>(p2), semantic_at_c<N-1>(p3));
366 //static_transform with one source
367 template <typename P1,typename Dst,typename Op>
368 static Op static_transform(P1& src, Dst& dst, Op op) {
369 Op op2(element_recursion<N-1>::static_transform(src,dst,op));
370 semantic_at_c<N-1>(dst)=op2(semantic_at_c<N-1>(src));
373 template <typename P1,typename Dst,typename Op>
374 static Op static_transform(const P1& src, Dst& dst, Op op) {
375 Op op2(element_recursion<N-1>::static_transform(src,dst,op));
376 semantic_at_c<N-1>(dst)=op2(semantic_at_c<N-1>(src));
379 //static_transform with two sources
380 template <typename P1,typename P2,typename Dst,typename Op>
381 static Op static_transform(P1& src1, P2& src2, Dst& dst, Op op) {
382 Op op2(element_recursion<N-1>::static_transform(src1,src2,dst,op));
383 semantic_at_c<N-1>(dst)=op2(semantic_at_c<N-1>(src1), semantic_at_c<N-1>(src2));
386 template <typename P1,typename P2,typename Dst,typename Op>
387 static Op static_transform(P1& src1, const P2& src2, Dst& dst, Op op) {
388 Op op2(element_recursion<N-1>::static_transform(src1,src2,dst,op));
389 semantic_at_c<N-1>(dst)=op2(semantic_at_c<N-1>(src1), semantic_at_c<N-1>(src2));
392 template <typename P1,typename P2,typename Dst,typename Op>
393 static Op static_transform(const P1& src1, P2& src2, Dst& dst, Op op) {
394 Op op2(element_recursion<N-1>::static_transform(src1,src2,dst,op));
395 semantic_at_c<N-1>(dst)=op2(semantic_at_c<N-1>(src1), semantic_at_c<N-1>(src2));
398 template <typename P1,typename P2,typename Dst,typename Op>
399 static Op static_transform(const P1& src1, const P2& src2, Dst& dst, Op op) {
400 Op op2(element_recursion<N-1>::static_transform(src1,src2,dst,op));
401 semantic_at_c<N-1>(dst)=op2(semantic_at_c<N-1>(src1), semantic_at_c<N-1>(src2));
406 // Termination condition of the compile-time recursion for element operations on a color base
407 template<> struct element_recursion<0> {
409 template <typename P1,typename P2>
410 static bool static_equal(const P1&, const P2&) { return true; }
412 template <typename P1,typename P2>
413 static void static_copy(const P1&, const P2&) {}
415 template <typename P, typename T2>
416 static void static_fill(const P&, T2) {}
418 template <typename Dst,typename Op>
419 static void static_generate(const Dst&,Op){}
420 //static_for_each with one source
421 template <typename P1,typename Op>
422 static Op static_for_each(const P1&,Op op){return op;}
423 //static_for_each with two sources
424 template <typename P1,typename P2,typename Op>
425 static Op static_for_each(const P1&,const P2&,Op op){return op;}
426 //static_for_each with three sources
427 template <typename P1,typename P2,typename P3,typename Op>
428 static Op static_for_each(const P1&,const P2&,const P3&,Op op){return op;}
429 //static_transform with one source
430 template <typename P1,typename Dst,typename Op>
431 static Op static_transform(const P1&,const Dst&,Op op){return op;}
432 //static_transform with two sources
433 template <typename P1,typename P2,typename Dst,typename Op>
434 static Op static_transform(const P1&,const P2&,const Dst&,Op op){return op;}
437 // std::min and std::max don't have the mutable overloads...
438 template <typename Q> inline const Q& mutable_min(const Q& x, const Q& y) { return x<y ? x : y; }
439 template <typename Q> inline Q& mutable_min( Q& x, Q& y) { return x<y ? x : y; }
440 template <typename Q> inline const Q& mutable_max(const Q& x, const Q& y) { return x<y ? y : x; }
441 template <typename Q> inline Q& mutable_max( Q& x, Q& y) { return x<y ? y : x; }
444 // compile-time recursion for min/max element
446 struct min_max_recur {
447 template <typename P> static typename element_const_reference_type<P>::type max_(const P& p) {
448 return mutable_max(min_max_recur<N-1>::max_(p),semantic_at_c<N-1>(p));
450 template <typename P> static typename element_reference_type<P>::type max_( P& p) {
451 return mutable_max(min_max_recur<N-1>::max_(p),semantic_at_c<N-1>(p));
453 template <typename P> static typename element_const_reference_type<P>::type min_(const P& p) {
454 return mutable_min(min_max_recur<N-1>::min_(p),semantic_at_c<N-1>(p));
456 template <typename P> static typename element_reference_type<P>::type min_( P& p) {
457 return mutable_min(min_max_recur<N-1>::min_(p),semantic_at_c<N-1>(p));
461 // termination condition of the compile-time recursion for min/max element
463 struct min_max_recur<1> {
464 template <typename P> static typename element_const_reference_type<P>::type max_(const P& p) { return semantic_at_c<0>(p); }
465 template <typename P> static typename element_reference_type<P>::type max_( P& p) { return semantic_at_c<0>(p); }
466 template <typename P> static typename element_const_reference_type<P>::type min_(const P& p) { return semantic_at_c<0>(p); }
467 template <typename P> static typename element_reference_type<P>::type min_( P& p) { return semantic_at_c<0>(p); }
469 } // namespace detail
471 /// \defgroup ColorBaseAlgorithmMinMax static_min, static_max
472 /// \ingroup ColorBaseAlgorithm
473 /// \brief Equivalents to std::min_element and std::max_element for homogeneous color bases
477 /// rgb8_pixel_t pixel(10,20,30);
478 /// assert(pixel[2] == 30);
479 /// static_max(pixel) = static_min(pixel);
480 /// assert(pixel[2] == 10);
484 template <typename P>
486 typename element_const_reference_type<P>::type static_max(const P& p) { return detail::min_max_recur<size<P>::value>::max_(p); }
488 template <typename P>
490 typename element_reference_type<P>::type static_max( P& p) { return detail::min_max_recur<size<P>::value>::max_(p); }
492 template <typename P>
494 typename element_const_reference_type<P>::type static_min(const P& p) { return detail::min_max_recur<size<P>::value>::min_(p); }
496 template <typename P>
498 typename element_reference_type<P>::type static_min( P& p) { return detail::min_max_recur<size<P>::value>::min_(p); }
501 /// \defgroup ColorBaseAlgorithmEqual static_equal
502 /// \ingroup ColorBaseAlgorithm
503 /// \brief Equivalent to std::equal. Pairs the elements semantically
507 /// rgb8_pixel_t rgb_red(255,0,0);
508 /// bgr8_pixel_t bgr_red(0,0,255);
509 /// assert(rgb_red[0]==255 && bgr_red[0]==0);
511 /// assert(static_equal(rgb_red,bgr_red));
512 /// assert(rgb_red==bgr_red); // operator== invokes static_equal
516 template <typename P1,typename P2>
518 bool static_equal(const P1& p1, const P2& p2) { return detail::element_recursion<size<P1>::value>::static_equal(p1,p2); }
522 /// \defgroup ColorBaseAlgorithmCopy static_copy
523 /// \ingroup ColorBaseAlgorithm
524 /// \brief Equivalent to std::copy. Pairs the elements semantically
528 /// rgb8_pixel_t rgb_red(255,0,0);
529 /// bgr8_pixel_t bgr_red;
530 /// static_copy(rgb_red, bgr_red); // same as bgr_red = rgb_red
532 /// assert(rgb_red[0] == 255 && bgr_red[0] == 0);
533 /// assert(rgb_red == bgr_red);
537 template <typename Src,typename Dst>
539 void static_copy(const Src& src, Dst& dst)
541 detail::element_recursion<size<Dst>::value>::static_copy(src, dst);
546 /// \defgroup ColorBaseAlgorithmFill static_fill
547 /// \ingroup ColorBaseAlgorithm
548 /// \brief Equivalent to std::fill.
553 /// static_fill(p, 10);
554 /// assert(p == rgb8_pixel_t(10,10,10));
558 template <typename P,typename V>
560 void static_fill(P& p, const V& v)
562 detail::element_recursion<size<P>::value>::static_fill(p,v);
567 /// \defgroup ColorBaseAlgorithmGenerate static_generate
568 /// \ingroup ColorBaseAlgorithm
569 /// \brief Equivalent to std::generate.
571 /// Example: Set each channel of a pixel to its semantic index. The channels must be assignable from an integer.
573 /// struct consecutive_fn {
575 /// consecutive_fn(int& start) : _current(start) {}
576 /// int operator()() { return _current++; }
580 /// static_generate(p, consecutive_fn(start));
581 /// assert(p == rgb8_pixel_t(0,1,2));
586 template <typename P1,typename Op>
588 void static_generate(P1& dst,Op op) { detail::element_recursion<size<P1>::value>::static_generate(dst,op); }
591 /// \defgroup ColorBaseAlgorithmTransform static_transform
592 /// \ingroup ColorBaseAlgorithm
593 /// \brief Equivalent to std::transform. Pairs the elements semantically
595 /// Example: Write a generic function that adds two pixels into a homogeneous result pixel.
597 /// template <typename Result>
599 /// template <typename T1, typename T2>
600 /// Result operator()(T1 f1, T2 f2) const { return f1+f2; }
603 /// template <typename Pixel1, typename Pixel2, typename Pixel3>
604 /// void sum_channels(const Pixel1& p1, const Pixel2& p2, Pixel3& result) {
605 /// using result_channel_t = typename channel_type<Pixel3>::type;
606 /// static_transform(p1,p2,result,my_plus<result_channel_t>());
609 /// rgb8_pixel_t p1(1,2,3);
610 /// bgr8_pixel_t p2(3,2,1);
611 /// rgb8_pixel_t result;
612 /// sum_channels(p1,p2,result);
613 /// assert(result == rgb8_pixel_t(2,4,6));
617 //static_transform with one source
618 template <typename Src,typename Dst,typename Op>
620 Op static_transform(Src& src,Dst& dst,Op op) { return detail::element_recursion<size<Dst>::value>::static_transform(src,dst,op); }
621 template <typename Src,typename Dst,typename Op>
623 Op static_transform(const Src& src,Dst& dst,Op op) { return detail::element_recursion<size<Dst>::value>::static_transform(src,dst,op); }
624 //static_transform with two sources
625 template <typename P2,typename P3,typename Dst,typename Op>
627 Op static_transform(P2& p2,P3& p3,Dst& dst,Op op) { return detail::element_recursion<size<Dst>::value>::static_transform(p2,p3,dst,op); }
628 template <typename P2,typename P3,typename Dst,typename Op>
630 Op static_transform(P2& p2,const P3& p3,Dst& dst,Op op) { return detail::element_recursion<size<Dst>::value>::static_transform(p2,p3,dst,op); }
631 template <typename P2,typename P3,typename Dst,typename Op>
633 Op static_transform(const P2& p2,P3& p3,Dst& dst,Op op) { return detail::element_recursion<size<Dst>::value>::static_transform(p2,p3,dst,op); }
634 template <typename P2,typename P3,typename Dst,typename Op>
636 Op static_transform(const P2& p2,const P3& p3,Dst& dst,Op op) { return detail::element_recursion<size<Dst>::value>::static_transform(p2,p3,dst,op); }
639 /// \defgroup ColorBaseAlgorithmForEach static_for_each
640 /// \ingroup ColorBaseAlgorithm
641 /// \brief Equivalent to std::for_each. Pairs the elements semantically
643 /// Example: Use static_for_each to increment a planar pixel iterator
645 /// struct increment {
646 /// template <typename Incrementable>
647 /// void operator()(Incrementable& x) const { ++x; }
650 /// template <typename ColorBase>
651 /// void increment_elements(ColorBase& cb) {
652 /// static_for_each(cb, increment());
655 /// uint8_t red[2], green[2], blue[2];
656 /// rgb8c_planar_ptr_t p1(red,green,blue);
657 /// rgb8c_planar_ptr_t p2=p1;
658 /// increment_elements(p1);
660 /// assert(p1 == p2);
664 //static_for_each with one source
665 template <typename P1,typename Op>
667 Op static_for_each( P1& p1, Op op) { return detail::element_recursion<size<P1>::value>::static_for_each(p1,op); }
668 template <typename P1,typename Op>
670 Op static_for_each(const P1& p1, Op op) { return detail::element_recursion<size<P1>::value>::static_for_each(p1,op); }
671 //static_for_each with two sources
672 template <typename P1,typename P2,typename Op>
674 Op static_for_each(P1& p1, P2& p2, Op op) { return detail::element_recursion<size<P1>::value>::static_for_each(p1,p2,op); }
675 template <typename P1,typename P2,typename Op>
677 Op static_for_each(P1& p1,const P2& p2, Op op) { return detail::element_recursion<size<P1>::value>::static_for_each(p1,p2,op); }
678 template <typename P1,typename P2,typename Op>
680 Op static_for_each(const P1& p1, P2& p2, Op op) { return detail::element_recursion<size<P1>::value>::static_for_each(p1,p2,op); }
681 template <typename P1,typename P2,typename Op>
683 Op static_for_each(const P1& p1,const P2& p2, Op op) { return detail::element_recursion<size<P1>::value>::static_for_each(p1,p2,op); }
684 //static_for_each with three sources
685 template <typename P1,typename P2,typename P3,typename Op>
687 Op static_for_each(P1& p1,P2& p2,P3& p3,Op op) { return detail::element_recursion<size<P1>::value>::static_for_each(p1,p2,p3,op); }
688 template <typename P1,typename P2,typename P3,typename Op>
690 Op static_for_each(P1& p1,P2& p2,const P3& p3,Op op) { return detail::element_recursion<size<P1>::value>::static_for_each(p1,p2,p3,op); }
691 template <typename P1,typename P2,typename P3,typename Op>
693 Op static_for_each(P1& p1,const P2& p2,P3& p3,Op op) { return detail::element_recursion<size<P1>::value>::static_for_each(p1,p2,p3,op); }
694 template <typename P1,typename P2,typename P3,typename Op>
696 Op static_for_each(P1& p1,const P2& p2,const P3& p3,Op op) { return detail::element_recursion<size<P1>::value>::static_for_each(p1,p2,p3,op); }
697 template <typename P1,typename P2,typename P3,typename Op>
699 Op static_for_each(const P1& p1,P2& p2,P3& p3,Op op) { return detail::element_recursion<size<P1>::value>::static_for_each(p1,p2,p3,op); }
700 template <typename P1,typename P2,typename P3,typename Op>
702 Op static_for_each(const P1& p1,P2& p2,const P3& p3,Op op) { return detail::element_recursion<size<P1>::value>::static_for_each(p1,p2,p3,op); }
703 template <typename P1,typename P2,typename P3,typename Op>
705 Op static_for_each(const P1& p1,const P2& p2,P3& p3,Op op) { return detail::element_recursion<size<P1>::value>::static_for_each(p1,p2,p3,op); }
706 template <typename P1,typename P2,typename P3,typename Op>
708 Op static_for_each(const P1& p1,const P2& p2,const P3& p3,Op op) { return detail::element_recursion<size<P1>::value>::static_for_each(p1,p2,p3,op); }
711 } } // namespace boost::gil