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/mpl/less.hpp>
28 #include <boost/mpl/integral_c.hpp>
29 #include <boost/mpl/greater.hpp>
30 #include <boost/type_traits.hpp>
31 
32 #include "gil_config.hpp"
33 #include "channel.hpp"
34 #include "promote_integral.hpp"
35 #include "typedefs.hpp"
36 
37 #include <limits>
38 
39 namespace boost { namespace gil {
40 
41 //#ifdef _MSC_VER
42 //#pragma warning(push)
43 //#pragma warning(disable: 4309) // disable truncation of constant value warning (using -1 to get the max value of an integral)
44 //#endif
45 
46 namespace detail {
47 
48 // some forward declarations
49 template <typename SrcChannelV, typename DstChannelV, bool SrcIsIntegral, bool DstIsIntegral> struct channel_converter_unsigned_impl;
50 template <typename SrcChannelV, typename DstChannelV, bool SrcIsGreater> struct channel_converter_unsigned_integral;
51 template <typename SrcChannelV, typename DstChannelV, bool SrcLessThanDst, bool SrcDivisible> struct channel_converter_unsigned_integral_impl;
52 template <typename SrcChannelV, typename DstChannelV, bool SrcLessThanDst, bool CannotFitInInteger> struct channel_converter_unsigned_integral_nondivisible;
53 
57 
58 
59 template <typename UnsignedIntegralChannel>
60 struct unsigned_integral_max_value : public mpl::integral_c<UnsignedIntegralChannel,std::numeric_limits<UnsignedIntegralChannel>::max()> {};
61 
62 template <>
63 struct unsigned_integral_max_value<uint8_t> : public mpl::integral_c<uint32_t,0xFF> {};
64 template <>
65 struct unsigned_integral_max_value<uint16_t> : public mpl::integral_c<uint32_t,0xFFFF> {};
66 template <>
67 struct unsigned_integral_max_value<uint32_t> : public mpl::integral_c<uintmax_t,0xFFFFFFFF> {};
68 
69 
70 template <int K>
71 struct unsigned_integral_max_value<packed_channel_value<K> >
72  : public mpl::integral_c<typename packed_channel_value<K>::integer_t, (uint64_t(1)<<K)-1> {};
73 
74 
75 
79 
80 template <typename UnsignedIntegralChannel>
81 struct unsigned_integral_num_bits : public mpl::int_<sizeof(UnsignedIntegralChannel)*8> {};
82 
83 template <int K>
84 struct unsigned_integral_num_bits<packed_channel_value<K> >
85  : public mpl::int_<K> {};
86 
87 } // namespace detail
88 
122 
126 template <typename SrcChannelV, typename DstChannelV> // Model ChannelValueConcept
127 struct channel_converter_unsigned
128  : public detail::channel_converter_unsigned_impl<SrcChannelV,DstChannelV,is_integral<SrcChannelV>::value,is_integral<DstChannelV>::value> {};
129 
130 
132 template <typename T> struct channel_converter_unsigned<T,T> : public detail::identity<T> {};
133 
134 
135 namespace detail {
136 
140 
142 template <typename SrcChannelV, typename DstChannelV, bool SrcIsIntegral, bool DstIsIntegral>
143 struct channel_converter_unsigned_impl {
144  typedef SrcChannelV argument_type;
145  typedef DstChannelV result_type;
146  DstChannelV operator()(SrcChannelV src) const {
147  return DstChannelV(channel_traits<DstChannelV>::min_value() +
148  (src - channel_traits<SrcChannelV>::min_value()) / channel_range<SrcChannelV>() * channel_range<DstChannelV>());
149  }
150 private:
151  template <typename C>
152  static double channel_range() {
153  return double(channel_traits<C>::max_value()) - double(channel_traits<C>::min_value());
154  }
155 };
156 
157 // When both the source and the destination are integral channels, perform a faster conversion
158 template <typename SrcChannelV, typename DstChannelV>
159 struct channel_converter_unsigned_impl<SrcChannelV,DstChannelV,true,true>
160  : public channel_converter_unsigned_integral<SrcChannelV,DstChannelV,
161  mpl::less<unsigned_integral_max_value<SrcChannelV>,unsigned_integral_max_value<DstChannelV> >::value > {};
162 
163 
167 
168 template <typename SrcChannelV, typename DstChannelV>
169 struct channel_converter_unsigned_integral<SrcChannelV,DstChannelV,true>
170  : public channel_converter_unsigned_integral_impl<SrcChannelV,DstChannelV,true,
171  !(unsigned_integral_max_value<DstChannelV>::value % unsigned_integral_max_value<SrcChannelV>::value) > {};
172 
173 template <typename SrcChannelV, typename DstChannelV>
174 struct channel_converter_unsigned_integral<SrcChannelV,DstChannelV,false>
175  : public channel_converter_unsigned_integral_impl<SrcChannelV,DstChannelV,false,
176  !(unsigned_integral_max_value<SrcChannelV>::value % unsigned_integral_max_value<DstChannelV>::value) > {};
177 
178 
182 
183 // Both source and destination are unsigned integral channels,
184 // the src max value is less than the dst max value,
185 // and the dst max value is divisible by the src max value
186 template <typename SrcChannelV, typename DstChannelV>
187 struct channel_converter_unsigned_integral_impl<SrcChannelV,DstChannelV,true,true> {
188  DstChannelV operator()(SrcChannelV src) const {
189  typedef typename unsigned_integral_max_value<DstChannelV>::value_type integer_t;
190  static const integer_t mul = unsigned_integral_max_value<DstChannelV>::value / unsigned_integral_max_value<SrcChannelV>::value;
191  return DstChannelV(src * mul);
192  }
193 };
194 
195 // Both source and destination are unsigned integral channels,
196 // the dst max value is less than (or equal to) the src max value,
197 // and the src max value is divisible by the dst max value
198 template <typename SrcChannelV, typename DstChannelV>
199 struct channel_converter_unsigned_integral_impl<SrcChannelV,DstChannelV,false,true> {
200  DstChannelV operator()(SrcChannelV src) const {
201  typedef typename unsigned_integral_max_value<SrcChannelV>::value_type integer_t;
202  static const integer_t div = unsigned_integral_max_value<SrcChannelV>::value / unsigned_integral_max_value<DstChannelV>::value;
203  static const integer_t div2 = div/2;
204  return DstChannelV((src + div2) / div);
205  }
206 };
207 
208 // Prevent overflow for the largest integral type
209 template <typename DstChannelV>
210 struct channel_converter_unsigned_integral_impl<uintmax_t,DstChannelV,false,true> {
211  DstChannelV operator()(uintmax_t src) const {
212  static const uintmax_t div = unsigned_integral_max_value<uint32_t>::value / unsigned_integral_max_value<DstChannelV>::value;
213  static const uintmax_t div2 = div/2;
214  if (src > unsigned_integral_max_value<uintmax_t>::value - div2)
215  return unsigned_integral_max_value<DstChannelV>::value;
216  return DstChannelV((src + div2) / div);
217  }
218 };
219 
220 // Both source and destination are unsigned integral channels,
221 // and the dst max value is not divisible by the src max value
222 // See if you can represent the expression (src * dst_max) / src_max in integral form
223 template <typename SrcChannelV, typename DstChannelV, bool SrcLessThanDst>
224 struct channel_converter_unsigned_integral_impl<SrcChannelV,DstChannelV,SrcLessThanDst,false>
225  : public channel_converter_unsigned_integral_nondivisible<SrcChannelV,DstChannelV,SrcLessThanDst,
226  mpl::greater<
227  mpl::plus<unsigned_integral_num_bits<SrcChannelV>,unsigned_integral_num_bits<DstChannelV> >,
228  unsigned_integral_num_bits<uintmax_t>
229  >::value> {};
230 
231 
232 // Both source and destination are unsigned integral channels,
233 // the src max value is less than the dst max value,
234 // and the dst max value is not divisible by the src max value
235 // The expression (src * dst_max) / src_max fits in an integer
236 template <typename SrcChannelV, typename DstChannelV>
237 struct channel_converter_unsigned_integral_nondivisible<SrcChannelV,DstChannelV,true,false> {
238  DstChannelV operator()(SrcChannelV src) const {
239  typedef typename base_channel_type<DstChannelV>::type dest_t;
240  return DstChannelV(static_cast<dest_t>( src * unsigned_integral_max_value<DstChannelV>::value) / unsigned_integral_max_value<SrcChannelV>::value);
241  }
242 };
243 
244 // Both source and destination are unsigned integral channels,
245 // the src max value is less than the dst max value,
246 // and the dst max value is not divisible by the src max value
247 // The expression (src * dst_max) / src_max cannot fit in an integer (overflows). Use a double
248 template <typename SrcChannelV, typename DstChannelV>
249 struct channel_converter_unsigned_integral_nondivisible<SrcChannelV,DstChannelV,true,true> {
250  DstChannelV operator()(SrcChannelV src) const {
251  static const double mul = unsigned_integral_max_value<DstChannelV>::value / double(unsigned_integral_max_value<SrcChannelV>::value);
252  return DstChannelV(src * mul);
253  }
254 };
255 
256 // Both source and destination are unsigned integral channels,
257 // the dst max value is less than (or equal to) the src max value,
258 // and the src max value is not divisible by the dst max value
259 template <typename SrcChannelV, typename DstChannelV, bool CannotFit>
260 struct channel_converter_unsigned_integral_nondivisible<SrcChannelV,DstChannelV,false,CannotFit> {
261  DstChannelV operator()(SrcChannelV src) const {
262 
263  typedef typename detail::unsigned_integral_max_value< SrcChannelV >::value_type src_integer_t;
264  typedef typename detail::unsigned_integral_max_value< DstChannelV >::value_type dst_integer_t;
265 
266  static const double div = unsigned_integral_max_value<SrcChannelV>::value
267  / static_cast< double >( unsigned_integral_max_value<DstChannelV>::value );
268 
269  static const src_integer_t div2 = static_cast< src_integer_t >( div / 2.0 );
270 
271  return DstChannelV( static_cast< dst_integer_t >(( static_cast< double >( src + div2 ) / div )));
272  }
273 };
274 
275 } // namespace detail
276 
280 
281 template <typename DstChannelV> struct channel_converter_unsigned<float32_t,DstChannelV> {
282  typedef float32_t argument_type;
283  typedef DstChannelV result_type;
284  DstChannelV operator()(float32_t x) const
285  {
286  typedef typename detail::unsigned_integral_max_value< DstChannelV >::value_type dst_integer_t;
287  return DstChannelV( static_cast< dst_integer_t >(x*channel_traits<DstChannelV>::max_value()+0.5f ));
288  }
289 };
290 
291 template <typename SrcChannelV> struct channel_converter_unsigned<SrcChannelV,float32_t> {
292  typedef float32_t argument_type;
293  typedef SrcChannelV result_type;
294  float32_t operator()(SrcChannelV x) const { return float32_t(x/float(channel_traits<SrcChannelV>::max_value())); }
295 };
296 
297 template <> struct channel_converter_unsigned<float32_t,float32_t> {
298  typedef float32_t argument_type;
299  typedef float32_t result_type;
300  float32_t operator()(float32_t x) const { return x; }
301 };
302 
303 
305 template <> struct channel_converter_unsigned<uint32_t,float32_t> {
306  typedef uint32_t argument_type;
307  typedef float32_t result_type;
308  float32_t operator()(uint32_t x) const {
309  // 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
310  if (x>=channel_traits<uint32_t>::max_value()) return channel_traits<float32_t>::max_value();
311  return float(x) / float(channel_traits<uint32_t>::max_value());
312  }
313 };
315 template <> struct channel_converter_unsigned<float32_t,uint32_t> {
316  typedef float32_t argument_type;
317  typedef uint32_t result_type;
318  uint32_t operator()(float32_t x) const {
319  // 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
322 
323  auto const max_value = channel_traits<uint32_t>::max_value();
324  auto const result = x * static_cast<float32_t::base_channel_t>(max_value) + 0.5f;
325  return static_cast<uint32_t>(result);
326  }
327 };
328 
330 
331 namespace detail {
332 // Converting from signed to unsigned integral channel.
333 // It is both a unary function, and a metafunction (thus requires the 'type' nested typedef, which equals result_type)
334 template <typename ChannelValue> // Model ChannelValueConcept
335 struct channel_convert_to_unsigned : public detail::identity<ChannelValue> {
336  typedef ChannelValue type;
337 };
338 
339 template <> struct channel_convert_to_unsigned<int8_t> {
340  typedef int8_t argument_type;
341  typedef uint8_t result_type;
342  typedef uint8_t type;
343  type operator()(int8_t val) const {
344  return static_cast<uint8_t>(static_cast<uint32_t>(val) + 128u);
345  }
346 };
347 
348 template <> struct channel_convert_to_unsigned<int16_t> {
349  typedef int16_t argument_type;
350  typedef uint16_t result_type;
351  typedef uint16_t type;
352  type operator()(int16_t val) const {
353  return static_cast<uint16_t>(static_cast<uint32_t>(val) + 32768u);
354  }
355 };
356 
357 template <> struct channel_convert_to_unsigned<int32_t> {
358  typedef int32_t argument_type;
359  typedef uint32_t result_type;
360  typedef uint32_t type;
361  type operator()(int32_t val) const {
362  return static_cast<uint32_t>(val)+(1u<<31);
363  }
364 };
365 
366 
367 // Converting from unsigned to signed integral channel
368 // It is both a unary function, and a metafunction (thus requires the 'type' nested typedef, which equals result_type)
369 template <typename ChannelValue> // Model ChannelValueConcept
370 struct channel_convert_from_unsigned : public detail::identity<ChannelValue> {
371  typedef ChannelValue type;
372 };
373 
374 template <> struct channel_convert_from_unsigned<int8_t> {
375  typedef uint8_t argument_type;
376  typedef int8_t result_type;
377  typedef int8_t type;
378  type operator()(uint8_t val) const {
379  return static_cast<int8_t>(static_cast<int32_t>(val) - 128);
380  }
381 };
382 
383 template <> struct channel_convert_from_unsigned<int16_t> {
384  typedef uint16_t argument_type;
385  typedef int16_t result_type;
386  typedef int16_t type;
387  type operator()(uint16_t val) const {
388  return static_cast<int16_t>(static_cast<int32_t>(val) - 32768);
389  }
390 };
391 
392 template <> struct channel_convert_from_unsigned<int32_t> {
393  typedef uint32_t argument_type;
394  typedef int32_t result_type;
395  typedef int32_t type;
396  type operator()(uint32_t val) const {
397  return static_cast<int32_t>(val - (1u<<31));
398  }
399 };
400 
401 } // namespace detail
402 
405 template <typename SrcChannelV, typename DstChannelV> // Model ChannelValueConcept
407  typedef SrcChannelV argument_type;
408  typedef DstChannelV result_type;
409  DstChannelV operator()(const SrcChannelV& src) const {
410  typedef detail::channel_convert_to_unsigned<SrcChannelV> to_unsigned;
411  typedef detail::channel_convert_from_unsigned<DstChannelV> from_unsigned;
412  typedef channel_converter_unsigned<typename to_unsigned::result_type, typename from_unsigned::argument_type> converter_unsigned;
413  return from_unsigned()(converter_unsigned()(to_unsigned()(src)));
414  }
415 };
416 
419 template <typename DstChannel, typename SrcChannel> // Model ChannelConcept (could be channel references)
420 inline typename channel_traits<DstChannel>::value_type channel_convert(const SrcChannel& src) {
423 }
424 
430  template <typename Ch1, typename Ch2>
431  void operator()(const Ch1& src, Ch2& dst) const {
432  dst=channel_convert<Ch2>(src);
433  }
434 };
435 
436 namespace detail {
437  // fast integer division by 255
438  inline uint32_t div255(uint32_t in) { uint32_t tmp=in+128; return (tmp + (tmp>>8))>>8; }
439 
440  // fast integer divison by 32768
441  inline uint32_t div32768(uint32_t in) { return (in+16384)>>15; }
442 }
443 
457 
460 template <typename ChannelValue>
462  typedef ChannelValue first_argument_type;
463  typedef ChannelValue second_argument_type;
464  typedef ChannelValue result_type;
465  ChannelValue operator()(ChannelValue a, ChannelValue b) const {
466  return ChannelValue(static_cast<typename base_channel_type<ChannelValue>::type>(a / double(channel_traits<ChannelValue>::max_value()) * b));
467  }
468 };
469 
471 template<> struct channel_multiplier_unsigned<uint8_t> {
472  typedef uint8_t first_argument_type;
473  typedef uint8_t second_argument_type;
474  typedef uint8_t result_type;
475  uint8_t operator()(uint8_t a, uint8_t b) const { return uint8_t(detail::div255(uint32_t(a) * uint32_t(b))); }
476 };
477 
479 template<> struct channel_multiplier_unsigned<uint16_t> {
480  typedef uint16_t first_argument_type;
481  typedef uint16_t second_argument_type;
482  typedef uint16_t result_type;
483  uint16_t operator()(uint16_t a, uint16_t b) const { return uint16_t((uint32_t(a) * uint32_t(b))/65535); }
484 };
485 
490  typedef float32_t result_type;
491  float32_t operator()(float32_t a, float32_t b) const { return a*b; }
492 };
493 
495 template <typename ChannelValue>
497  typedef ChannelValue first_argument_type;
498  typedef ChannelValue second_argument_type;
499  typedef ChannelValue result_type;
500  ChannelValue operator()(ChannelValue a, ChannelValue b) const {
501  typedef detail::channel_convert_to_unsigned<ChannelValue> to_unsigned;
502  typedef detail::channel_convert_from_unsigned<ChannelValue> from_unsigned;
504  return from_unsigned()(multiplier_unsigned()(to_unsigned()(a), to_unsigned()(b)));
505  }
506 };
507 
509 template <typename Channel> // Models ChannelConcept (could be a channel reference)
510 inline typename channel_traits<Channel>::value_type channel_multiply(Channel a, Channel b) {
512 }
514 
529 template <typename Channel> // Models ChannelConcept (could be a channel reference)
533 
534  using base_t = typename base_channel_type<Channel>::type;
535  using promoted_t = typename promote_integral<base_t>::type;
536  promoted_t const promoted_x = x;
537  promoted_t const promoted_max = channel_traits<Channel>::max_value();
538  promoted_t const promoted_min = channel_traits<Channel>::min_value();
539  promoted_t const promoted_inverted_x = promoted_max - promoted_x + promoted_min;
540  auto const inverted_x = static_cast<base_t>(promoted_inverted_x);
541  return inverted_x;
542 }
543 
544 //#ifdef _MSC_VER
545 //#pragma warning(pop)
546 //#endif
547 
548 } } // namespace boost::gil
549 
550 #endif
channel_traits< Channel >::value_type channel_invert(Channel x)
Default implementation. Provide overloads for performance.
Definition: channel_algorithm.hpp:532
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:420
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:510
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:429
A function object to multiply two channels. result = a * b / max_value.
Definition: channel_algorithm.hpp:496
Useful public typedefs.
This is the default implementation. Performance specializatons are provided.
Definition: channel_algorithm.hpp:461
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:49
A unary function object converting between channel types.
Definition: channel_algorithm.hpp:406