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 
15 #include <boost/mpl/less.hpp>
16 #include <boost/mpl/integral_c.hpp>
17 #include <boost/mpl/greater.hpp>
18 #include <boost/type_traits.hpp>
19 
20 #include <limits>
21 
22 namespace boost { namespace gil {
23 
24 namespace detail {
25 
26 // some forward declarations
27 template <typename SrcChannelV, typename DstChannelV, bool SrcIsIntegral, bool DstIsIntegral> struct channel_converter_unsigned_impl;
28 template <typename SrcChannelV, typename DstChannelV, bool SrcIsGreater> struct channel_converter_unsigned_integral;
29 template <typename SrcChannelV, typename DstChannelV, bool SrcLessThanDst, bool SrcDivisible> struct channel_converter_unsigned_integral_impl;
30 template <typename SrcChannelV, typename DstChannelV, bool SrcLessThanDst, bool CannotFitInInteger> struct channel_converter_unsigned_integral_nondivisible;
31 
35 
36 
37 template <typename UnsignedIntegralChannel>
38 struct unsigned_integral_max_value : public mpl::integral_c<UnsignedIntegralChannel,std::numeric_limits<UnsignedIntegralChannel>::max()> {};
39 
40 template <>
41 struct unsigned_integral_max_value<uint8_t> : public mpl::integral_c<uint32_t,0xFF> {};
42 template <>
43 struct unsigned_integral_max_value<uint16_t> : public mpl::integral_c<uint32_t,0xFFFF> {};
44 template <>
45 struct unsigned_integral_max_value<uint32_t> : public mpl::integral_c<uintmax_t,0xFFFFFFFF> {};
46 
47 
48 template <int K>
49 struct unsigned_integral_max_value<packed_channel_value<K> >
50  : public mpl::integral_c<typename packed_channel_value<K>::integer_t, (uint64_t(1)<<K)-1> {};
51 
52 
53 
57 
58 template <typename UnsignedIntegralChannel>
59 struct unsigned_integral_num_bits : public mpl::int_<sizeof(UnsignedIntegralChannel)*8> {};
60 
61 template <int K>
62 struct unsigned_integral_num_bits<packed_channel_value<K> >
63  : public mpl::int_<K> {};
64 
65 } // namespace detail
66 
100 
104 template <typename SrcChannelV, typename DstChannelV> // Model ChannelValueConcept
105 struct channel_converter_unsigned
106  : public detail::channel_converter_unsigned_impl<SrcChannelV,DstChannelV,is_integral<SrcChannelV>::value,is_integral<DstChannelV>::value> {};
107 
108 
110 template <typename T> struct channel_converter_unsigned<T,T> : public detail::identity<T> {};
111 
112 
113 namespace detail {
114 
118 
120 template <typename SrcChannelV, typename DstChannelV, bool SrcIsIntegral, bool DstIsIntegral>
121 struct channel_converter_unsigned_impl {
122  typedef SrcChannelV argument_type;
123  typedef DstChannelV result_type;
124  DstChannelV operator()(SrcChannelV src) const {
125  return DstChannelV(channel_traits<DstChannelV>::min_value() +
126  (src - channel_traits<SrcChannelV>::min_value()) / channel_range<SrcChannelV>() * channel_range<DstChannelV>());
127  }
128 private:
129  template <typename C>
130  static double channel_range() {
131  return double(channel_traits<C>::max_value()) - double(channel_traits<C>::min_value());
132  }
133 };
134 
135 // When both the source and the destination are integral channels, perform a faster conversion
136 template <typename SrcChannelV, typename DstChannelV>
137 struct channel_converter_unsigned_impl<SrcChannelV,DstChannelV,true,true>
138  : public channel_converter_unsigned_integral<SrcChannelV,DstChannelV,
139  mpl::less<unsigned_integral_max_value<SrcChannelV>,unsigned_integral_max_value<DstChannelV> >::value > {};
140 
141 
145 
146 template <typename SrcChannelV, typename DstChannelV>
147 struct channel_converter_unsigned_integral<SrcChannelV,DstChannelV,true>
148  : public channel_converter_unsigned_integral_impl<SrcChannelV,DstChannelV,true,
149  !(unsigned_integral_max_value<DstChannelV>::value % unsigned_integral_max_value<SrcChannelV>::value) > {};
150 
151 template <typename SrcChannelV, typename DstChannelV>
152 struct channel_converter_unsigned_integral<SrcChannelV,DstChannelV,false>
153  : public channel_converter_unsigned_integral_impl<SrcChannelV,DstChannelV,false,
154  !(unsigned_integral_max_value<SrcChannelV>::value % unsigned_integral_max_value<DstChannelV>::value) > {};
155 
156 
160 
161 // Both source and destination are unsigned integral channels,
162 // the src max value is less than the dst max value,
163 // and the dst max value is divisible by the src max value
164 template <typename SrcChannelV, typename DstChannelV>
165 struct channel_converter_unsigned_integral_impl<SrcChannelV,DstChannelV,true,true> {
166  DstChannelV operator()(SrcChannelV src) const {
167  typedef typename unsigned_integral_max_value<DstChannelV>::value_type integer_t;
168  static const integer_t mul = unsigned_integral_max_value<DstChannelV>::value / unsigned_integral_max_value<SrcChannelV>::value;
169  return DstChannelV(src * mul);
170  }
171 };
172 
173 // Both source and destination are unsigned integral channels,
174 // the dst max value is less than (or equal to) the src max value,
175 // and the src max value is divisible by the dst max value
176 template <typename SrcChannelV, typename DstChannelV>
177 struct channel_converter_unsigned_integral_impl<SrcChannelV,DstChannelV,false,true> {
178  DstChannelV operator()(SrcChannelV src) const {
179  typedef typename unsigned_integral_max_value<SrcChannelV>::value_type integer_t;
180  static const integer_t div = unsigned_integral_max_value<SrcChannelV>::value / unsigned_integral_max_value<DstChannelV>::value;
181  static const integer_t div2 = div/2;
182  return DstChannelV((src + div2) / div);
183  }
184 };
185 
186 // Prevent overflow for the largest integral type
187 template <typename DstChannelV>
188 struct channel_converter_unsigned_integral_impl<uintmax_t,DstChannelV,false,true> {
189  DstChannelV operator()(uintmax_t src) const {
190  static const uintmax_t div = unsigned_integral_max_value<uint32_t>::value / unsigned_integral_max_value<DstChannelV>::value;
191  static const uintmax_t div2 = div/2;
192  if (src > unsigned_integral_max_value<uintmax_t>::value - div2)
193  return unsigned_integral_max_value<DstChannelV>::value;
194  return DstChannelV((src + div2) / div);
195  }
196 };
197 
198 // Both source and destination are unsigned integral channels,
199 // and the dst max value is not divisible by the src max value
200 // See if you can represent the expression (src * dst_max) / src_max in integral form
201 template <typename SrcChannelV, typename DstChannelV, bool SrcLessThanDst>
202 struct channel_converter_unsigned_integral_impl<SrcChannelV,DstChannelV,SrcLessThanDst,false>
203  : public channel_converter_unsigned_integral_nondivisible<SrcChannelV,DstChannelV,SrcLessThanDst,
204  mpl::greater<
205  mpl::plus<unsigned_integral_num_bits<SrcChannelV>,unsigned_integral_num_bits<DstChannelV> >,
206  unsigned_integral_num_bits<uintmax_t>
207  >::value> {};
208 
209 
210 // Both source and destination are unsigned integral channels,
211 // the src max value is less than the dst max value,
212 // and the dst max value is not divisible by the src max value
213 // The expression (src * dst_max) / src_max fits in an integer
214 template <typename SrcChannelV, typename DstChannelV>
215 struct channel_converter_unsigned_integral_nondivisible<SrcChannelV,DstChannelV,true,false> {
216  DstChannelV operator()(SrcChannelV src) const {
217  typedef typename base_channel_type<DstChannelV>::type dest_t;
218  return DstChannelV(static_cast<dest_t>( src * unsigned_integral_max_value<DstChannelV>::value) / unsigned_integral_max_value<SrcChannelV>::value);
219  }
220 };
221 
222 // Both source and destination are unsigned integral channels,
223 // the src max value is less than the dst max value,
224 // and the dst max value is not divisible by the src max value
225 // The expression (src * dst_max) / src_max cannot fit in an integer (overflows). Use a double
226 template <typename SrcChannelV, typename DstChannelV>
227 struct channel_converter_unsigned_integral_nondivisible<SrcChannelV,DstChannelV,true,true> {
228  DstChannelV operator()(SrcChannelV src) const {
229  static const double mul = unsigned_integral_max_value<DstChannelV>::value / double(unsigned_integral_max_value<SrcChannelV>::value);
230  return DstChannelV(src * mul);
231  }
232 };
233 
234 // Both source and destination are unsigned integral channels,
235 // the dst max value is less than (or equal to) the src max value,
236 // and the src max value is not divisible by the dst max value
237 template <typename SrcChannelV, typename DstChannelV, bool CannotFit>
238 struct channel_converter_unsigned_integral_nondivisible<SrcChannelV,DstChannelV,false,CannotFit> {
239  DstChannelV operator()(SrcChannelV src) const {
240 
241  typedef typename detail::unsigned_integral_max_value< SrcChannelV >::value_type src_integer_t;
242  typedef typename detail::unsigned_integral_max_value< DstChannelV >::value_type dst_integer_t;
243 
244  static const double div = unsigned_integral_max_value<SrcChannelV>::value
245  / static_cast< double >( unsigned_integral_max_value<DstChannelV>::value );
246 
247  static const src_integer_t div2 = static_cast< src_integer_t >( div / 2.0 );
248 
249  return DstChannelV( static_cast< dst_integer_t >(( static_cast< double >( src + div2 ) / div )));
250  }
251 };
252 
253 } // namespace detail
254 
258 
259 template <typename DstChannelV> struct channel_converter_unsigned<float32_t,DstChannelV> {
260  typedef float32_t argument_type;
261  typedef DstChannelV result_type;
262  DstChannelV operator()(float32_t x) const
263  {
264  typedef typename detail::unsigned_integral_max_value< DstChannelV >::value_type dst_integer_t;
265  return DstChannelV( static_cast< dst_integer_t >(x*channel_traits<DstChannelV>::max_value()+0.5f ));
266  }
267 };
268 
269 template <typename SrcChannelV> struct channel_converter_unsigned<SrcChannelV,float32_t> {
270  typedef float32_t argument_type;
271  typedef SrcChannelV result_type;
272  float32_t operator()(SrcChannelV x) const { return float32_t(x/float(channel_traits<SrcChannelV>::max_value())); }
273 };
274 
275 template <> struct channel_converter_unsigned<float32_t,float32_t> {
276  typedef float32_t argument_type;
277  typedef float32_t result_type;
278  float32_t operator()(float32_t x) const { return x; }
279 };
280 
281 
283 template <> struct channel_converter_unsigned<uint32_t,float32_t> {
284  typedef uint32_t argument_type;
285  typedef float32_t result_type;
286  float32_t operator()(uint32_t x) const {
287  // 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
288  if (x>=channel_traits<uint32_t>::max_value()) return channel_traits<float32_t>::max_value();
289  return float(x) / float(channel_traits<uint32_t>::max_value());
290  }
291 };
293 template <> struct channel_converter_unsigned<float32_t,uint32_t> {
294  typedef float32_t argument_type;
295  typedef uint32_t result_type;
296  uint32_t operator()(float32_t x) const {
297  // 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
298  if (x>=channel_traits<float32_t>::max_value())
299  return channel_traits<uint32_t>::max_value();
300 
301  auto const max_value = channel_traits<uint32_t>::max_value();
302  auto const result = x * static_cast<float32_t::base_channel_t>(max_value) + 0.5f;
303  return static_cast<uint32_t>(result);
304  }
305 };
306 
308 
309 namespace detail {
310 // Converting from signed to unsigned integral channel.
311 // It is both a unary function, and a metafunction (thus requires the 'type' nested typedef, which equals result_type)
312 template <typename ChannelValue> // Model ChannelValueConcept
313 struct channel_convert_to_unsigned : public detail::identity<ChannelValue> {
314  typedef ChannelValue type;
315 };
316 
317 template <> struct channel_convert_to_unsigned<int8_t> {
318  typedef int8_t argument_type;
319  typedef uint8_t result_type;
320  typedef uint8_t type;
321  type operator()(int8_t val) const {
322  return static_cast<uint8_t>(static_cast<uint32_t>(val) + 128u);
323  }
324 };
325 
326 template <> struct channel_convert_to_unsigned<int16_t> {
327  typedef int16_t argument_type;
328  typedef uint16_t result_type;
329  typedef uint16_t type;
330  type operator()(int16_t val) const {
331  return static_cast<uint16_t>(static_cast<uint32_t>(val) + 32768u);
332  }
333 };
334 
335 template <> struct channel_convert_to_unsigned<int32_t> {
336  typedef int32_t argument_type;
337  typedef uint32_t result_type;
338  typedef uint32_t type;
339  type operator()(int32_t val) const {
340  return static_cast<uint32_t>(val)+(1u<<31);
341  }
342 };
343 
344 
345 // Converting from unsigned to signed integral channel
346 // It is both a unary function, and a metafunction (thus requires the 'type' nested typedef, which equals result_type)
347 template <typename ChannelValue> // Model ChannelValueConcept
348 struct channel_convert_from_unsigned : public detail::identity<ChannelValue> {
349  typedef ChannelValue type;
350 };
351 
352 template <> struct channel_convert_from_unsigned<int8_t> {
353  typedef uint8_t argument_type;
354  typedef int8_t result_type;
355  typedef int8_t type;
356  type operator()(uint8_t val) const {
357  return static_cast<int8_t>(static_cast<int32_t>(val) - 128);
358  }
359 };
360 
361 template <> struct channel_convert_from_unsigned<int16_t> {
362  typedef uint16_t argument_type;
363  typedef int16_t result_type;
364  typedef int16_t type;
365  type operator()(uint16_t val) const {
366  return static_cast<int16_t>(static_cast<int32_t>(val) - 32768);
367  }
368 };
369 
370 template <> struct channel_convert_from_unsigned<int32_t> {
371  typedef uint32_t argument_type;
372  typedef int32_t result_type;
373  typedef int32_t type;
374  type operator()(uint32_t val) const {
375  return static_cast<int32_t>(val - (1u<<31));
376  }
377 };
378 
379 } // namespace detail
380 
383 template <typename SrcChannelV, typename DstChannelV> // Model ChannelValueConcept
385  typedef SrcChannelV argument_type;
386  typedef DstChannelV result_type;
387  DstChannelV operator()(const SrcChannelV& src) const {
388  typedef detail::channel_convert_to_unsigned<SrcChannelV> to_unsigned;
389  typedef detail::channel_convert_from_unsigned<DstChannelV> from_unsigned;
390  typedef channel_converter_unsigned<typename to_unsigned::result_type, typename from_unsigned::argument_type> converter_unsigned;
391  return from_unsigned()(converter_unsigned()(to_unsigned()(src)));
392  }
393 };
394 
397 template <typename DstChannel, typename SrcChannel> // Model ChannelConcept (could be channel references)
398 inline typename channel_traits<DstChannel>::value_type channel_convert(const SrcChannel& src) {
400  typename channel_traits<DstChannel>::value_type>()(src);
401 }
402 
408  template <typename Ch1, typename Ch2>
409  void operator()(const Ch1& src, Ch2& dst) const {
410  dst=channel_convert<Ch2>(src);
411  }
412 };
413 
414 namespace detail {
415  // fast integer division by 255
416  inline uint32_t div255(uint32_t in) { uint32_t tmp=in+128; return (tmp + (tmp>>8))>>8; }
417 
418  // fast integer divison by 32768
419  inline uint32_t div32768(uint32_t in) { return (in+16384)>>15; }
420 }
421 
435 
438 template <typename ChannelValue>
440  typedef ChannelValue first_argument_type;
441  typedef ChannelValue second_argument_type;
442  typedef ChannelValue result_type;
443  ChannelValue operator()(ChannelValue a, ChannelValue b) const {
444  return ChannelValue(static_cast<typename base_channel_type<ChannelValue>::type>(a / double(channel_traits<ChannelValue>::max_value()) * b));
445  }
446 };
447 
449 template<> struct channel_multiplier_unsigned<uint8_t> {
450  typedef uint8_t first_argument_type;
451  typedef uint8_t second_argument_type;
452  typedef uint8_t result_type;
453  uint8_t operator()(uint8_t a, uint8_t b) const { return uint8_t(detail::div255(uint32_t(a) * uint32_t(b))); }
454 };
455 
457 template<> struct channel_multiplier_unsigned<uint16_t> {
458  typedef uint16_t first_argument_type;
459  typedef uint16_t second_argument_type;
460  typedef uint16_t result_type;
461  uint16_t operator()(uint16_t a, uint16_t b) const { return uint16_t((uint32_t(a) * uint32_t(b))/65535); }
462 };
463 
466  typedef float32_t first_argument_type;
467  typedef float32_t second_argument_type;
468  typedef float32_t result_type;
469  float32_t operator()(float32_t a, float32_t b) const { return a*b; }
470 };
471 
473 template <typename ChannelValue>
475  typedef ChannelValue first_argument_type;
476  typedef ChannelValue second_argument_type;
477  typedef ChannelValue result_type;
478  ChannelValue operator()(ChannelValue a, ChannelValue b) const {
479  typedef detail::channel_convert_to_unsigned<ChannelValue> to_unsigned;
480  typedef detail::channel_convert_from_unsigned<ChannelValue> from_unsigned;
482  return from_unsigned()(multiplier_unsigned()(to_unsigned()(a), to_unsigned()(b)));
483  }
484 };
485 
487 template <typename Channel> // Models ChannelConcept (could be a channel reference)
488 inline typename channel_traits<Channel>::value_type channel_multiply(Channel a, Channel b) {
490 }
492 
507 template <typename Channel> // Models ChannelConcept (could be a channel reference)
510 inline typename channel_traits<Channel>::value_type channel_invert(Channel x) {
511 
512  using base_t = typename base_channel_type<Channel>::type;
513  using promoted_t = typename promote_integral<base_t>::type;
514  promoted_t const promoted_x = x;
515  promoted_t const promoted_max = channel_traits<Channel>::max_value();
516  promoted_t const promoted_min = channel_traits<Channel>::min_value();
517  promoted_t const promoted_inverted_x = promoted_max - promoted_x + promoted_min;
518  auto const inverted_x = static_cast<base_t>(promoted_inverted_x);
519  return inverted_x;
520 }
521 
522 } } // namespace boost::gil
523 
524 #endif
channel_traits< Channel >::value_type channel_invert(Channel x)
Default implementation. Provide overloads for performance.
Definition: channel_algorithm.hpp:510
channel_traits< DstChannel >::value_type channel_convert(const SrcChannel &src)
Converting from one channel type to another.
Definition: channel_algorithm.hpp:398
channel_traits< Channel >::value_type channel_multiply(Channel a, Channel b)
A function multiplying two channels. result = a * b / max_value.
Definition: channel_algorithm.hpp:488
identity taken from SGI STL.
Definition: utilities.hpp:193
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:124
Same as channel_converter, except it takes the destination channel by reference, which allows us to m...
Definition: channel_algorithm.hpp:407
A function object to multiply two channels. result = a * b / max_value.
Definition: channel_algorithm.hpp:474
This is the default implementation. Performance specializatons are provided.
Definition: channel_algorithm.hpp:439
This is the default implementation. Performance specializatons are provided.
Definition: channel_algorithm.hpp:27
A unary function object converting between channel types.
Definition: channel_algorithm.hpp:384