Boost GIL


channel_algorithm.hpp
Go to the documentation of this file.
1 /*
2  Copyright 2005-2007 Adobe Systems Incorporated
3 
4  Use, modification and distribution are subject to the Boost Software License,
5  Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
6  http://www.boost.org/LICENSE_1_0.txt).
7 
8  See http://opensource.adobe.com/gil for most recent version including documentation.
9 */
10 /*************************************************************************************************/
11 
12 #ifndef GIL_CHANNEL_ALGORITHM_HPP
13 #define GIL_CHANNEL_ALGORITHM_HPP
14 
25 
26 #include <boost/config.hpp>
27 #include <boost/integer_traits.hpp>
28 #include <boost/mpl/less.hpp>
29 #include <boost/mpl/integral_c.hpp>
30 #include <boost/mpl/greater.hpp>
31 #include <boost/type_traits.hpp>
32 
33 #include "gil_config.hpp"
34 #include "channel.hpp"
35 #include "typedefs.hpp"
36 
37 namespace boost { namespace gil {
38 
39 //#ifdef _MSC_VER
40 //#pragma warning(push)
41 //#pragma warning(disable: 4309) // disable truncation of constant value warning (using -1 to get the max value of an integral)
42 //#endif
43 
44 namespace detail {
45 
46 // some forward declarations
47 template <typename SrcChannelV, typename DstChannelV, bool SrcIsIntegral, bool DstIsIntegral> struct channel_converter_unsigned_impl;
48 template <typename SrcChannelV, typename DstChannelV, bool SrcIsGreater> struct channel_converter_unsigned_integral;
49 template <typename SrcChannelV, typename DstChannelV, bool SrcLessThanDst, bool SrcDivisible> struct channel_converter_unsigned_integral_impl;
50 template <typename SrcChannelV, typename DstChannelV, bool SrcLessThanDst, bool CannotFitInInteger> struct channel_converter_unsigned_integral_nondivisible;
51 
55 
56 
57 template <typename UnsignedIntegralChannel>
58 struct unsigned_integral_max_value : public mpl::integral_c<UnsignedIntegralChannel,integer_traits< UnsignedIntegralChannel>::const_max> {};
59 
60 template <>
61 struct unsigned_integral_max_value<uint8_t> : public mpl::integral_c<uint32_t,0xFF> {};
62 template <>
63 struct unsigned_integral_max_value<uint16_t> : public mpl::integral_c<uint32_t,0xFFFF> {};
64 template <>
65 struct unsigned_integral_max_value<uint32_t> : public mpl::integral_c<uintmax_t,0xFFFFFFFF> {};
66 
67 
68 template <int K>
69 struct unsigned_integral_max_value<packed_channel_value<K> >
70  : public mpl::integral_c<typename packed_channel_value<K>::integer_t, (uint64_t(1)<<K)-1> {};
71 
72 
73 
77 
78 template <typename UnsignedIntegralChannel>
79 struct unsigned_integral_num_bits : public mpl::int_<sizeof(UnsignedIntegralChannel)*8> {};
80 
81 template <int K>
82 struct unsigned_integral_num_bits<packed_channel_value<K> >
83  : public mpl::int_<K> {};
84 
85 } // namespace detail
86 
120 
124 template <typename SrcChannelV, typename DstChannelV> // Model ChannelValueConcept
125 struct channel_converter_unsigned
126  : public detail::channel_converter_unsigned_impl<SrcChannelV,DstChannelV,is_integral<SrcChannelV>::value,is_integral<DstChannelV>::value> {};
127 
128 
130 template <typename T> struct channel_converter_unsigned<T,T> : public detail::identity<T> {};
131 
132 
133 namespace detail {
134 
138 
140 template <typename SrcChannelV, typename DstChannelV, bool SrcIsIntegral, bool DstIsIntegral>
141 struct channel_converter_unsigned_impl {
142  typedef SrcChannelV argument_type;
143  typedef DstChannelV result_type;
144  DstChannelV operator()(SrcChannelV src) const {
145  return DstChannelV(channel_traits<DstChannelV>::min_value() +
146  (src - channel_traits<SrcChannelV>::min_value()) / channel_range<SrcChannelV>() * channel_range<DstChannelV>());
147  }
148 private:
149  template <typename C>
150  static double channel_range() {
151  return double(channel_traits<C>::max_value()) - double(channel_traits<C>::min_value());
152  }
153 };
154 
155 // When both the source and the destination are integral channels, perform a faster conversion
156 template <typename SrcChannelV, typename DstChannelV>
157 struct channel_converter_unsigned_impl<SrcChannelV,DstChannelV,true,true>
158  : public channel_converter_unsigned_integral<SrcChannelV,DstChannelV,
159  mpl::less<unsigned_integral_max_value<SrcChannelV>,unsigned_integral_max_value<DstChannelV> >::value > {};
160 
161 
165 
166 template <typename SrcChannelV, typename DstChannelV>
167 struct channel_converter_unsigned_integral<SrcChannelV,DstChannelV,true>
168  : public channel_converter_unsigned_integral_impl<SrcChannelV,DstChannelV,true,
169  !(unsigned_integral_max_value<DstChannelV>::value % unsigned_integral_max_value<SrcChannelV>::value) > {};
170 
171 template <typename SrcChannelV, typename DstChannelV>
172 struct channel_converter_unsigned_integral<SrcChannelV,DstChannelV,false>
173  : public channel_converter_unsigned_integral_impl<SrcChannelV,DstChannelV,false,
174  !(unsigned_integral_max_value<SrcChannelV>::value % unsigned_integral_max_value<DstChannelV>::value) > {};
175 
176 
180 
181 // Both source and destination are unsigned integral channels,
182 // the src max value is less than the dst max value,
183 // and the dst max value is divisible by the src max value
184 template <typename SrcChannelV, typename DstChannelV>
185 struct channel_converter_unsigned_integral_impl<SrcChannelV,DstChannelV,true,true> {
186  DstChannelV operator()(SrcChannelV src) const {
187  typedef typename unsigned_integral_max_value<DstChannelV>::value_type integer_t;
188  static const integer_t mul = unsigned_integral_max_value<DstChannelV>::value / unsigned_integral_max_value<SrcChannelV>::value;
189  return DstChannelV(src * mul);
190  }
191 };
192 
193 // Both source and destination are unsigned integral channels,
194 // the dst max value is less than (or equal to) the src max value,
195 // and the src max value is divisible by the dst max value
196 template <typename SrcChannelV, typename DstChannelV>
197 struct channel_converter_unsigned_integral_impl<SrcChannelV,DstChannelV,false,true> {
198  DstChannelV operator()(SrcChannelV src) const {
199  typedef typename unsigned_integral_max_value<SrcChannelV>::value_type integer_t;
200  static const integer_t div = unsigned_integral_max_value<SrcChannelV>::value / unsigned_integral_max_value<DstChannelV>::value;
201  static const integer_t div2 = div/2;
202  return DstChannelV((src + div2) / div);
203  }
204 };
205 
206 // Prevent overflow for the largest integral type
207 template <typename DstChannelV>
208 struct channel_converter_unsigned_integral_impl<uintmax_t,DstChannelV,false,true> {
209  DstChannelV operator()(uintmax_t src) const {
210  static const uintmax_t div = unsigned_integral_max_value<uint32_t>::value / unsigned_integral_max_value<DstChannelV>::value;
211  static const uintmax_t div2 = div/2;
212  if (src > unsigned_integral_max_value<uintmax_t>::value - div2)
213  return unsigned_integral_max_value<DstChannelV>::value;
214  return DstChannelV((src + div2) / div);
215  }
216 };
217 
218 // Both source and destination are unsigned integral channels,
219 // and the dst max value is not divisible by the src max value
220 // See if you can represent the expression (src * dst_max) / src_max in integral form
221 template <typename SrcChannelV, typename DstChannelV, bool SrcLessThanDst>
222 struct channel_converter_unsigned_integral_impl<SrcChannelV,DstChannelV,SrcLessThanDst,false>
223  : public channel_converter_unsigned_integral_nondivisible<SrcChannelV,DstChannelV,SrcLessThanDst,
224  mpl::greater<
225  mpl::plus<unsigned_integral_num_bits<SrcChannelV>,unsigned_integral_num_bits<DstChannelV> >,
226  unsigned_integral_num_bits<uintmax_t>
227  >::value> {};
228 
229 
230 // Both source and destination are unsigned integral channels,
231 // the src max value is less than the dst max value,
232 // and the dst max value is not divisible by the src max value
233 // The expression (src * dst_max) / src_max fits in an integer
234 template <typename SrcChannelV, typename DstChannelV>
235 struct channel_converter_unsigned_integral_nondivisible<SrcChannelV,DstChannelV,true,false> {
236  DstChannelV operator()(SrcChannelV src) const {
237  typedef typename base_channel_type<DstChannelV>::type dest_t;
238  return DstChannelV(static_cast<dest_t>( src * unsigned_integral_max_value<DstChannelV>::value) / unsigned_integral_max_value<SrcChannelV>::value);
239  }
240 };
241 
242 // Both source and destination are unsigned integral channels,
243 // the src max value is less than the dst max value,
244 // and the dst max value is not divisible by the src max value
245 // The expression (src * dst_max) / src_max cannot fit in an integer (overflows). Use a double
246 template <typename SrcChannelV, typename DstChannelV>
247 struct channel_converter_unsigned_integral_nondivisible<SrcChannelV,DstChannelV,true,true> {
248  DstChannelV operator()(SrcChannelV src) const {
249  static const double mul = unsigned_integral_max_value<DstChannelV>::value / double(unsigned_integral_max_value<SrcChannelV>::value);
250  return DstChannelV(src * mul);
251  }
252 };
253 
254 // Both source and destination are unsigned integral channels,
255 // the dst max value is less than (or equal to) the src max value,
256 // and the src max value is not divisible by the dst max value
257 template <typename SrcChannelV, typename DstChannelV, bool CannotFit>
258 struct channel_converter_unsigned_integral_nondivisible<SrcChannelV,DstChannelV,false,CannotFit> {
259  DstChannelV operator()(SrcChannelV src) const {
260 
261  typedef typename detail::unsigned_integral_max_value< SrcChannelV >::value_type src_integer_t;
262  typedef typename detail::unsigned_integral_max_value< DstChannelV >::value_type dst_integer_t;
263 
264  static const double div = unsigned_integral_max_value<SrcChannelV>::value
265  / static_cast< double >( unsigned_integral_max_value<DstChannelV>::value );
266 
267  static const src_integer_t div2 = static_cast< src_integer_t >( div / 2.0 );
268 
269  return DstChannelV( static_cast< dst_integer_t >(( static_cast< double >( src + div2 ) / div )));
270  }
271 };
272 
273 } // namespace detail
274 
278 
279 template <typename DstChannelV> struct channel_converter_unsigned<float32_t,DstChannelV> {
280  typedef float32_t argument_type;
281  typedef DstChannelV result_type;
282  DstChannelV operator()(float32_t x) const
283  {
284  typedef typename detail::unsigned_integral_max_value< DstChannelV >::value_type dst_integer_t;
285  return DstChannelV( static_cast< dst_integer_t >(x*channel_traits<DstChannelV>::max_value()+0.5f ));
286  }
287 };
288 
289 template <typename SrcChannelV> struct channel_converter_unsigned<SrcChannelV,float32_t> {
290  typedef float32_t argument_type;
291  typedef SrcChannelV result_type;
292  float32_t operator()(SrcChannelV x) const { return float32_t(x/float(channel_traits<SrcChannelV>::max_value())); }
293 };
294 
295 template <> struct channel_converter_unsigned<float32_t,float32_t> {
296  typedef float32_t argument_type;
297  typedef float32_t result_type;
298  float32_t operator()(float32_t x) const { return x; }
299 };
300 
301 
303 template <> struct channel_converter_unsigned<uint32_t,float32_t> {
304  typedef uint32_t argument_type;
305  typedef float32_t result_type;
306  float32_t operator()(uint32_t x) const {
307  // 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
308  if (x>=channel_traits<uint32_t>::max_value()) return channel_traits<float32_t>::max_value();
309  return float(x) / float(channel_traits<uint32_t>::max_value());
310  }
311 };
313 template <> struct channel_converter_unsigned<float32_t,uint32_t> {
314  typedef float32_t argument_type;
315  typedef uint32_t result_type;
316  uint32_t operator()(float32_t x) const {
317  // 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
320 
321  auto const max_value = channel_traits<uint32_t>::max_value();
322  auto const result = x * static_cast<float32_t::base_channel_t>(max_value) + 0.5f;
323  return static_cast<uint32_t>(result);
324  }
325 };
326 
328 
329 namespace detail {
330 // Converting from signed to unsigned integral channel.
331 // It is both a unary function, and a metafunction (thus requires the 'type' nested typedef, which equals result_type)
332 template <typename ChannelValue> // Model ChannelValueConcept
333 struct channel_convert_to_unsigned : public detail::identity<ChannelValue> {
334  typedef ChannelValue type;
335 };
336 
337 template <> struct channel_convert_to_unsigned<int8_t> {
338  typedef int8_t argument_type;
339  typedef uint8_t result_type;
340  typedef uint8_t type;
341  type operator()(int8_t val) const {
342  return static_cast<uint8_t>(static_cast<uint32_t>(val) + 128u);
343  }
344 };
345 
346 template <> struct channel_convert_to_unsigned<int16_t> {
347  typedef int16_t argument_type;
348  typedef uint16_t result_type;
349  typedef uint16_t type;
350  type operator()(int16_t val) const {
351  return static_cast<uint16_t>(static_cast<uint32_t>(val) + 32768u);
352  }
353 };
354 
355 template <> struct channel_convert_to_unsigned<int32_t> {
356  typedef int32_t argument_type;
357  typedef uint32_t result_type;
358  typedef uint32_t type;
359  type operator()(int32_t val) const {
360  return static_cast<uint32_t>(val)+(1u<<31);
361  }
362 };
363 
364 
365 // Converting from unsigned to signed integral channel
366 // It is both a unary function, and a metafunction (thus requires the 'type' nested typedef, which equals result_type)
367 template <typename ChannelValue> // Model ChannelValueConcept
368 struct channel_convert_from_unsigned : public detail::identity<ChannelValue> {
369  typedef ChannelValue type;
370 };
371 
372 template <> struct channel_convert_from_unsigned<int8_t> {
373  typedef uint8_t argument_type;
374  typedef int8_t result_type;
375  typedef int8_t type;
376  type operator()(uint8_t val) const {
377  return static_cast<int8_t>(static_cast<int32_t>(val) - 128);
378  }
379 };
380 
381 template <> struct channel_convert_from_unsigned<int16_t> {
382  typedef uint16_t argument_type;
383  typedef int16_t result_type;
384  typedef int16_t type;
385  type operator()(uint16_t val) const {
386  return static_cast<int16_t>(static_cast<int32_t>(val) - 32768);
387  }
388 };
389 
390 template <> struct channel_convert_from_unsigned<int32_t> {
391  typedef uint32_t argument_type;
392  typedef int32_t result_type;
393  typedef int32_t type;
394  type operator()(uint32_t val) const {
395  return static_cast<int32_t>(val - (1u<<31));
396  }
397 };
398 
399 } // namespace detail
400 
403 template <typename SrcChannelV, typename DstChannelV> // Model ChannelValueConcept
405  typedef SrcChannelV argument_type;
406  typedef DstChannelV result_type;
407  DstChannelV operator()(const SrcChannelV& src) const {
408  typedef detail::channel_convert_to_unsigned<SrcChannelV> to_unsigned;
409  typedef detail::channel_convert_from_unsigned<DstChannelV> from_unsigned;
410  typedef channel_converter_unsigned<typename to_unsigned::result_type, typename from_unsigned::argument_type> converter_unsigned;
411  return from_unsigned()(converter_unsigned()(to_unsigned()(src)));
412  }
413 };
414 
417 template <typename DstChannel, typename SrcChannel> // Model ChannelConcept (could be channel references)
418 inline typename channel_traits<DstChannel>::value_type channel_convert(const SrcChannel& src) {
420  typename channel_traits<DstChannel>::value_type>()(src);
421 }
422 
428  template <typename Ch1, typename Ch2>
429  void operator()(const Ch1& src, Ch2& dst) const {
430  dst=channel_convert<Ch2>(src);
431  }
432 };
433 
434 namespace detail {
435  // fast integer division by 255
436  inline uint32_t div255(uint32_t in) { uint32_t tmp=in+128; return (tmp + (tmp>>8))>>8; }
437 
438  // fast integer divison by 32768
439  inline uint32_t div32768(uint32_t in) { return (in+16384)>>15; }
440 }
441 
455 
458 template <typename ChannelValue>
460  typedef ChannelValue first_argument_type;
461  typedef ChannelValue second_argument_type;
462  typedef ChannelValue result_type;
463  ChannelValue operator()(ChannelValue a, ChannelValue b) const {
464  return ChannelValue(static_cast<typename base_channel_type<ChannelValue>::type>(a / double(channel_traits<ChannelValue>::max_value()) * b));
465  }
466 };
467 
469 template<> struct channel_multiplier_unsigned<uint8_t> {
470  typedef uint8_t first_argument_type;
471  typedef uint8_t second_argument_type;
472  typedef uint8_t result_type;
473  uint8_t operator()(uint8_t a, uint8_t b) const { return uint8_t(detail::div255(uint32_t(a) * uint32_t(b))); }
474 };
475 
477 template<> struct channel_multiplier_unsigned<uint16_t> {
478  typedef uint16_t first_argument_type;
479  typedef uint16_t second_argument_type;
480  typedef uint16_t result_type;
481  uint16_t operator()(uint16_t a, uint16_t b) const { return uint16_t((uint32_t(a) * uint32_t(b))/65535); }
482 };
483 
488  typedef float32_t result_type;
489  float32_t operator()(float32_t a, float32_t b) const { return a*b; }
490 };
491 
493 template <typename ChannelValue>
495  typedef ChannelValue first_argument_type;
496  typedef ChannelValue second_argument_type;
497  typedef ChannelValue result_type;
498  ChannelValue operator()(ChannelValue a, ChannelValue b) const {
499  typedef detail::channel_convert_to_unsigned<ChannelValue> to_unsigned;
500  typedef detail::channel_convert_from_unsigned<ChannelValue> from_unsigned;
502  return from_unsigned()(multiplier_unsigned()(to_unsigned()(a), to_unsigned()(b)));
503  }
504 };
505 
507 template <typename Channel> // Models ChannelConcept (could be a channel reference)
508 inline typename channel_traits<Channel>::value_type channel_multiply(Channel a, Channel b) {
510 }
512 
527 template <typename Channel> // Models ChannelConcept (could be a channel reference)
532 }
533 
534 //#ifdef _MSC_VER
535 //#pragma warning(pop)
536 //#endif
537 
538 } } // namespace boost::gil
539 
540 #endif
channel_traits< Channel >::value_type channel_invert(Channel x)
Default implementation. Provide overloads for performance.
Definition: channel_algorithm.hpp:530
A channel adaptor that modifies the range of the source channel. Models: ChannelValueConcept.
Definition: channel.hpp:156
channel_traits< DstChannel >::value_type channel_convert(const SrcChannel &src)
Converting from one channel type to another.
Definition: channel_algorithm.hpp:418
Channel utilities.
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:508
identity taken from SGI STL.
Definition: utilities.hpp:265
Same as channel_converter, except it takes the destination channel by reference, which allows us to m...
Definition: channel_algorithm.hpp:427
A function object to multiply two channels. result = a * b / max_value.
Definition: channel_algorithm.hpp:494
Useful public typedefs.
This is the default implementation. Performance specializatons are provided.
Definition: channel_algorithm.hpp:459
Traits for channels. Contains the following members:
Definition: channel.hpp:114
GIL configuration file.
This is the default implementation. Performance specializatons are provided.
Definition: channel_algorithm.hpp:47
A unary function object converting between channel types.
Definition: channel_algorithm.hpp:404