]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/gil/channel_algorithm.hpp
import new upstream nautilus stable release 14.2.8
[ceph.git] / ceph / src / boost / 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
37 //////////////////////////////////////
38 //// unsigned_integral_max_value - given an unsigned integral channel type,
39 //// returns its maximum value as an integral constant
40 //////////////////////////////////////
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
75 //////////////////////////////////////
76 //// unsigned_integral_num_bits - given an unsigned integral channel type,
77 //// returns the minimum number of bits needed to represent it
78 //////////////////////////////////////
79
80 template <typename UnsignedIntegralChannel>
81 struct unsigned_integral_num_bits
82 : std::integral_constant<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
92 /// \defgroup ChannelConvertAlgorithm channel_convert
93 /// \brief Converting from one channel type to another
94 /// \ingroup ChannelAlgorithm
95 ///
96 /// Conversion is done as a simple linear mapping of one channel range to the other,
97 /// such that the minimum/maximum value of the source maps to the minimum/maximum value of the destination.
98 /// One implication of this is that the value 0 of signed channels may not be preserved!
99 ///
100 /// When creating new channel models, it is often a good idea to provide specializations for the channel conversion algorithms, for
101 /// example, for performance optimizations. If the new model is an integral type that can be signed, it is easier to define the conversion
102 /// only for the unsigned type (\p channel_converter_unsigned) and provide specializations of \p detail::channel_convert_to_unsigned
103 /// and \p detail::channel_convert_from_unsigned to convert between the signed and unsigned type.
104 ///
105 /// Example:
106 /// \code
107 /// // float32_t is a floating point channel with range [0.0f ... 1.0f]
108 /// float32_t src_channel = channel_traits<float32_t>::max_value();
109 /// assert(src_channel == 1);
110 ///
111 /// // uint8_t is 8-bit unsigned integral channel (aliased from unsigned char)
112 /// uint8_t dst_channel = channel_convert<uint8_t>(src_channel);
113 /// assert(dst_channel == 255); // max value goes to max value
114 /// \endcode
115
116 ///
117 /// \defgroup ChannelConvertUnsignedAlgorithm channel_converter_unsigned
118 /// \ingroup ChannelConvertAlgorithm
119 /// \brief Convert one unsigned/floating point channel to another. Converts both the channel type and range
120 /// @{
121
122 //////////////////////////////////////
123 //// channel_converter_unsigned
124 //////////////////////////////////////
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
137 /// \brief Converting a channel to itself - identity operation
138 template <typename T> struct channel_converter_unsigned<T,T> : public detail::identity<T> {};
139
140 namespace detail {
141
142 //////////////////////////////////////
143 //// channel_converter_unsigned_impl
144 //////////////////////////////////////
145
146 /// \brief This is the default implementation. Performance specializatons are provided
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 DstChannelV operator()(SrcChannelV src) const {
152 return DstChannelV(channel_traits<DstChannelV>::min_value() +
153 (src - channel_traits<SrcChannelV>::min_value()) / channel_range<SrcChannelV>() * channel_range<DstChannelV>());
154 }
155 private:
156 template <typename C>
157 static double channel_range() {
158 return double(channel_traits<C>::max_value()) - double(channel_traits<C>::min_value());
159 }
160 };
161
162 // When both the source and the destination are integral channels, perform a faster conversion
163 template <typename SrcChannelV, typename DstChannelV>
164 struct channel_converter_unsigned_impl<SrcChannelV, DstChannelV, true, true>
165 : channel_converter_unsigned_integral
166 <
167 SrcChannelV,
168 DstChannelV,
169 mp11::mp_less
170 <
171 unsigned_integral_max_value<SrcChannelV>,
172 unsigned_integral_max_value<DstChannelV>
173 >::value
174 >
175 {};
176
177 //////////////////////////////////////
178 //// channel_converter_unsigned_integral
179 //////////////////////////////////////
180
181 template <typename SrcChannelV, typename DstChannelV>
182 struct channel_converter_unsigned_integral<SrcChannelV,DstChannelV,true>
183 : public channel_converter_unsigned_integral_impl<SrcChannelV,DstChannelV,true,
184 !(unsigned_integral_max_value<DstChannelV>::value % unsigned_integral_max_value<SrcChannelV>::value) > {};
185
186 template <typename SrcChannelV, typename DstChannelV>
187 struct channel_converter_unsigned_integral<SrcChannelV,DstChannelV,false>
188 : public channel_converter_unsigned_integral_impl<SrcChannelV,DstChannelV,false,
189 !(unsigned_integral_max_value<SrcChannelV>::value % unsigned_integral_max_value<DstChannelV>::value) > {};
190
191
192 //////////////////////////////////////
193 //// channel_converter_unsigned_integral_impl
194 //////////////////////////////////////
195
196 // Both source and destination are unsigned integral channels,
197 // the src max value is less than the dst max value,
198 // and the dst max value is divisible by the src max value
199 template <typename SrcChannelV, typename DstChannelV>
200 struct channel_converter_unsigned_integral_impl<SrcChannelV,DstChannelV,true,true> {
201 DstChannelV operator()(SrcChannelV src) const {
202 using integer_t = typename unsigned_integral_max_value<DstChannelV>::value_type;
203 static const integer_t mul = unsigned_integral_max_value<DstChannelV>::value / unsigned_integral_max_value<SrcChannelV>::value;
204 return DstChannelV(src * mul);
205 }
206 };
207
208 // Both source and destination are unsigned integral channels,
209 // the dst max value is less than (or equal to) the src max value,
210 // and the src max value is divisible by the dst max value
211 template <typename SrcChannelV, typename DstChannelV>
212 struct channel_converter_unsigned_integral_impl<SrcChannelV,DstChannelV,false,true> {
213 DstChannelV operator()(SrcChannelV src) const {
214 using integer_t = typename unsigned_integral_max_value<SrcChannelV>::value_type;
215 static const integer_t div = unsigned_integral_max_value<SrcChannelV>::value / unsigned_integral_max_value<DstChannelV>::value;
216 static const integer_t div2 = div/2;
217 return DstChannelV((src + div2) / div);
218 }
219 };
220
221 // Prevent overflow for the largest integral type
222 template <typename DstChannelV>
223 struct channel_converter_unsigned_integral_impl<uintmax_t,DstChannelV,false,true> {
224 DstChannelV operator()(uintmax_t src) const {
225 static const uintmax_t div = unsigned_integral_max_value<uint32_t>::value / unsigned_integral_max_value<DstChannelV>::value;
226 static const uintmax_t div2 = div/2;
227 if (src > unsigned_integral_max_value<uintmax_t>::value - div2)
228 return unsigned_integral_max_value<DstChannelV>::value;
229 return DstChannelV((src + div2) / div);
230 }
231 };
232
233 // Both source and destination are unsigned integral channels,
234 // and the dst max value is not divisible by the src max value
235 // See if you can represent the expression (src * dst_max) / src_max in integral form
236 template <typename SrcChannelV, typename DstChannelV, bool SrcLessThanDst>
237 struct channel_converter_unsigned_integral_impl<SrcChannelV, DstChannelV, SrcLessThanDst, false>
238 : channel_converter_unsigned_integral_nondivisible
239 <
240 SrcChannelV,
241 DstChannelV,
242 SrcLessThanDst,
243 mp11::mp_less
244 <
245 unsigned_integral_num_bits<uintmax_t>,
246 mp11::mp_plus
247 <
248 unsigned_integral_num_bits<SrcChannelV>,
249 unsigned_integral_num_bits<DstChannelV>
250 >
251 >::value
252 >
253 {};
254
255 // Both source and destination are unsigned integral channels,
256 // the src max value is less than the dst max value,
257 // and the dst max value is not divisible by the src max value
258 // The expression (src * dst_max) / src_max fits in an integer
259 template <typename SrcChannelV, typename DstChannelV>
260 struct channel_converter_unsigned_integral_nondivisible<SrcChannelV, DstChannelV, true, false>
261 {
262 DstChannelV operator()(SrcChannelV src) const
263 {
264 using dest_t = typename base_channel_type<DstChannelV>::type;
265 return DstChannelV(
266 static_cast<dest_t>(src * unsigned_integral_max_value<DstChannelV>::value)
267 / unsigned_integral_max_value<SrcChannelV>::value);
268 }
269 };
270
271 // Both source and destination are unsigned integral channels,
272 // the src max value is less than the dst max value,
273 // and the dst max value is not divisible by the src max value
274 // The expression (src * dst_max) / src_max cannot fit in an integer (overflows). Use a double
275 template <typename SrcChannelV, typename DstChannelV>
276 struct channel_converter_unsigned_integral_nondivisible<SrcChannelV, DstChannelV, true, true>
277 {
278 DstChannelV operator()(SrcChannelV src) const
279 {
280 static const double mul
281 = unsigned_integral_max_value<DstChannelV>::value
282 / double(unsigned_integral_max_value<SrcChannelV>::value);
283 return DstChannelV(src * mul);
284 }
285 };
286
287 // Both source and destination are unsigned integral channels,
288 // the dst max value is less than (or equal to) the src max value,
289 // and the src max value is not divisible by the dst max value
290 template <typename SrcChannelV, typename DstChannelV, bool CannotFit>
291 struct channel_converter_unsigned_integral_nondivisible<SrcChannelV,DstChannelV,false,CannotFit> {
292 DstChannelV operator()(SrcChannelV src) const {
293
294 using src_integer_t = typename detail::unsigned_integral_max_value<SrcChannelV>::value_type;
295 using dst_integer_t = typename detail::unsigned_integral_max_value<DstChannelV>::value_type;
296
297 static const double div = unsigned_integral_max_value<SrcChannelV>::value
298 / static_cast< double >( unsigned_integral_max_value<DstChannelV>::value );
299
300 static const src_integer_t div2 = static_cast< src_integer_t >( div / 2.0 );
301
302 return DstChannelV( static_cast< dst_integer_t >(( static_cast< double >( src + div2 ) / div )));
303 }
304 };
305
306 } // namespace detail
307
308 /////////////////////////////////////////////////////
309 /// float32_t conversion
310 /////////////////////////////////////////////////////
311
312 template <typename DstChannelV> struct channel_converter_unsigned<float32_t,DstChannelV> {
313 using argument_type = float32_t;
314 using result_type = DstChannelV;
315 DstChannelV operator()(float32_t x) const
316 {
317 using dst_integer_t = typename detail::unsigned_integral_max_value<DstChannelV>::value_type;
318 return DstChannelV( static_cast< dst_integer_t >(x*channel_traits<DstChannelV>::max_value()+0.5f ));
319 }
320 };
321
322 template <typename SrcChannelV> struct channel_converter_unsigned<SrcChannelV,float32_t> {
323 using argument_type = float32_t;
324 using result_type = SrcChannelV;
325 float32_t operator()(SrcChannelV x) const { return float32_t(x/float(channel_traits<SrcChannelV>::max_value())); }
326 };
327
328 template <> struct channel_converter_unsigned<float32_t,float32_t> {
329 using argument_type = float32_t;
330 using result_type = float32_t;
331 float32_t operator()(float32_t x) const { return x; }
332 };
333
334
335 /// \brief 32 bit <-> float channel conversion
336 template <> struct channel_converter_unsigned<uint32_t,float32_t> {
337 using argument_type = uint32_t;
338 using result_type = float32_t;
339 float32_t operator()(uint32_t x) const {
340 // 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
341 if (x>=channel_traits<uint32_t>::max_value()) return channel_traits<float32_t>::max_value();
342 return float(x) / float(channel_traits<uint32_t>::max_value());
343 }
344 };
345 /// \brief 32 bit <-> float channel conversion
346 template <> struct channel_converter_unsigned<float32_t,uint32_t> {
347 using argument_type = float32_t;
348 using result_type = uint32_t;
349 uint32_t operator()(float32_t x) const {
350 // 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
351 if (x>=channel_traits<float32_t>::max_value())
352 return channel_traits<uint32_t>::max_value();
353
354 auto const max_value = channel_traits<uint32_t>::max_value();
355 auto const result = x * static_cast<float32_t::base_channel_t>(max_value) + 0.5f;
356 return static_cast<uint32_t>(result);
357 }
358 };
359
360 /// @}
361
362 namespace detail {
363 // Converting from signed to unsigned integral channel.
364 // It is both a unary function, and a metafunction (thus requires the 'type' nested alias, which equals result_type)
365 template <typename ChannelValue> // Model ChannelValueConcept
366 struct channel_convert_to_unsigned : public detail::identity<ChannelValue> {
367 using type = ChannelValue;
368 };
369
370 template <> struct channel_convert_to_unsigned<int8_t> {
371 using argument_type = int8_t;
372 using result_type = uint8_t;
373 using type = uint8_t;
374 type operator()(int8_t val) const {
375 return static_cast<uint8_t>(static_cast<uint32_t>(val) + 128u);
376 }
377 };
378
379 template <> struct channel_convert_to_unsigned<int16_t> {
380 using argument_type = int16_t;
381 using result_type = uint16_t;
382 using type = uint16_t;
383 type operator()(int16_t val) const {
384 return static_cast<uint16_t>(static_cast<uint32_t>(val) + 32768u);
385 }
386 };
387
388 template <> struct channel_convert_to_unsigned<int32_t> {
389 using argument_type = int32_t;
390 using result_type = uint32_t;
391 using type = uint32_t;
392 type operator()(int32_t val) const {
393 return static_cast<uint32_t>(val)+(1u<<31);
394 }
395 };
396
397
398 // Converting from unsigned to signed integral channel
399 // It is both a unary function, and a metafunction (thus requires the 'type' nested alias, which equals result_type)
400 template <typename ChannelValue> // Model ChannelValueConcept
401 struct channel_convert_from_unsigned : public detail::identity<ChannelValue> {
402 using type = ChannelValue;
403 };
404
405 template <> struct channel_convert_from_unsigned<int8_t> {
406 using argument_type = uint8_t;
407 using result_type = int8_t;
408 using type = int8_t;
409 type operator()(uint8_t val) const {
410 return static_cast<int8_t>(static_cast<int32_t>(val) - 128);
411 }
412 };
413
414 template <> struct channel_convert_from_unsigned<int16_t> {
415 using argument_type = uint16_t;
416 using result_type = int16_t;
417 using type = int16_t;
418 type operator()(uint16_t val) const {
419 return static_cast<int16_t>(static_cast<int32_t>(val) - 32768);
420 }
421 };
422
423 template <> struct channel_convert_from_unsigned<int32_t> {
424 using argument_type = uint32_t;
425 using result_type = int32_t;
426 using type = int32_t;
427 type operator()(uint32_t val) const {
428 return static_cast<int32_t>(val - (1u<<31));
429 }
430 };
431
432 } // namespace detail
433
434 /// \ingroup ChannelConvertAlgorithm
435 /// \brief A unary function object converting between channel types
436 template <typename SrcChannelV, typename DstChannelV> // Model ChannelValueConcept
437 struct channel_converter {
438 using argument_type = SrcChannelV;
439 using result_type = DstChannelV;
440 DstChannelV operator()(const SrcChannelV& src) const {
441 using to_unsigned = detail::channel_convert_to_unsigned<SrcChannelV>;
442 using from_unsigned = detail::channel_convert_from_unsigned<DstChannelV>;
443 using converter_unsigned = channel_converter_unsigned<typename to_unsigned::result_type, typename from_unsigned::argument_type>;
444 return from_unsigned()(converter_unsigned()(to_unsigned()(src)));
445 }
446 };
447
448 /// \ingroup ChannelConvertAlgorithm
449 /// \brief Converting from one channel type to another.
450 template <typename DstChannel, typename SrcChannel> // Model ChannelConcept (could be channel references)
451 inline typename channel_traits<DstChannel>::value_type channel_convert(const SrcChannel& src) {
452 return channel_converter<typename channel_traits<SrcChannel>::value_type,
453 typename channel_traits<DstChannel>::value_type>()(src);
454 }
455
456 /// \ingroup ChannelConvertAlgorithm
457 /// \brief Same as channel_converter, except it takes the destination channel by reference, which allows
458 /// us to move the templates from the class level to the method level. This is important when invoking it
459 /// on heterogeneous pixels.
460 struct default_channel_converter {
461 template <typename Ch1, typename Ch2>
462 void operator()(const Ch1& src, Ch2& dst) const {
463 dst=channel_convert<Ch2>(src);
464 }
465 };
466
467 namespace detail {
468 // fast integer division by 255
469 inline uint32_t div255(uint32_t in) { uint32_t tmp=in+128; return (tmp + (tmp>>8))>>8; }
470
471 // fast integer divison by 32768
472 inline uint32_t div32768(uint32_t in) { return (in+16384)>>15; }
473 }
474
475 /// \defgroup ChannelMultiplyAlgorithm channel_multiply
476 /// \ingroup ChannelAlgorithm
477 /// \brief Multiplying unsigned channel values of the same type. Performs scaled multiplication result = a * b / max_value
478 ///
479 /// Example:
480 /// \code
481 /// uint8_t x=128;
482 /// uint8_t y=128;
483 /// uint8_t mul = channel_multiply(x,y);
484 /// assert(mul == 64); // 64 = 128 * 128 / 255
485 /// \endcode
486 /// @{
487
488 /// \brief This is the default implementation. Performance specializatons are provided
489 template <typename ChannelValue>
490 struct channel_multiplier_unsigned {
491 using first_argument_type = ChannelValue;
492 using second_argument_type = ChannelValue;
493 using result_type = ChannelValue;
494 ChannelValue operator()(ChannelValue a, ChannelValue b) const {
495 return ChannelValue(static_cast<typename base_channel_type<ChannelValue>::type>(a / double(channel_traits<ChannelValue>::max_value()) * b));
496 }
497 };
498
499 /// \brief Specialization of channel_multiply for 8-bit unsigned channels
500 template<> struct channel_multiplier_unsigned<uint8_t> {
501 using first_argument_type = uint8_t;
502 using second_argument_type = uint8_t;
503 using result_type = uint8_t;
504 uint8_t operator()(uint8_t a, uint8_t b) const { return uint8_t(detail::div255(uint32_t(a) * uint32_t(b))); }
505 };
506
507 /// \brief Specialization of channel_multiply for 16-bit unsigned channels
508 template<> struct channel_multiplier_unsigned<uint16_t> {
509 using first_argument_type = uint16_t;
510 using second_argument_type = uint16_t;
511 using result_type = uint16_t;
512 uint16_t operator()(uint16_t a, uint16_t b) const { return uint16_t((uint32_t(a) * uint32_t(b))/65535); }
513 };
514
515 /// \brief Specialization of channel_multiply for float 0..1 channels
516 template<> struct channel_multiplier_unsigned<float32_t> {
517 using first_argument_type = float32_t;
518 using second_argument_type = float32_t;
519 using result_type = float32_t;
520 float32_t operator()(float32_t a, float32_t b) const { return a*b; }
521 };
522
523 /// \brief A function object to multiply two channels. result = a * b / max_value
524 template <typename ChannelValue>
525 struct channel_multiplier {
526 using first_argument_type = ChannelValue;
527 using second_argument_type = ChannelValue;
528 using result_type = ChannelValue;
529 ChannelValue operator()(ChannelValue a, ChannelValue b) const {
530 using to_unsigned = detail::channel_convert_to_unsigned<ChannelValue>;
531 using from_unsigned = detail::channel_convert_from_unsigned<ChannelValue>;
532 using multiplier_unsigned = channel_multiplier_unsigned<typename to_unsigned::result_type>;
533 return from_unsigned()(multiplier_unsigned()(to_unsigned()(a), to_unsigned()(b)));
534 }
535 };
536
537 /// \brief A function multiplying two channels. result = a * b / max_value
538 template <typename Channel> // Models ChannelConcept (could be a channel reference)
539 inline typename channel_traits<Channel>::value_type channel_multiply(Channel a, Channel b) {
540 return channel_multiplier<typename channel_traits<Channel>::value_type>()(a,b);
541 }
542 /// @}
543
544 /// \defgroup ChannelInvertAlgorithm channel_invert
545 /// \ingroup ChannelAlgorithm
546 /// \brief Returns the inverse of a channel. result = max_value - x + min_value
547 ///
548 /// Example:
549 /// \code
550 /// // uint8_t == uint8_t == unsigned char
551 /// uint8_t x=255;
552 /// uint8_t inv = channel_invert(x);
553 /// assert(inv == 0);
554 /// \endcode
555
556 /// \brief Default implementation. Provide overloads for performance
557 /// \ingroup ChannelInvertAlgorithm channel_invert
558 template <typename Channel> // Models ChannelConcept (could be a channel reference)
559 inline typename channel_traits<Channel>::value_type channel_invert(Channel x) {
560
561 using base_t = typename base_channel_type<Channel>::type;
562 using promoted_t = typename promote_integral<base_t>::type;
563 promoted_t const promoted_x = x;
564 promoted_t const promoted_max = channel_traits<Channel>::max_value();
565 promoted_t const promoted_min = channel_traits<Channel>::min_value();
566 promoted_t const promoted_inverted_x = promoted_max - promoted_x + promoted_min;
567 auto const inverted_x = static_cast<base_t>(promoted_inverted_x);
568 return inverted_x;
569 }
570
571 } } // namespace boost::gil
572
573 #endif