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