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