Boost GIL


channel_algorithm.hpp
1 //
2 // Copyright 2005-2007 Adobe Systems Incorporated
3 //
4 // Distributed under the Boost Software License, Version 1.0
5 // See accompanying file LICENSE_1_0.txt or copy at
6 // http://www.boost.org/LICENSE_1_0.txt
7 //
8 #ifndef BOOST_GIL_GIL_CHANNEL_ALGORITHM_HPP
9 #define BOOST_GIL_GIL_CHANNEL_ALGORITHM_HPP
10 
11 #include <boost/gil/channel.hpp>
12 #include <boost/gil/promote_integral.hpp>
13 #include <boost/gil/typedefs.hpp>
14 #include <boost/gil/detail/is_channel_integral.hpp>
15 #include <boost/gil/detail/mp11.hpp>
16 
17 #include <limits>
18 #include <type_traits>
19 
20 namespace boost { namespace gil {
21 
22 namespace detail {
23 
24 // some forward declarations
25 template <typename SrcChannelV, typename DstChannelV, bool SrcIsIntegral, bool DstIsIntegral>
26 struct channel_converter_unsigned_impl;
27 
28 template <typename SrcChannelV, typename DstChannelV, bool SrcIsGreater>
29 struct channel_converter_unsigned_integral;
30 
31 template <typename SrcChannelV, typename DstChannelV, bool SrcLessThanDst, bool SrcDivisible>
32 struct channel_converter_unsigned_integral_impl;
33 
34 template <typename SrcChannelV, typename DstChannelV, bool SrcLessThanDst, bool CannotFitInInteger>
35 struct channel_converter_unsigned_integral_nondivisible;
36 
41 
42 template <typename UnsignedIntegralChannel>
43 struct unsigned_integral_max_value
44  : std::integral_constant
45  <
46  UnsignedIntegralChannel,
47  (std::numeric_limits<UnsignedIntegralChannel>::max)()
48  >
49 {};
50 
51 template <>
52 struct unsigned_integral_max_value<uint8_t>
53  : std::integral_constant<uint32_t, 0xFF>
54 {};
55 
56 template <>
57 struct unsigned_integral_max_value<uint16_t>
58  : std::integral_constant<uint32_t, 0xFFFF>
59 {};
60 
61 template <>
62 struct unsigned_integral_max_value<uint32_t>
63  : std::integral_constant<uintmax_t, 0xFFFFFFFF>
64 {};
65 
66 template <int K>
67 struct unsigned_integral_max_value<packed_channel_value<K>>
68  : std::integral_constant
69  <
70  typename packed_channel_value<K>::integer_t,
71  (uint64_t(1)<<K)-1
72  >
73 {};
74 
79 
80 template <typename UnsignedIntegralChannel>
81 struct unsigned_integral_num_bits
82  : std::integral_constant<int, static_cast<int>(sizeof(UnsignedIntegralChannel) * 8)>
83 {};
84 
85 template <int K>
86 struct unsigned_integral_num_bits<packed_channel_value<K>>
87  : std::integral_constant<int, K>
88 {};
89 
90 } // namespace detail
91 
115 
121 
125 
126 template <typename SrcChannelV, typename DstChannelV> // Model ChannelValueConcept
127 struct channel_converter_unsigned
128  : detail::channel_converter_unsigned_impl
129  <
130  SrcChannelV,
131  DstChannelV,
132  detail::is_channel_integral<SrcChannelV>::value,
133  detail::is_channel_integral<DstChannelV>::value
134  >
135 {};
136 
138 template <typename T> struct channel_converter_unsigned<T,T> : public detail::identity<T> {};
139 
140 namespace detail {
141 
145 
147 template <typename SrcChannelV, typename DstChannelV, bool SrcIsIntegral, bool DstIsIntegral>
148 struct channel_converter_unsigned_impl {
149  using argument_type = SrcChannelV;
150  using result_type = DstChannelV;
151  auto operator()(SrcChannelV src) const -> DstChannelV
152  {
153  return DstChannelV(channel_traits<DstChannelV>::min_value() +
154  (src - channel_traits<SrcChannelV>::min_value()) / channel_range<SrcChannelV>() * channel_range<DstChannelV>());
155  }
156 
157 private:
158  template <typename C>
159  static auto channel_range() -> double
160  {
161  return double(channel_traits<C>::max_value()) - double(channel_traits<C>::min_value());
162  }
163 };
164 
165 // When both the source and the destination are integral channels, perform a faster conversion
166 template <typename SrcChannelV, typename DstChannelV>
167 struct channel_converter_unsigned_impl<SrcChannelV, DstChannelV, true, true>
168  : channel_converter_unsigned_integral
169  <
170  SrcChannelV,
171  DstChannelV,
172  mp11::mp_less
173  <
174  unsigned_integral_max_value<SrcChannelV>,
175  unsigned_integral_max_value<DstChannelV>
176  >::value
177  >
178 {};
179 
183 
184 template <typename SrcChannelV, typename DstChannelV>
185 struct channel_converter_unsigned_integral<SrcChannelV,DstChannelV,true>
186  : public channel_converter_unsigned_integral_impl<SrcChannelV,DstChannelV,true,
187  !(unsigned_integral_max_value<DstChannelV>::value % unsigned_integral_max_value<SrcChannelV>::value) > {};
188 
189 template <typename SrcChannelV, typename DstChannelV>
190 struct channel_converter_unsigned_integral<SrcChannelV,DstChannelV,false>
191  : public channel_converter_unsigned_integral_impl<SrcChannelV,DstChannelV,false,
192  !(unsigned_integral_max_value<SrcChannelV>::value % unsigned_integral_max_value<DstChannelV>::value) > {};
193 
194 
198 
199 // Both source and destination are unsigned integral channels,
200 // the src max value is less than the dst max value,
201 // and the dst max value is divisible by the src max value
202 template <typename SrcChannelV, typename DstChannelV>
203 struct channel_converter_unsigned_integral_impl<SrcChannelV,DstChannelV,true,true> {
204  auto operator()(SrcChannelV src) const -> DstChannelV
205  {
206  using integer_t = typename unsigned_integral_max_value<DstChannelV>::value_type;
207  static const integer_t mul = unsigned_integral_max_value<DstChannelV>::value / unsigned_integral_max_value<SrcChannelV>::value;
208  return DstChannelV(src * mul);
209  }
210 };
211 
212 // Both source and destination are unsigned integral channels,
213 // the dst max value is less than (or equal to) the src max value,
214 // and the src max value is divisible by the dst max value
215 template <typename SrcChannelV, typename DstChannelV>
216 struct channel_converter_unsigned_integral_impl<SrcChannelV,DstChannelV,false,true> {
217  auto operator()(SrcChannelV src) const -> DstChannelV
218  {
219  using integer_t = typename unsigned_integral_max_value<SrcChannelV>::value_type;
220  static const integer_t div = unsigned_integral_max_value<SrcChannelV>::value / unsigned_integral_max_value<DstChannelV>::value;
221  static const integer_t div2 = div/2;
222  return DstChannelV((src + div2) / div);
223  }
224 };
225 
226 // Prevent overflow for the largest integral type
227 template <typename DstChannelV>
228 struct channel_converter_unsigned_integral_impl<uintmax_t,DstChannelV,false,true> {
229  auto operator()(uintmax_t src) const -> DstChannelV
230  {
231  static const uintmax_t div = unsigned_integral_max_value<uint32_t>::value / unsigned_integral_max_value<DstChannelV>::value;
232  static const uintmax_t div2 = div/2;
233  if (src > unsigned_integral_max_value<uintmax_t>::value - div2)
234  return unsigned_integral_max_value<DstChannelV>::value;
235  return DstChannelV((src + div2) / div);
236  }
237 };
238 
239 // Both source and destination are unsigned integral channels,
240 // and the dst max value is not divisible by the src max value
241 // See if you can represent the expression (src * dst_max) / src_max in integral form
242 template <typename SrcChannelV, typename DstChannelV, bool SrcLessThanDst>
243 struct channel_converter_unsigned_integral_impl<SrcChannelV, DstChannelV, SrcLessThanDst, false>
244  : channel_converter_unsigned_integral_nondivisible
245  <
246  SrcChannelV,
247  DstChannelV,
248  SrcLessThanDst,
249  mp11::mp_less
250  <
251  unsigned_integral_num_bits<uintmax_t>,
252  mp11::mp_plus
253  <
254  unsigned_integral_num_bits<SrcChannelV>,
255  unsigned_integral_num_bits<DstChannelV>
256  >
257  >::value
258  >
259 {};
260 
261 // Both source and destination are unsigned integral channels,
262 // the src max value is less than the dst max value,
263 // and the dst max value is not divisible by the src max value
264 // The expression (src * dst_max) / src_max fits in an integer
265 template <typename SrcChannelV, typename DstChannelV>
266 struct channel_converter_unsigned_integral_nondivisible<SrcChannelV, DstChannelV, true, false>
267 {
268  auto operator()(SrcChannelV src) const -> DstChannelV
269  {
270  using dest_t = typename base_channel_type<DstChannelV>::type;
271  return DstChannelV(
272  static_cast<dest_t>(src * unsigned_integral_max_value<DstChannelV>::value)
273  / unsigned_integral_max_value<SrcChannelV>::value);
274  }
275 };
276 
277 // Both source and destination are unsigned integral channels,
278 // the src max value is less than the dst max value,
279 // and the dst max value is not divisible by the src max value
280 // The expression (src * dst_max) / src_max cannot fit in an integer (overflows). Use a double
281 template <typename SrcChannelV, typename DstChannelV>
282 struct channel_converter_unsigned_integral_nondivisible<SrcChannelV, DstChannelV, true, true>
283 {
284  auto operator()(SrcChannelV src) const -> DstChannelV
285  {
286  static const double mul
287  = unsigned_integral_max_value<DstChannelV>::value
288  / double(unsigned_integral_max_value<SrcChannelV>::value);
289  return DstChannelV(src * mul);
290  }
291 };
292 
293 // Both source and destination are unsigned integral channels,
294 // the dst max value is less than (or equal to) the src max value,
295 // and the src max value is not divisible by the dst max value
296 template <typename SrcChannelV, typename DstChannelV, bool CannotFit>
297 struct channel_converter_unsigned_integral_nondivisible<SrcChannelV,DstChannelV,false,CannotFit>
298 {
299  auto operator()(SrcChannelV src) const -> DstChannelV
300  {
301  using src_integer_t = typename detail::unsigned_integral_max_value<SrcChannelV>::value_type;
302  using dst_integer_t = typename detail::unsigned_integral_max_value<DstChannelV>::value_type;
303 
304  static const double div = unsigned_integral_max_value<SrcChannelV>::value
305  / static_cast< double >( unsigned_integral_max_value<DstChannelV>::value );
306 
307  static const src_integer_t div2 = static_cast< src_integer_t >( div / 2.0 );
308 
309  return DstChannelV( static_cast< dst_integer_t >(( static_cast< double >( src + div2 ) / div )));
310  }
311 };
312 
313 } // namespace detail
314 
318 
319 template <typename DstChannelV> struct channel_converter_unsigned<float32_t,DstChannelV> {
320  using argument_type = float32_t;
321  using result_type = DstChannelV;
322  auto operator()(float32_t x) const -> DstChannelV
323  {
324  using dst_integer_t = typename detail::unsigned_integral_max_value<DstChannelV>::value_type;
325  return DstChannelV( static_cast< dst_integer_t >(x*channel_traits<DstChannelV>::max_value()+0.5f ));
326  }
327 };
328 
329 template <typename SrcChannelV> struct channel_converter_unsigned<SrcChannelV,float32_t> {
330  using argument_type = float32_t;
331  using result_type = SrcChannelV;
332  auto operator()(SrcChannelV x) const -> float32_t { return float32_t(x/float(channel_traits<SrcChannelV>::max_value())); }
333 };
334 
335 template <> struct channel_converter_unsigned<float32_t,float32_t> {
336  using argument_type = float32_t;
337  using result_type = float32_t;
338  auto operator()(float32_t x) const -> float32_t { return x; }
339 };
340 
341 
343 template <> struct channel_converter_unsigned<uint32_t,float32_t> {
344  using argument_type = uint32_t;
345  using result_type = float32_t;
346  auto operator()(uint32_t x) const -> float32_t
347  {
348  // unfortunately without an explicit check it is possible to get a round-off error. We must ensure that max_value of uint32_t matches max_value of float32_t
349  if (x>=channel_traits<uint32_t>::max_value()) return channel_traits<float32_t>::max_value();
350  return float(x) / float(channel_traits<uint32_t>::max_value());
351  }
352 };
354 template <> struct channel_converter_unsigned<float32_t,uint32_t> {
355  using argument_type = float32_t;
356  using result_type = uint32_t;
357  auto operator()(float32_t x) const -> uint32_t
358  {
359  // unfortunately without an explicit check it is possible to get a round-off error. We must ensure that max_value of uint32_t matches max_value of float32_t
360  if (x>=channel_traits<float32_t>::max_value())
361  return channel_traits<uint32_t>::max_value();
362 
363  auto const max_value = channel_traits<uint32_t>::max_value();
364  auto const result = x * static_cast<float32_t::base_channel_t>(max_value) + 0.5f;
365  return static_cast<uint32_t>(result);
366  }
367 };
368 
370 
371 namespace detail {
372 // Converting from signed to unsigned integral channel.
373 // It is both a unary function, and a metafunction (thus requires the 'type' nested alias, which equals result_type)
374 template <typename ChannelValue> // Model ChannelValueConcept
375 struct channel_convert_to_unsigned : public detail::identity<ChannelValue> {
376  using type = ChannelValue;
377 };
378 
379 template <> struct channel_convert_to_unsigned<int8_t> {
380  using argument_type = int8_t;
381  using result_type = uint8_t;
382  using type = uint8_t;
383  type operator()(int8_t val) const {
384  return static_cast<uint8_t>(static_cast<uint32_t>(val) + 128u);
385  }
386 };
387 
388 template <> struct channel_convert_to_unsigned<int16_t> {
389  using argument_type = int16_t;
390  using result_type = uint16_t;
391  using type = uint16_t;
392  type operator()(int16_t val) const {
393  return static_cast<uint16_t>(static_cast<uint32_t>(val) + 32768u);
394  }
395 };
396 
397 template <> struct channel_convert_to_unsigned<int32_t> {
398  using argument_type = int32_t;
399  using result_type = uint32_t;
400  using type = uint32_t;
401  type operator()(int32_t val) const {
402  return static_cast<uint32_t>(val)+(1u<<31);
403  }
404 };
405 
406 
407 // Converting from unsigned to signed integral channel
408 // It is both a unary function, and a metafunction (thus requires the 'type' nested alias, which equals result_type)
409 template <typename ChannelValue> // Model ChannelValueConcept
410 struct channel_convert_from_unsigned : public detail::identity<ChannelValue> {
411  using type = ChannelValue;
412 };
413 
414 template <> struct channel_convert_from_unsigned<int8_t> {
415  using argument_type = uint8_t;
416  using result_type = int8_t;
417  using type = int8_t;
418  type operator()(uint8_t val) const {
419  return static_cast<int8_t>(static_cast<int32_t>(val) - 128);
420  }
421 };
422 
423 template <> struct channel_convert_from_unsigned<int16_t> {
424  using argument_type = uint16_t;
425  using result_type = int16_t;
426  using type = int16_t;
427  type operator()(uint16_t val) const {
428  return static_cast<int16_t>(static_cast<int32_t>(val) - 32768);
429  }
430 };
431 
432 template <> struct channel_convert_from_unsigned<int32_t> {
433  using argument_type = uint32_t;
434  using result_type = int32_t;
435  using type = int32_t;
436  type operator()(uint32_t val) const {
437  return static_cast<int32_t>(val - (1u<<31));
438  }
439 };
440 
441 } // namespace detail
442 
445 template <typename SrcChannelV, typename DstChannelV> // Model ChannelValueConcept
447  using argument_type = SrcChannelV;
448  using result_type = DstChannelV;
449  auto operator()(SrcChannelV const& src) const -> DstChannelV
450  {
451  using to_unsigned = detail::channel_convert_to_unsigned<SrcChannelV>;
452  using from_unsigned = detail::channel_convert_from_unsigned<DstChannelV>;
453  using converter_unsigned = channel_converter_unsigned<typename to_unsigned::result_type, typename from_unsigned::argument_type>;
454  return from_unsigned()(converter_unsigned()(to_unsigned()(src)));
455  }
456 };
457 
460 template <typename DstChannel, typename SrcChannel> // Model ChannelConcept (could be channel references)
461 inline auto channel_convert(SrcChannel const& src) -> typename channel_traits<DstChannel>::value_type
462 {
464  typename channel_traits<DstChannel>::value_type>()(src);
465 }
466 
472  template <typename Ch1, typename Ch2>
473  void operator()(Ch1 const& src, Ch2& dst) const
474  {
475  dst=channel_convert<Ch2>(src);
476  }
477 };
478 
479 namespace detail
480 {
481  // fast integer division by 255
482  inline auto div255(uint32_t in) -> uint32_t
483  {
484  uint32_t tmp = in + 128;
485  return (tmp + (tmp >> 8)) >> 8;
486  }
487 
488  // fast integer division by 32768
489  inline auto div32768(uint32_t in) -> uint32_t
490  {
491  return (in + 16384) >> 15;
492  }
493 }
494 
507 
509 template <typename ChannelValue>
511  using first_argument_type = ChannelValue;
512  using second_argument_type = ChannelValue;
513  using result_type = ChannelValue;
514  auto operator()(ChannelValue a, ChannelValue b) const -> ChannelValue
515  {
516  return ChannelValue(static_cast<typename base_channel_type<ChannelValue>::type>(a / double(channel_traits<ChannelValue>::max_value()) * b));
517  }
518 };
519 
521 template<> struct channel_multiplier_unsigned<uint8_t> {
522  using first_argument_type = uint8_t;
523  using second_argument_type = uint8_t;
524  using result_type = uint8_t;
525  auto operator()(uint8_t a, uint8_t b) const -> uint8_t { return uint8_t(detail::div255(uint32_t(a) * uint32_t(b))); }
526 };
527 
529 template<> struct channel_multiplier_unsigned<uint16_t> {
530  using first_argument_type = uint16_t;
531  using second_argument_type = uint16_t;
532  using result_type = uint16_t;
533  auto operator()(uint16_t a, uint16_t b) const -> uint16_t { return uint16_t((uint32_t(a) * uint32_t(b))/65535); }
534 };
535 
538  using first_argument_type = float32_t;
539  using second_argument_type = float32_t;
540  using result_type = float32_t;
541  auto operator()(float32_t a, float32_t b) const -> float32_t { return a*b; }
542 };
543 
545 template <typename ChannelValue>
547  using first_argument_type = ChannelValue;
548  using second_argument_type = ChannelValue;
549  using result_type = ChannelValue;
550  auto operator()(ChannelValue a, ChannelValue b) const -> ChannelValue
551  {
552  using to_unsigned = detail::channel_convert_to_unsigned<ChannelValue>;
553  using from_unsigned = detail::channel_convert_from_unsigned<ChannelValue>;
555  return from_unsigned()(multiplier_unsigned()(to_unsigned()(a), to_unsigned()(b)));
556  }
557 };
558 
560 template <typename Channel> // Models ChannelConcept (could be a channel reference)
561 inline auto channel_multiply(Channel a, Channel b) -> typename channel_traits<Channel>::value_type
562 {
564 }
566 
578 
581 template <typename Channel> // Models ChannelConcept (could be a channel reference)
582 inline auto channel_invert(Channel x) -> typename channel_traits<Channel>::value_type
583 {
584  using base_t = typename base_channel_type<Channel>::type;
585  using promoted_t = typename promote_integral<base_t>::type;
586  promoted_t const promoted_x = x;
587  promoted_t const promoted_max = channel_traits<Channel>::max_value();
588  promoted_t const promoted_min = channel_traits<Channel>::min_value();
589  promoted_t const promoted_inverted_x = promoted_max - promoted_x + promoted_min;
590  auto const inverted_x = static_cast<base_t>(promoted_inverted_x);
591  return inverted_x;
592 }
593 
594 }} // namespace boost::gil
595 
596 #endif
auto channel_convert(SrcChannel const &src) -> typename channel_traits< DstChannel >::value_type
Converting from one channel type to another.
Definition: channel_algorithm.hpp:461
auto channel_invert(Channel x) -> typename channel_traits< Channel >::value_type
Default implementation. Provide overloads for performance.
Definition: channel_algorithm.hpp:582
scoped_channel_value< float, float_point_zero< float >, float_point_one< float > > float32_t
32-bit floating point channel type with range [0.0f ... 1.0f]. Models ChannelValueConcept
Definition: typedefs.hpp:153
auto channel_multiply(Channel a, Channel b) -> typename channel_traits< Channel >::value_type
A function multiplying two channels. result = a * b / max_value.
Definition: channel_algorithm.hpp:561
defined(BOOST_NO_CXX17_HDR_MEMORY_RESOURCE)
Definition: algorithm.hpp:36
A unary function object converting between channel types.
Definition: channel_algorithm.hpp:446
This is the default implementation. Performance specializatons are provided.
Definition: channel_algorithm.hpp:510
A function object to multiply two channels. result = a * b / max_value.
Definition: channel_algorithm.hpp:546
Same as channel_converter, except it takes the destination channel by reference, which allows us to m...
Definition: channel_algorithm.hpp:471
identity taken from SGI STL.
Definition: utilities.hpp:211