Generic Image Library: channel_algorithm.hpp Source File

###  | #  |

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
20namespace boost { namespace gil {
21
22namespace detail {
23
24// some forward declarations
25template <typename SrcChannelV, typename DstChannelV, bool SrcIsIntegral, bool DstIsIntegral>
26struct channel_converter_unsigned_impl;
27
28template <typename SrcChannelV, typename DstChannelV, bool SrcIsGreater>
29struct channel_converter_unsigned_integral;
30
31template <typename SrcChannelV, typename DstChannelV, bool SrcLessThanDst, bool SrcDivisible>
32struct channel_converter_unsigned_integral_impl;
33
34template <typename SrcChannelV, typename DstChannelV, bool SrcLessThanDst, bool CannotFitInInteger>
35struct channel_converter_unsigned_integral_nondivisible;
36
41
42template <typename UnsignedIntegralChannel>
43struct unsigned_integral_max_value
44 : std::integral_constant
45 <
46 UnsignedIntegralChannel,
47 (std::numeric_limits<UnsignedIntegralChannel>::max)()
48 >
49{};
50
51template <>
52struct unsigned_integral_max_value<uint8_t>
53 : std::integral_constant<uint32_t, 0xFF>
54{};
55
56template <>
57struct unsigned_integral_max_value<uint16_t>
58 : std::integral_constant<uint32_t, 0xFFFF>
59{};
60
61template <>
62struct unsigned_integral_max_value<uint32_t>
63 : std::integral_constant<uintmax_t, 0xFFFFFFFF>
64{};
65
66template <int K>
67struct 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
79
80template <typename UnsignedIntegralChannel>
81struct unsigned_integral_num_bits
82 : std::integral_constant<int, static_cast<int>(sizeof(UnsignedIntegralChannel) * 8)>
83{};
84
85template <int K>
86struct unsigned_integral_num_bits<packed_channel_value<K>>
87 : std::integral_constant<int, K>
88{};
89
90} // namespace detail
91
115
121
125
126template <typename SrcChannelV, typename DstChannelV> // Model ChannelValueConcept
127struct 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
138template <typename T> struct channel_converter_unsigned<T,T> : public detail::identity<T> {};
139
140namespace detail {
141
145
147template <typename SrcChannelV, typename DstChannelV, bool SrcIsIntegral, bool DstIsIntegral>
148struct channel_converter_unsigned_impl {
149 using argument_type = SrcChannelV;
150 using result_type = DstChannelV;
151 auto operator()(SrcChannelV src) const -> DstChannelV
152 {
153 return DstChannelV(channel_traits<DstChannelV>::min_value() +
154 (src - channel_traits<SrcChannelV>::min_value()) / channel_range<SrcChannelV>() * channel_range<DstChannelV>());
155 }
156
157private:
158 template <typename C>
159 static auto channel_range() -> double
160 {
161 return double(channel_traits<C>::max_value()) - double(channel_traits<C>::min_value());
162 }
163};
164
165// When both the source and the destination are integral channels, perform a faster conversion
166template <typename SrcChannelV, typename DstChannelV>
167struct channel_converter_unsigned_impl<SrcChannelV, DstChannelV, true, true>
168 : channel_converter_unsigned_integral
169 <
170 SrcChannelV,
171 DstChannelV,
172 mp11::mp_less
173 <
174 unsigned_integral_max_value<SrcChannelV>,
175 unsigned_integral_max_value<DstChannelV>
176 >::value
177 >
178{};
179
183
184template <typename SrcChannelV, typename DstChannelV>
185struct channel_converter_unsigned_integral<SrcChannelV,DstChannelV,true>
186 : public channel_converter_unsigned_integral_impl<SrcChannelV,DstChannelV,true,
187 !(unsigned_integral_max_value<DstChannelV>::value % unsigned_integral_max_value<SrcChannelV>::value) > {};
188
189template <typename SrcChannelV, typename DstChannelV>
190struct channel_converter_unsigned_integral<SrcChannelV,DstChannelV,false>
191 : public channel_converter_unsigned_integral_impl<SrcChannelV,DstChannelV,false,
192 !(unsigned_integral_max_value<SrcChannelV>::value % unsigned_integral_max_value<DstChannelV>::value) > {};
193
194
198
199// Both source and destination are unsigned integral channels,
200// the src max value is less than the dst max value,
201// and the dst max value is divisible by the src max value
202template <typename SrcChannelV, typename DstChannelV>
203struct channel_converter_unsigned_integral_impl<SrcChannelV,DstChannelV,true,true> {
204 auto operator()(SrcChannelV src) const -> DstChannelV
205 {
206 using integer_t = typename unsigned_integral_max_value<DstChannelV>::value_type;
207 static const integer_t mul = unsigned_integral_max_value<DstChannelV>::value / unsigned_integral_max_value<SrcChannelV>::value;
208 return DstChannelV(src * mul);
209 }
210};
211
212// Both source and destination are unsigned integral channels,
213// the dst max value is less than (or equal to) the src max value,
214// and the src max value is divisible by the dst max value
215template <typename SrcChannelV, typename DstChannelV>
216struct channel_converter_unsigned_integral_impl<SrcChannelV,DstChannelV,false,true> {
217 auto operator()(SrcChannelV src) const -> DstChannelV
218 {
219 using integer_t = typename unsigned_integral_max_value<SrcChannelV>::value_type;
220 static const integer_t div = unsigned_integral_max_value<SrcChannelV>::value / unsigned_integral_max_value<DstChannelV>::value;
221 static const integer_t div2 = div/2;
222 return DstChannelV((src + div2) / div);
223 }
224};
225
226// Prevent overflow for the largest integral type
227template <typename DstChannelV>
228struct channel_converter_unsigned_integral_impl<uintmax_t,DstChannelV,false,true> {
229 auto operator()(uintmax_t src) const -> DstChannelV
230 {
231 static const uintmax_t div = unsigned_integral_max_value<uint32_t>::value / unsigned_integral_max_value<DstChannelV>::value;
232 static const uintmax_t div2 = div/2;
233 if (src > unsigned_integral_max_value<uintmax_t>::value - div2)
234 return unsigned_integral_max_value<DstChannelV>::value;
235 return DstChannelV((src + div2) / div);
236 }
237};
238
239// Both source and destination are unsigned integral channels,
240// and the dst max value is not divisible by the src max value
241// See if you can represent the expression (src * dst_max) / src_max in integral form
242template <typename SrcChannelV, typename DstChannelV, bool SrcLessThanDst>
243struct channel_converter_unsigned_integral_impl<SrcChannelV, DstChannelV, SrcLessThanDst, false>
244 : channel_converter_unsigned_integral_nondivisible
245 <
246 SrcChannelV,
247 DstChannelV,
248 SrcLessThanDst,
249 mp11::mp_less
250 <
251 unsigned_integral_num_bits<uintmax_t>,
252 mp11::mp_plus
253 <
254 unsigned_integral_num_bits<SrcChannelV>,
255 unsigned_integral_num_bits<DstChannelV>
256 >
257 >::value
258 >
259{};
260
261// Both source and destination are unsigned integral channels,
262// the src max value is less than the dst max value,
263// and the dst max value is not divisible by the src max value
264// The expression (src * dst_max) / src_max fits in an integer
265template <typename SrcChannelV, typename DstChannelV>
266struct channel_converter_unsigned_integral_nondivisible<SrcChannelV, DstChannelV, true, false>
267{
268 auto operator()(SrcChannelV src) const -> DstChannelV
269 {
270 using dest_t = typename base_channel_type<DstChannelV>::type;
271 return DstChannelV(
272 static_cast<dest_t>(src * unsigned_integral_max_value<DstChannelV>::value)
273 / unsigned_integral_max_value<SrcChannelV>::value);
274 }
275};
276
277// Both source and destination are unsigned integral channels,
278// the src max value is less than the dst max value,
279// and the dst max value is not divisible by the src max value
280// The expression (src * dst_max) / src_max cannot fit in an integer (overflows). Use a double
281template <typename SrcChannelV, typename DstChannelV>
282struct channel_converter_unsigned_integral_nondivisible<SrcChannelV, DstChannelV, true, true>
283{
284 auto operator()(SrcChannelV src) const -> DstChannelV
285 {
286 static const double mul
287 = unsigned_integral_max_value<DstChannelV>::value
288 / double(unsigned_integral_max_value<SrcChannelV>::value);
289 return DstChannelV(src * mul);
290 }
291};
292
293// Both source and destination are unsigned integral channels,
294// the dst max value is less than (or equal to) the src max value,
295// and the src max value is not divisible by the dst max value
296template <typename SrcChannelV, typename DstChannelV, bool CannotFit>
297struct channel_converter_unsigned_integral_nondivisible<SrcChannelV,DstChannelV,false,CannotFit>
298{
299 auto operator()(SrcChannelV src) const -> DstChannelV
300 {
301 using src_integer_t = typename detail::unsigned_integral_max_value<SrcChannelV>::value_type;
302 using dst_integer_t = typename detail::unsigned_integral_max_value<DstChannelV>::value_type;
303
304 static const double div = unsigned_integral_max_value<SrcChannelV>::value
305 / static_cast< double >( unsigned_integral_max_value<DstChannelV>::value );
306
307 static const src_integer_t div2 = static_cast< src_integer_t >( div / 2.0 );
308
309 return DstChannelV( static_cast< dst_integer_t >(( static_cast< double >( src + div2 ) / div )));
310 }
311};
312
313} // namespace detail
314
318
319 template <typename DstChannelV> struct channel_converter_unsigned<float32_t,DstChannelV> {
320 using argument_type = float32_t;
321 using result_type = DstChannelV;
322 auto operator()(float32_t x) const -> DstChannelV
323 {
324 using dst_integer_t = typename detail::unsigned_integral_max_value<DstChannelV>::value_type;
325 return DstChannelV( static_cast< dst_integer_t >(x*channel_traits<DstChannelV>::max_value()+0.5f ));
326 }
327};
328
329template <typename SrcChannelV> struct channel_converter_unsigned<SrcChannelV,float32_t> {
330 using argument_type = float32_t;
331 using result_type = SrcChannelV;
332 auto operator()(SrcChannelV x) const -> float32_t { return float32_t(x/float(channel_traits<SrcChannelV>::max_value())); }
333};
334
335template <> struct channel_converter_unsigned<float32_t,float32_t> {
336 using argument_type = float32_t;
337 using result_type = float32_t;
338 auto operator()(float32_t x) const -> float32_t { return x; }
339};
340
341
343 template <> struct channel_converter_unsigned<uint32_t,float32_t> {
344 using argument_type = uint32_t;
345 using result_type = float32_t;
346 auto operator()(uint32_t x) const -> float32_t
347 {
348 // 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
349 if (x>=channel_traits<uint32_t>::max_value()) return channel_traits<float32_t>::max_value();
350 return float(x) / float(channel_traits<uint32_t>::max_value());
351 }
352};
354 template <> struct channel_converter_unsigned<float32_t,uint32_t> {
355 using argument_type = float32_t;
356 using result_type = uint32_t;
357 auto operator()(float32_t x) const -> uint32_t
358 {
359 // 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
360 if (x>=channel_traits<float32_t>::max_value())
361 return channel_traits<uint32_t>::max_value();
362
363 auto const max_value = channel_traits<uint32_t>::max_value();
364 auto const result = x * static_cast<float32_t::base_channel_t>(max_value) + 0.5f;
365 return static_cast<uint32_t>(result);
366 }
367};
368
370
371namespace detail {
372// Converting from signed to unsigned integral channel.
373// It is both a unary function, and a metafunction (thus requires the 'type' nested alias, which equals result_type)
374template <typename ChannelValue> // Model ChannelValueConcept
375struct channel_convert_to_unsigned : public detail::identity<ChannelValue> {
376 using type = ChannelValue;
377};
378
379template <> struct channel_convert_to_unsigned<int8_t> {
380 using argument_type = int8_t;
381 using result_type = uint8_t;
382 using type = uint8_t;
383 type operator()(int8_t val) const {
384 return static_cast<uint8_t>(static_cast<uint32_t>(val) + 128u);
385 }
386};
387
388template <> struct channel_convert_to_unsigned<int16_t> {
389 using argument_type = int16_t;
390 using result_type = uint16_t;
391 using type = uint16_t;
392 type operator()(int16_t val) const {
393 return static_cast<uint16_t>(static_cast<uint32_t>(val) + 32768u);
394 }
395};
396
397template <> struct channel_convert_to_unsigned<int32_t> {
398 using argument_type = int32_t;
399 using result_type = uint32_t;
400 using type = uint32_t;
401 type operator()(int32_t val) const {
402 return static_cast<uint32_t>(val)+(1u<<31);
403 }
404};
405
406
407// Converting from unsigned to signed integral channel
408// It is both a unary function, and a metafunction (thus requires the 'type' nested alias, which equals result_type)
409template <typename ChannelValue> // Model ChannelValueConcept
410struct channel_convert_from_unsigned : public detail::identity<ChannelValue> {
411 using type = ChannelValue;
412};
413
414template <> struct channel_convert_from_unsigned<int8_t> {
415 using argument_type = uint8_t;
416 using result_type = int8_t;
417 using type = int8_t;
418 type operator()(uint8_t val) const {
419 return static_cast<int8_t>(static_cast<int32_t>(val) - 128);
420 }
421};
422
423template <> struct channel_convert_from_unsigned<int16_t> {
424 using argument_type = uint16_t;
425 using result_type = int16_t;
426 using type = int16_t;
427 type operator()(uint16_t val) const {
428 return static_cast<int16_t>(static_cast<int32_t>(val) - 32768);
429 }
430};
431
432template <> struct channel_convert_from_unsigned<int32_t> {
433 using argument_type = uint32_t;
434 using result_type = int32_t;
435 using type = int32_t;
436 type operator()(uint32_t val) const {
437 return static_cast<int32_t>(val - (1u<<31));
438 }
439};
440
441} // namespace detail
442
445template <typename SrcChannelV, typename DstChannelV> // Model ChannelValueConcept
446 struct channel_converter {
447 using argument_type = SrcChannelV;
448 using result_type = DstChannelV;
449 auto operator()(SrcChannelV const& src) const -> DstChannelV
450 {
451 using to_unsigned = detail::channel_convert_to_unsigned<SrcChannelV>;
452 using from_unsigned = detail::channel_convert_from_unsigned<DstChannelV>;
453 using converter_unsigned = channel_converter_unsigned<typename to_unsigned::result_type, typename from_unsigned::argument_type>;
454 return from_unsigned()(converter_unsigned()(to_unsigned()(src)));
455 }
456};
457
460template <typename DstChannel, typename SrcChannel> // Model ChannelConcept (could be channel references)
461 inline auto channel_convert(SrcChannel const& src) -> typename channel_traits<DstChannel>::value_type
462{
463 return channel_converter<typename channel_traits<SrcChannel>::value_type,
464 typename channel_traits<DstChannel>::value_type>()(src);
465}
466
471 struct default_channel_converter {
472 template <typename Ch1, typename Ch2>
473 void operator()(Ch1 const& src, Ch2& dst) const
474 {
475 dst=channel_convert<Ch2>(src);
476 }
477};
478
479namespace detail
480{
481 // fast integer division by 255
482 inline auto div255(uint32_t in) -> uint32_t
483 {
484 uint32_t tmp = in + 128;
485 return (tmp + (tmp >> 8)) >> 8;
486 }
487
488 // fast integer divison by 32768
489 inline auto div32768(uint32_t in) -> uint32_t
490 {
491 return (in + 16384) >> 15;
492 }
493}
494
507
509template <typename ChannelValue>
510 struct channel_multiplier_unsigned {
511 using first_argument_type = ChannelValue;
512 using second_argument_type = ChannelValue;
513 using result_type = ChannelValue;
514 auto operator()(ChannelValue a, ChannelValue b) const -> ChannelValue
515 {
516 return ChannelValue(static_cast<typename base_channel_type<ChannelValue>::type>(a / double(channel_traits<ChannelValue>::max_value()) * b));
517 }
518};
519
521 template<> struct channel_multiplier_unsigned<uint8_t> {
522 using first_argument_type = uint8_t;
523 using second_argument_type = uint8_t;
524 using result_type = uint8_t;
525 auto operator()(uint8_t a, uint8_t b) const -> uint8_t { return uint8_t(detail::div255(uint32_t(a) * uint32_t(b))); }
526};
527
529 template<> struct channel_multiplier_unsigned<uint16_t> {
530 using first_argument_type = uint16_t;
531 using second_argument_type = uint16_t;
532 using result_type = uint16_t;
533 auto operator()(uint16_t a, uint16_t b) const -> uint16_t { return uint16_t((uint32_t(a) * uint32_t(b))/65535); }
534};
535
537 template<> struct channel_multiplier_unsigned<float32_t> {
538 using first_argument_type = float32_t;
539 using second_argument_type = float32_t;
540 using result_type = float32_t;
541 auto operator()(float32_t a, float32_t b) const -> float32_t { return a*b; }
542};
543
545template <typename ChannelValue>
546 struct channel_multiplier {
547 using first_argument_type = ChannelValue;
548 using second_argument_type = ChannelValue;
549 using result_type = ChannelValue;
550 auto operator()(ChannelValue a, ChannelValue b) const -> ChannelValue
551 {
552 using to_unsigned = detail::channel_convert_to_unsigned<ChannelValue>;
553 using from_unsigned = detail::channel_convert_from_unsigned<ChannelValue>;
554 using multiplier_unsigned = channel_multiplier_unsigned<typename to_unsigned::result_type>;
555 return from_unsigned()(multiplier_unsigned()(to_unsigned()(a), to_unsigned()(b)));
556 }
557};
558
560template <typename Channel> // Models ChannelConcept (could be a channel reference)
561 inline auto channel_multiply(Channel a, Channel b) -> typename channel_traits<Channel>::value_type
562{
563 return channel_multiplier<typename channel_traits<Channel>::value_type>()(a,b);
564}
566
578
581template <typename Channel> // Models ChannelConcept (could be a channel reference)
582 inline auto channel_invert(Channel x) -> typename channel_traits<Channel>::value_type
583{
584 using base_t = typename base_channel_type<Channel>::type;
585 using promoted_t = typename promote_integral<base_t>::type;
586 promoted_t const promoted_x = x;
587 promoted_t const promoted_max = channel_traits<Channel>::max_value();
588 promoted_t const promoted_min = channel_traits<Channel>::min_value();
589 promoted_t const promoted_inverted_x = promoted_max - promoted_x + promoted_min;
590 auto const inverted_x = static_cast<base_t>(promoted_inverted_x);
591 return inverted_x;
592}
593
594}} // namespace boost::gil
595
596#endif
boost::gil::channel_convert
auto channel_convert(SrcChannel const &src) -> typename channel_traits< DstChannel >::value_type
Converting from one channel type to another.
Definition channel_algorithm.hpp:461
boost::gil::channel_invert
auto channel_invert(Channel x) -> typename channel_traits< Channel >::value_type
Default implementation. Provide overloads for performance.
Definition channel_algorithm.hpp:582
boost::gil::float32_t
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:153
boost::gil::channel_multiply
auto channel_multiply(Channel a, Channel b) -> typename channel_traits< Channel >::value_type
A function multiplying two channels. result = a * b / max_value.
Definition channel_algorithm.hpp:561
boost
defined(BOOST_NO_CXX17_HDR_MEMORY_RESOURCE)
Definition algorithm.hpp:36
boost::gil::channel_converter
A unary function object converting between channel types.
Definition channel_algorithm.hpp:446
boost::gil::channel_multiplier_unsigned
This is the default implementation. Performance specializatons are provided.
Definition channel_algorithm.hpp:510
boost::gil::channel_multiplier
A function object to multiply two channels. result = a * b / max_value.
Definition channel_algorithm.hpp:546
boost::gil::default_channel_converter
Same as channel_converter, except it takes the destination channel by reference, which allows us to m...
Definition channel_algorithm.hpp:471
boost::gil::detail::identity
identity taken from SGI STL.
Definition utilities.hpp:211