Chris@16
|
1 /*
|
Chris@16
|
2 Copyright 2005-2007 Adobe Systems Incorporated
|
Chris@16
|
3
|
Chris@16
|
4 Use, modification and distribution are subject to the Boost Software License,
|
Chris@16
|
5 Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
Chris@16
|
6 http://www.boost.org/LICENSE_1_0.txt).
|
Chris@16
|
7
|
Chris@16
|
8 See http://opensource.adobe.com/gil for most recent version including documentation.
|
Chris@16
|
9 */
|
Chris@16
|
10 /*************************************************************************************************/
|
Chris@16
|
11
|
Chris@16
|
12 #ifndef GIL_CHANNEL_ALGORITHM_HPP
|
Chris@16
|
13 #define GIL_CHANNEL_ALGORITHM_HPP
|
Chris@16
|
14
|
Chris@16
|
15 ////////////////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
16 /// \file
|
Chris@16
|
17 /// \brief Channel algorithms
|
Chris@16
|
18 /// \author Lubomir Bourdev and Hailin Jin \n
|
Chris@16
|
19 /// Adobe Systems Incorporated
|
Chris@16
|
20 /// \date 2005-2007 \n Last updated on May 6, 2007
|
Chris@16
|
21 ///
|
Chris@16
|
22 /// Definitions of standard GIL 8-bit, 16-bit, 32-bit channels
|
Chris@16
|
23 ///
|
Chris@16
|
24 ////////////////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
25
|
Chris@16
|
26 #include "gil_config.hpp"
|
Chris@16
|
27 #include "channel.hpp"
|
Chris@16
|
28 #include <boost/mpl/less.hpp>
|
Chris@16
|
29 #include <boost/mpl/integral_c.hpp>
|
Chris@16
|
30 #include <boost/mpl/greater.hpp>
|
Chris@16
|
31 #include <boost/type_traits.hpp>
|
Chris@16
|
32
|
Chris@16
|
33 namespace boost { namespace gil {
|
Chris@16
|
34
|
Chris@16
|
35 //#ifdef _MSC_VER
|
Chris@16
|
36 //#pragma warning(push)
|
Chris@16
|
37 //#pragma warning(disable: 4309) // disable truncation of constant value warning (using -1 to get the max value of an integral)
|
Chris@16
|
38 //#endif
|
Chris@16
|
39
|
Chris@16
|
40 namespace detail {
|
Chris@16
|
41
|
Chris@16
|
42 // some forward declarations
|
Chris@16
|
43 template <typename SrcChannelV, typename DstChannelV, bool SrcIsIntegral, bool DstIsIntegral> struct channel_converter_unsigned_impl;
|
Chris@16
|
44 template <typename SrcChannelV, typename DstChannelV, bool SrcIsGreater> struct channel_converter_unsigned_integral;
|
Chris@16
|
45 template <typename SrcChannelV, typename DstChannelV, bool SrcLessThanDst, bool SrcDivisible> struct channel_converter_unsigned_integral_impl;
|
Chris@16
|
46 template <typename SrcChannelV, typename DstChannelV, bool SrcLessThanDst, bool CannotFitInInteger> struct channel_converter_unsigned_integral_nondivisible;
|
Chris@16
|
47
|
Chris@16
|
48 //////////////////////////////////////
|
Chris@16
|
49 //// unsigned_integral_max_value - given an unsigned integral channel type, returns its maximum value as an MPL integral constant
|
Chris@16
|
50 //////////////////////////////////////
|
Chris@16
|
51
|
Chris@16
|
52
|
Chris@16
|
53 template <typename UnsignedIntegralChannel>
|
Chris@16
|
54 struct unsigned_integral_max_value : public mpl::integral_c<UnsignedIntegralChannel,-1> {};
|
Chris@16
|
55
|
Chris@16
|
56 template <>
|
Chris@16
|
57 struct unsigned_integral_max_value<uint8_t> : public mpl::integral_c<uint32_t,0xFF> {};
|
Chris@16
|
58 template <>
|
Chris@16
|
59 struct unsigned_integral_max_value<uint16_t> : public mpl::integral_c<uint32_t,0xFFFF> {};
|
Chris@16
|
60 template <>
|
Chris@16
|
61 struct unsigned_integral_max_value<uint32_t> : public mpl::integral_c<uintmax_t,0xFFFFFFFF> {};
|
Chris@16
|
62
|
Chris@16
|
63
|
Chris@16
|
64 template <int K>
|
Chris@16
|
65 struct unsigned_integral_max_value<packed_channel_value<K> >
|
Chris@16
|
66 : public mpl::integral_c<typename packed_channel_value<K>::integer_t, (1<<K)-1> {};
|
Chris@16
|
67
|
Chris@16
|
68 //////////////////////////////////////
|
Chris@16
|
69 //// unsigned_integral_num_bits - given an unsigned integral channel type, returns the minimum number of bits needed to represent it
|
Chris@16
|
70 //////////////////////////////////////
|
Chris@16
|
71
|
Chris@16
|
72 template <typename UnsignedIntegralChannel>
|
Chris@16
|
73 struct unsigned_integral_num_bits : public mpl::int_<sizeof(UnsignedIntegralChannel)*8> {};
|
Chris@16
|
74
|
Chris@16
|
75 template <int K>
|
Chris@16
|
76 struct unsigned_integral_num_bits<packed_channel_value<K> >
|
Chris@16
|
77 : public mpl::int_<K> {};
|
Chris@16
|
78
|
Chris@16
|
79 } // namespace detail
|
Chris@16
|
80
|
Chris@16
|
81 /**
|
Chris@16
|
82 \defgroup ChannelConvertAlgorithm channel_convert
|
Chris@16
|
83 \brief Converting from one channel type to another
|
Chris@16
|
84 \ingroup ChannelAlgorithm
|
Chris@16
|
85
|
Chris@16
|
86 Conversion is done as a simple linear mapping of one channel range to the other,
|
Chris@16
|
87 such that the minimum/maximum value of the source maps to the minimum/maximum value of the destination.
|
Chris@16
|
88 One implication of this is that the value 0 of signed channels may not be preserved!
|
Chris@16
|
89
|
Chris@16
|
90 When creating new channel models, it is often a good idea to provide specializations for the channel conversion algorithms, for
|
Chris@16
|
91 example, for performance optimizations. If the new model is an integral type that can be signed, it is easier to define the conversion
|
Chris@16
|
92 only for the unsigned type (\p channel_converter_unsigned) and provide specializations of \p detail::channel_convert_to_unsigned
|
Chris@16
|
93 and \p detail::channel_convert_from_unsigned to convert between the signed and unsigned type.
|
Chris@16
|
94
|
Chris@16
|
95 Example:
|
Chris@16
|
96 \code
|
Chris@16
|
97 // bits32f is a floating point channel with range [0.0f ... 1.0f]
|
Chris@16
|
98 bits32f src_channel = channel_traits<bits32f>::max_value();
|
Chris@16
|
99 assert(src_channel == 1);
|
Chris@16
|
100
|
Chris@16
|
101 // bits8 is 8-bit unsigned integral channel (typedef-ed from unsigned char)
|
Chris@16
|
102 bits8 dst_channel = channel_convert<bits8>(src_channel);
|
Chris@16
|
103 assert(dst_channel == 255); // max value goes to max value
|
Chris@16
|
104 \endcode
|
Chris@16
|
105 */
|
Chris@16
|
106
|
Chris@16
|
107 /**
|
Chris@16
|
108 \defgroup ChannelConvertUnsignedAlgorithm channel_converter_unsigned
|
Chris@16
|
109 \ingroup ChannelConvertAlgorithm
|
Chris@16
|
110 \brief Convert one unsigned/floating point channel to another. Converts both the channel type and range
|
Chris@16
|
111 @{
|
Chris@16
|
112 */
|
Chris@16
|
113
|
Chris@16
|
114 //////////////////////////////////////
|
Chris@16
|
115 //// channel_converter_unsigned
|
Chris@16
|
116 //////////////////////////////////////
|
Chris@16
|
117
|
Chris@16
|
118 template <typename SrcChannelV, typename DstChannelV> // Model ChannelValueConcept
|
Chris@16
|
119 struct channel_converter_unsigned
|
Chris@16
|
120 : public detail::channel_converter_unsigned_impl<SrcChannelV,DstChannelV,is_integral<SrcChannelV>::value,is_integral<DstChannelV>::value> {};
|
Chris@16
|
121
|
Chris@16
|
122
|
Chris@16
|
123 /// \brief Converting a channel to itself - identity operation
|
Chris@16
|
124 template <typename T> struct channel_converter_unsigned<T,T> : public detail::identity<T> {};
|
Chris@16
|
125
|
Chris@16
|
126
|
Chris@16
|
127 namespace detail {
|
Chris@16
|
128
|
Chris@16
|
129 //////////////////////////////////////
|
Chris@16
|
130 //// channel_converter_unsigned_impl
|
Chris@16
|
131 //////////////////////////////////////
|
Chris@16
|
132
|
Chris@16
|
133 /// \brief This is the default implementation. Performance specializatons are provided
|
Chris@16
|
134 template <typename SrcChannelV, typename DstChannelV, bool SrcIsIntegral, bool DstIsIntegral>
|
Chris@16
|
135 struct channel_converter_unsigned_impl : public std::unary_function<DstChannelV,SrcChannelV> {
|
Chris@16
|
136 DstChannelV operator()(SrcChannelV src) const {
|
Chris@16
|
137 return DstChannelV(channel_traits<DstChannelV>::min_value() +
|
Chris@16
|
138 (src - channel_traits<SrcChannelV>::min_value()) / channel_range<SrcChannelV>() * channel_range<DstChannelV>());
|
Chris@16
|
139 }
|
Chris@16
|
140 private:
|
Chris@16
|
141 template <typename C>
|
Chris@16
|
142 static double channel_range() {
|
Chris@16
|
143 return double(channel_traits<C>::max_value()) - double(channel_traits<C>::min_value());
|
Chris@16
|
144 }
|
Chris@16
|
145 };
|
Chris@16
|
146
|
Chris@16
|
147 // When both the source and the destination are integral channels, perform a faster conversion
|
Chris@16
|
148 template <typename SrcChannelV, typename DstChannelV>
|
Chris@16
|
149 struct channel_converter_unsigned_impl<SrcChannelV,DstChannelV,true,true>
|
Chris@16
|
150 : public channel_converter_unsigned_integral<SrcChannelV,DstChannelV,
|
Chris@16
|
151 mpl::less<unsigned_integral_max_value<SrcChannelV>,unsigned_integral_max_value<DstChannelV> >::value > {};
|
Chris@16
|
152
|
Chris@16
|
153
|
Chris@16
|
154 //////////////////////////////////////
|
Chris@16
|
155 //// channel_converter_unsigned_integral
|
Chris@16
|
156 //////////////////////////////////////
|
Chris@16
|
157
|
Chris@16
|
158 template <typename SrcChannelV, typename DstChannelV>
|
Chris@16
|
159 struct channel_converter_unsigned_integral<SrcChannelV,DstChannelV,true>
|
Chris@16
|
160 : public channel_converter_unsigned_integral_impl<SrcChannelV,DstChannelV,true,
|
Chris@16
|
161 !(unsigned_integral_max_value<DstChannelV>::value % unsigned_integral_max_value<SrcChannelV>::value) > {};
|
Chris@16
|
162
|
Chris@16
|
163 template <typename SrcChannelV, typename DstChannelV>
|
Chris@16
|
164 struct channel_converter_unsigned_integral<SrcChannelV,DstChannelV,false>
|
Chris@16
|
165 : public channel_converter_unsigned_integral_impl<SrcChannelV,DstChannelV,false,
|
Chris@16
|
166 !(unsigned_integral_max_value<SrcChannelV>::value % unsigned_integral_max_value<DstChannelV>::value) > {};
|
Chris@16
|
167
|
Chris@16
|
168
|
Chris@16
|
169 //////////////////////////////////////
|
Chris@16
|
170 //// channel_converter_unsigned_integral_impl
|
Chris@16
|
171 //////////////////////////////////////
|
Chris@16
|
172
|
Chris@16
|
173 // Both source and destination are unsigned integral channels,
|
Chris@16
|
174 // the src max value is less than the dst max value,
|
Chris@16
|
175 // and the dst max value is divisible by the src max value
|
Chris@16
|
176 template <typename SrcChannelV, typename DstChannelV>
|
Chris@16
|
177 struct channel_converter_unsigned_integral_impl<SrcChannelV,DstChannelV,true,true> {
|
Chris@16
|
178 DstChannelV operator()(SrcChannelV src) const {
|
Chris@16
|
179 typedef typename unsigned_integral_max_value<DstChannelV>::value_type integer_t;
|
Chris@16
|
180 static const integer_t mul = unsigned_integral_max_value<DstChannelV>::value / unsigned_integral_max_value<SrcChannelV>::value;
|
Chris@16
|
181 return DstChannelV(src * mul);
|
Chris@16
|
182 }
|
Chris@16
|
183 };
|
Chris@16
|
184
|
Chris@16
|
185 // Both source and destination are unsigned integral channels,
|
Chris@16
|
186 // the dst max value is less than (or equal to) the src max value,
|
Chris@16
|
187 // and the src max value is divisible by the dst max value
|
Chris@16
|
188 template <typename SrcChannelV, typename DstChannelV>
|
Chris@16
|
189 struct channel_converter_unsigned_integral_impl<SrcChannelV,DstChannelV,false,true> {
|
Chris@16
|
190 DstChannelV operator()(SrcChannelV src) const {
|
Chris@16
|
191 typedef typename unsigned_integral_max_value<SrcChannelV>::value_type integer_t;
|
Chris@16
|
192 static const integer_t div = unsigned_integral_max_value<SrcChannelV>::value / unsigned_integral_max_value<DstChannelV>::value;
|
Chris@16
|
193 static const integer_t div2 = div/2;
|
Chris@16
|
194 return DstChannelV((src + div2) / div);
|
Chris@16
|
195 }
|
Chris@16
|
196 };
|
Chris@16
|
197
|
Chris@16
|
198 // Prevent overflow for the largest integral type
|
Chris@16
|
199 template <typename DstChannelV>
|
Chris@16
|
200 struct channel_converter_unsigned_integral_impl<uintmax_t,DstChannelV,false,true> {
|
Chris@16
|
201 DstChannelV operator()(uintmax_t src) const {
|
Chris@16
|
202 static const uintmax_t div = unsigned_integral_max_value<bits32>::value / unsigned_integral_max_value<DstChannelV>::value;
|
Chris@16
|
203 static const uintmax_t div2 = div/2;
|
Chris@16
|
204 if (src > unsigned_integral_max_value<uintmax_t>::value - div2)
|
Chris@16
|
205 return unsigned_integral_max_value<DstChannelV>::value;
|
Chris@16
|
206 return DstChannelV((src + div2) / div);
|
Chris@16
|
207 }
|
Chris@16
|
208 };
|
Chris@16
|
209
|
Chris@16
|
210 // Both source and destination are unsigned integral channels,
|
Chris@16
|
211 // and the dst max value is not divisible by the src max value
|
Chris@16
|
212 // See if you can represent the expression (src * dst_max) / src_max in integral form
|
Chris@16
|
213 template <typename SrcChannelV, typename DstChannelV, bool SrcLessThanDst>
|
Chris@16
|
214 struct channel_converter_unsigned_integral_impl<SrcChannelV,DstChannelV,SrcLessThanDst,false>
|
Chris@16
|
215 : public channel_converter_unsigned_integral_nondivisible<SrcChannelV,DstChannelV,SrcLessThanDst,
|
Chris@16
|
216 mpl::greater<
|
Chris@16
|
217 mpl::plus<unsigned_integral_num_bits<SrcChannelV>,unsigned_integral_num_bits<DstChannelV> >,
|
Chris@16
|
218 unsigned_integral_num_bits<uintmax_t>
|
Chris@16
|
219 >::value> {};
|
Chris@16
|
220
|
Chris@16
|
221
|
Chris@16
|
222 // Both source and destination are unsigned integral channels,
|
Chris@16
|
223 // the src max value is less than the dst max value,
|
Chris@16
|
224 // and the dst max value is not divisible by the src max value
|
Chris@16
|
225 // The expression (src * dst_max) / src_max fits in an integer
|
Chris@16
|
226 template <typename SrcChannelV, typename DstChannelV>
|
Chris@16
|
227 struct channel_converter_unsigned_integral_nondivisible<SrcChannelV,DstChannelV,true,false> {
|
Chris@16
|
228 DstChannelV operator()(SrcChannelV src) const {
|
Chris@16
|
229 typedef typename detail::min_fast_uint<unsigned_integral_num_bits<SrcChannelV>::value+unsigned_integral_num_bits<DstChannelV>::value>::type integer_t;
|
Chris@16
|
230 return DstChannelV(integer_t(src * unsigned_integral_max_value<DstChannelV>::value) / unsigned_integral_max_value<SrcChannelV>::value);
|
Chris@16
|
231 }
|
Chris@16
|
232 };
|
Chris@16
|
233
|
Chris@16
|
234 // Both source and destination are unsigned integral channels,
|
Chris@16
|
235 // the src max value is less than the dst max value,
|
Chris@16
|
236 // and the dst max value is not divisible by the src max value
|
Chris@16
|
237 // The expression (src * dst_max) / src_max cannot fit in an integer (overflows). Use a double
|
Chris@16
|
238 template <typename SrcChannelV, typename DstChannelV>
|
Chris@16
|
239 struct channel_converter_unsigned_integral_nondivisible<SrcChannelV,DstChannelV,true,true> {
|
Chris@16
|
240 DstChannelV operator()(SrcChannelV src) const {
|
Chris@16
|
241 static const double mul = unsigned_integral_max_value<DstChannelV>::value / double(unsigned_integral_max_value<SrcChannelV>::value);
|
Chris@16
|
242 return DstChannelV(src * mul);
|
Chris@16
|
243 }
|
Chris@16
|
244 };
|
Chris@16
|
245
|
Chris@16
|
246 // Both source and destination are unsigned integral channels,
|
Chris@16
|
247 // the dst max value is less than (or equal to) the src max value,
|
Chris@16
|
248 // and the src max value is not divisible by the dst max value
|
Chris@16
|
249 template <typename SrcChannelV, typename DstChannelV, bool CannotFit>
|
Chris@16
|
250 struct channel_converter_unsigned_integral_nondivisible<SrcChannelV,DstChannelV,false,CannotFit> {
|
Chris@16
|
251 DstChannelV operator()(SrcChannelV src) const {
|
Chris@16
|
252
|
Chris@16
|
253 typedef typename detail::unsigned_integral_max_value< SrcChannelV >::value_type src_integer_t;
|
Chris@16
|
254 typedef typename detail::unsigned_integral_max_value< DstChannelV >::value_type dst_integer_t;
|
Chris@16
|
255
|
Chris@16
|
256 static const double div = unsigned_integral_max_value<SrcChannelV>::value
|
Chris@16
|
257 / static_cast< double >( unsigned_integral_max_value<DstChannelV>::value );
|
Chris@16
|
258
|
Chris@16
|
259 static const src_integer_t div2 = static_cast< src_integer_t >( div / 2.0 );
|
Chris@16
|
260
|
Chris@16
|
261 return DstChannelV( static_cast< dst_integer_t >(( static_cast< double >( src + div2 ) / div )));
|
Chris@16
|
262 }
|
Chris@16
|
263 };
|
Chris@16
|
264
|
Chris@16
|
265 } // namespace detail
|
Chris@16
|
266
|
Chris@16
|
267 /////////////////////////////////////////////////////
|
Chris@16
|
268 /// bits32f conversion
|
Chris@16
|
269 /////////////////////////////////////////////////////
|
Chris@16
|
270
|
Chris@16
|
271 template <typename DstChannelV> struct channel_converter_unsigned<bits32f,DstChannelV> : public std::unary_function<bits32f,DstChannelV> {
|
Chris@16
|
272 DstChannelV operator()(bits32f x) const
|
Chris@16
|
273 {
|
Chris@16
|
274 typedef typename detail::unsigned_integral_max_value< DstChannelV >::value_type dst_integer_t;
|
Chris@16
|
275 return DstChannelV( static_cast< dst_integer_t >(x*channel_traits<DstChannelV>::max_value()+0.5f ));
|
Chris@16
|
276 }
|
Chris@16
|
277 };
|
Chris@16
|
278
|
Chris@16
|
279 template <typename SrcChannelV> struct channel_converter_unsigned<SrcChannelV,bits32f> : public std::unary_function<SrcChannelV,bits32f> {
|
Chris@16
|
280 bits32f operator()(SrcChannelV x) const { return bits32f(x/float(channel_traits<SrcChannelV>::max_value())); }
|
Chris@16
|
281 };
|
Chris@16
|
282
|
Chris@16
|
283 template <> struct channel_converter_unsigned<bits32f,bits32f> : public std::unary_function<bits32f,bits32f> {
|
Chris@16
|
284 bits32f operator()(bits32f x) const { return x; }
|
Chris@16
|
285 };
|
Chris@16
|
286
|
Chris@16
|
287
|
Chris@16
|
288 /// \brief 32 bit <-> float channel conversion
|
Chris@16
|
289 template <> struct channel_converter_unsigned<bits32,bits32f> : public std::unary_function<bits32,bits32f> {
|
Chris@16
|
290 bits32f operator()(bits32 x) const {
|
Chris@16
|
291 // unfortunately without an explicit check it is possible to get a round-off error. We must ensure that max_value of bits32 matches max_value of bits32f
|
Chris@16
|
292 if (x>=channel_traits<bits32>::max_value()) return channel_traits<bits32f>::max_value();
|
Chris@16
|
293 return float(x) / float(channel_traits<bits32>::max_value());
|
Chris@16
|
294 }
|
Chris@16
|
295 };
|
Chris@16
|
296 /// \brief 32 bit <-> float channel conversion
|
Chris@16
|
297 template <> struct channel_converter_unsigned<bits32f,bits32> : public std::unary_function<bits32f,bits32> {
|
Chris@16
|
298 bits32 operator()(bits32f x) const {
|
Chris@16
|
299 // unfortunately without an explicit check it is possible to get a round-off error. We must ensure that max_value of bits32 matches max_value of bits32f
|
Chris@16
|
300 if (x>=channel_traits<bits32f>::max_value()) return channel_traits<bits32>::max_value();
|
Chris@16
|
301 return bits32(x * channel_traits<bits32>::max_value() + 0.5f);
|
Chris@16
|
302 }
|
Chris@16
|
303 };
|
Chris@16
|
304
|
Chris@16
|
305 /// @}
|
Chris@16
|
306
|
Chris@16
|
307 namespace detail {
|
Chris@16
|
308 // Converting from signed to unsigned integral channel.
|
Chris@16
|
309 // It is both a unary function, and a metafunction (thus requires the 'type' nested typedef, which equals result_type)
|
Chris@16
|
310 template <typename ChannelValue> // Model ChannelValueConcept
|
Chris@16
|
311 struct channel_convert_to_unsigned : public detail::identity<ChannelValue> {
|
Chris@16
|
312 typedef ChannelValue type;
|
Chris@16
|
313 };
|
Chris@16
|
314
|
Chris@16
|
315 template <> struct channel_convert_to_unsigned<bits8s> : public std::unary_function<bits8s,bits8> {
|
Chris@16
|
316 typedef bits8 type;
|
Chris@16
|
317 type operator()(bits8s val) const { return val+128; }
|
Chris@16
|
318 };
|
Chris@16
|
319
|
Chris@16
|
320 template <> struct channel_convert_to_unsigned<bits16s> : public std::unary_function<bits16s,bits16> {
|
Chris@16
|
321 typedef bits16 type;
|
Chris@16
|
322 type operator()(bits16s val) const { return val+32768; }
|
Chris@16
|
323 };
|
Chris@16
|
324
|
Chris@16
|
325 template <> struct channel_convert_to_unsigned<bits32s> : public std::unary_function<bits32s,bits32> {
|
Chris@16
|
326 typedef bits32 type;
|
Chris@16
|
327 type operator()(bits32s x) const { return static_cast<bits32>(x+(1<<31)); }
|
Chris@16
|
328 };
|
Chris@16
|
329
|
Chris@16
|
330
|
Chris@16
|
331 // Converting from unsigned to signed integral channel
|
Chris@16
|
332 // It is both a unary function, and a metafunction (thus requires the 'type' nested typedef, which equals result_type)
|
Chris@16
|
333 template <typename ChannelValue> // Model ChannelValueConcept
|
Chris@16
|
334 struct channel_convert_from_unsigned : public detail::identity<ChannelValue> {
|
Chris@16
|
335 typedef ChannelValue type;
|
Chris@16
|
336 };
|
Chris@16
|
337
|
Chris@16
|
338 template <> struct channel_convert_from_unsigned<bits8s> : public std::unary_function<bits8,bits8s> {
|
Chris@16
|
339 typedef bits8s type;
|
Chris@16
|
340 type operator()(bits8 val) const { return val-128; }
|
Chris@16
|
341 };
|
Chris@16
|
342
|
Chris@16
|
343 template <> struct channel_convert_from_unsigned<bits16s> : public std::unary_function<bits16,bits16s> {
|
Chris@16
|
344 typedef bits16s type;
|
Chris@16
|
345 type operator()(bits16 val) const { return val-32768; }
|
Chris@16
|
346 };
|
Chris@16
|
347
|
Chris@16
|
348 template <> struct channel_convert_from_unsigned<bits32s> : public std::unary_function<bits32,bits32s> {
|
Chris@16
|
349 typedef bits32s type;
|
Chris@16
|
350 type operator()(bits32 x) const { return static_cast<bits32s>(x-(1<<31)); }
|
Chris@16
|
351 };
|
Chris@16
|
352
|
Chris@16
|
353 } // namespace detail
|
Chris@16
|
354
|
Chris@16
|
355 /// \ingroup ChannelConvertAlgorithm
|
Chris@16
|
356 /// \brief A unary function object converting between channel types
|
Chris@16
|
357 template <typename SrcChannelV, typename DstChannelV> // Model ChannelValueConcept
|
Chris@16
|
358 struct channel_converter : public std::unary_function<SrcChannelV,DstChannelV> {
|
Chris@16
|
359 DstChannelV operator()(const SrcChannelV& src) const {
|
Chris@16
|
360 typedef detail::channel_convert_to_unsigned<SrcChannelV> to_unsigned;
|
Chris@16
|
361 typedef detail::channel_convert_from_unsigned<DstChannelV> from_unsigned;
|
Chris@16
|
362 typedef channel_converter_unsigned<typename to_unsigned::result_type, typename from_unsigned::argument_type> converter_unsigned;
|
Chris@16
|
363 return from_unsigned()(converter_unsigned()(to_unsigned()(src)));
|
Chris@16
|
364 }
|
Chris@16
|
365 };
|
Chris@16
|
366
|
Chris@16
|
367 /// \ingroup ChannelConvertAlgorithm
|
Chris@16
|
368 /// \brief Converting from one channel type to another.
|
Chris@16
|
369 template <typename DstChannel, typename SrcChannel> // Model ChannelConcept (could be channel references)
|
Chris@16
|
370 inline typename channel_traits<DstChannel>::value_type channel_convert(const SrcChannel& src) {
|
Chris@16
|
371 return channel_converter<typename channel_traits<SrcChannel>::value_type,
|
Chris@16
|
372 typename channel_traits<DstChannel>::value_type>()(src);
|
Chris@16
|
373 }
|
Chris@16
|
374
|
Chris@16
|
375 /// \ingroup ChannelConvertAlgorithm
|
Chris@16
|
376 /// \brief Same as channel_converter, except it takes the destination channel by reference, which allows
|
Chris@16
|
377 /// us to move the templates from the class level to the method level. This is important when invoking it
|
Chris@16
|
378 /// on heterogeneous pixels.
|
Chris@16
|
379 struct default_channel_converter {
|
Chris@16
|
380 template <typename Ch1, typename Ch2>
|
Chris@16
|
381 void operator()(const Ch1& src, Ch2& dst) const {
|
Chris@16
|
382 dst=channel_convert<Ch2>(src);
|
Chris@16
|
383 }
|
Chris@16
|
384 };
|
Chris@16
|
385
|
Chris@16
|
386 namespace detail {
|
Chris@16
|
387 // fast integer division by 255
|
Chris@16
|
388 inline uint32_t div255(uint32_t in) { uint32_t tmp=in+128; return (tmp + (tmp>>8))>>8; }
|
Chris@16
|
389
|
Chris@16
|
390 // fast integer divison by 32768
|
Chris@16
|
391 inline uint32_t div32768(uint32_t in) { return (in+16384)>>15; }
|
Chris@16
|
392 }
|
Chris@16
|
393
|
Chris@16
|
394 /**
|
Chris@16
|
395 \defgroup ChannelMultiplyAlgorithm channel_multiply
|
Chris@16
|
396 \ingroup ChannelAlgorithm
|
Chris@16
|
397 \brief Multiplying unsigned channel values of the same type. Performs scaled multiplication result = a * b / max_value
|
Chris@16
|
398
|
Chris@16
|
399 Example:
|
Chris@16
|
400 \code
|
Chris@16
|
401 bits8 x=128;
|
Chris@16
|
402 bits8 y=128;
|
Chris@16
|
403 bits8 mul = channel_multiply(x,y);
|
Chris@16
|
404 assert(mul == 64); // 64 = 128 * 128 / 255
|
Chris@16
|
405 \endcode
|
Chris@16
|
406 */
|
Chris@16
|
407 /// @{
|
Chris@16
|
408
|
Chris@16
|
409 /// \brief This is the default implementation. Performance specializatons are provided
|
Chris@16
|
410 template <typename ChannelValue>
|
Chris@16
|
411 struct channel_multiplier_unsigned : public std::binary_function<ChannelValue,ChannelValue,ChannelValue> {
|
Chris@16
|
412 ChannelValue operator()(ChannelValue a, ChannelValue b) const {
|
Chris@16
|
413 return ChannelValue(a / double(channel_traits<ChannelValue>::max_value()) * b);
|
Chris@16
|
414 }
|
Chris@16
|
415 };
|
Chris@16
|
416
|
Chris@16
|
417 /// \brief Specialization of channel_multiply for 8-bit unsigned channels
|
Chris@16
|
418 template<> struct channel_multiplier_unsigned<bits8> : public std::binary_function<bits8,bits8,bits8> {
|
Chris@16
|
419 bits8 operator()(bits8 a, bits8 b) const { return bits8(detail::div255(uint32_t(a) * uint32_t(b))); }
|
Chris@16
|
420 };
|
Chris@16
|
421
|
Chris@16
|
422 /// \brief Specialization of channel_multiply for 16-bit unsigned channels
|
Chris@16
|
423 template<> struct channel_multiplier_unsigned<bits16> : public std::binary_function<bits16,bits16,bits16> {
|
Chris@16
|
424 bits16 operator()(bits16 a, bits16 b) const { return bits16((uint32_t(a) * uint32_t(b))/65535); }
|
Chris@16
|
425 };
|
Chris@16
|
426
|
Chris@16
|
427 /// \brief Specialization of channel_multiply for float 0..1 channels
|
Chris@16
|
428 template<> struct channel_multiplier_unsigned<bits32f> : public std::binary_function<bits32f,bits32f,bits32f> {
|
Chris@16
|
429 bits32f operator()(bits32f a, bits32f b) const { return a*b; }
|
Chris@16
|
430 };
|
Chris@16
|
431
|
Chris@16
|
432 /// \brief A function object to multiply two channels. result = a * b / max_value
|
Chris@16
|
433 template <typename ChannelValue>
|
Chris@16
|
434 struct channel_multiplier : public std::binary_function<ChannelValue, ChannelValue, ChannelValue> {
|
Chris@16
|
435 ChannelValue operator()(ChannelValue a, ChannelValue b) const {
|
Chris@16
|
436 typedef detail::channel_convert_to_unsigned<ChannelValue> to_unsigned;
|
Chris@16
|
437 typedef detail::channel_convert_from_unsigned<ChannelValue> from_unsigned;
|
Chris@16
|
438 typedef channel_multiplier_unsigned<typename to_unsigned::result_type> multiplier_unsigned;
|
Chris@16
|
439 return from_unsigned()(multiplier_unsigned()(to_unsigned()(a), to_unsigned()(b)));
|
Chris@16
|
440 }
|
Chris@16
|
441 };
|
Chris@16
|
442
|
Chris@16
|
443 /// \brief A function multiplying two channels. result = a * b / max_value
|
Chris@16
|
444 template <typename Channel> // Models ChannelConcept (could be a channel reference)
|
Chris@16
|
445 inline typename channel_traits<Channel>::value_type channel_multiply(Channel a, Channel b) {
|
Chris@16
|
446 return channel_multiplier<typename channel_traits<Channel>::value_type>()(a,b);
|
Chris@16
|
447 }
|
Chris@16
|
448 /// @}
|
Chris@16
|
449
|
Chris@16
|
450 /**
|
Chris@16
|
451 \defgroup ChannelInvertAlgorithm channel_invert
|
Chris@16
|
452 \ingroup ChannelAlgorithm
|
Chris@16
|
453 \brief Returns the inverse of a channel. result = max_value - x + min_value
|
Chris@16
|
454
|
Chris@16
|
455 Example:
|
Chris@16
|
456 \code
|
Chris@16
|
457 // bits8 == uint8_t == unsigned char
|
Chris@16
|
458 bits8 x=255;
|
Chris@16
|
459 bits8 inv = channel_invert(x);
|
Chris@16
|
460 assert(inv == 0);
|
Chris@16
|
461 \endcode
|
Chris@16
|
462 */
|
Chris@16
|
463
|
Chris@16
|
464 /// \brief Default implementation. Provide overloads for performance
|
Chris@16
|
465 /// \ingroup ChannelInvertAlgorithm channel_invert
|
Chris@16
|
466 template <typename Channel> // Models ChannelConcept (could be a channel reference)
|
Chris@16
|
467 inline typename channel_traits<Channel>::value_type channel_invert(Channel x) {
|
Chris@16
|
468 return channel_traits<Channel>::max_value()-x + channel_traits<Channel>::min_value();
|
Chris@16
|
469 }
|
Chris@16
|
470
|
Chris@16
|
471 //#ifdef _MSC_VER
|
Chris@16
|
472 //#pragma warning(pop)
|
Chris@16
|
473 //#endif
|
Chris@16
|
474
|
Chris@16
|
475 } } // namespace boost::gil
|
Chris@16
|
476
|
Chris@16
|
477 #endif
|