JeVoisBase  1.5
JeVois Smart Embedded Machine Vision Toolkit Base Modules
Share this page:
Promotions.H
Go to the documentation of this file.
1 // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
2 //
3 // JeVois Smart Embedded Machine Vision Toolkit - Copyright (C) 2016 by Laurent Itti, the University of Southern
4 // California (USC), and iLab at USC. See http://iLab.usc.edu and http://jevois.org for information about this project.
5 //
6 // This file is part of the JeVois Smart Embedded Machine Vision Toolkit. This program is free software; you can
7 // redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software
8 // Foundation, version 2. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
9 // without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
10 // License for more details. You should have received a copy of the GNU General Public License along with this program;
11 // if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
12 //
13 // Contact information: Laurent Itti - 3641 Watt Way, HNB-07A - Los Angeles, CA 90089-2520 - USA.
14 // Tel: +1 213 740 3527 - itti@pollux.usc.edu - http://iLab.usc.edu - http://jevois.org
15 // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
16 /*! \file */
17 
18 // This code from:
19 
20 // //////////////////////////////////////////////////////////////////// //
21 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2003 //
22 // by the University of Southern California (USC) and the iLab at USC. //
23 // See http://iLab.usc.edu for information about this project. //
24 // //////////////////////////////////////////////////////////////////// //
25 // Major portions of the iLab Neuromorphic Vision Toolkit are protected //
26 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency //
27 // in Visual Environments, and Applications'' by Christof Koch and //
28 // Laurent Itti, California Institute of Technology, 2001 (patent //
29 // pending; application number 09/912,225 filed July 23, 2001; see //
30 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status). //
31 // //////////////////////////////////////////////////////////////////// //
32 // This file is part of the iLab Neuromorphic Vision C++ Toolkit. //
33 // //
34 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can //
35 // redistribute it and/or modify it under the terms of the GNU General //
36 // Public License as published by the Free Software Foundation; either //
37 // version 2 of the License, or (at your option) any later version. //
38 // //
39 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope //
40 // that it will be useful, but WITHOUT ANY WARRANTY; without even the //
41 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR //
42 // PURPOSE. See the GNU General Public License for more details. //
43 // //
44 // You should have received a copy of the GNU General Public License //
45 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write //
46 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, //
47 // Boston, MA 02111-1307 USA. //
48 // //////////////////////////////////////////////////////////////////// //
49 //
50 // Primary maintainer for this file: Laurent Itti <itti@usc.edu>
51 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Util/Promotions.H $
52 // $Id: Promotions.H 4731 2005-06-29 19:33:51Z rjpeters $
53 //
54 
55 #pragma once
56 
58 #include <limits>
59 
60 
61 /*! The idea here is to create a mechanism by which a given template type can be promoted to a more capable type (e.g.,
62 byte to float, or PixRGB<byte> to PixRGB<float>), typically to hold the result of some operation that may exceed the
63 capacity of the original type (e.g., the result of adding two bytes may not fit within the range of possible values for
64 byte). See http://www.oonumerics.org/blitz/traits.html for further details. The way to use this is as follows: if you
65 have a template type T (which may be scalar or not) that you wish to promote to a more capable type that would have
66 "similar characteristics" to another type TT, then use the type promote_trait<T,TT>::TP. For example:
67 promote_trait<T,float>::TP is a float if T was a byte, and is a PixRGB<float> if T was a PixRGB<byte> */
68 
69 
70 //! Promote from T1 and T2 to a type than can hold T1 * T2
71 /*! Basic promotion mechanism: given T1 and T2, TP provides the appropriate type to hold the result of an operation
72  involving T1 and T2. Default is to promote to type T1, that is, no change (this is used when T2 is "weaker" than T1;
73  when T2 is "stronger" that T1, the explicit specialized rules below are used). */
74 template <class T1, class T2>
75 struct promote_trait { typedef T1 TP; enum { willPromote = 0 }; };
76 
77 // Here go the various specializations:
78 
79 // NOTE: we follow the basic C++ integral promotions, promoting to int
80 // from byte, int16 and int32
81 template <> struct promote_trait<byte, byte> { typedef int TP; enum { willPromote = 1 }; };
82 template <> struct promote_trait<byte, int16> { typedef int TP; enum { willPromote = 1 }; };
83 template <> struct promote_trait<byte, int32> { typedef int TP; enum { willPromote = 1 }; };
84 template <> struct promote_trait<byte, float> { typedef float TP; enum { willPromote = 1 }; };
85 template <> struct promote_trait<byte, double> { typedef double TP; enum { willPromote = 1 }; };
86 template <> struct promote_trait<byte, long double> { typedef long double TP; enum { willPromote = 1 }; };
87 
88 template <> struct promote_trait<int16, byte> { typedef int TP; enum { willPromote = 1 }; };
89 template <> struct promote_trait<int16, int16> { typedef int TP; enum { willPromote = 1 }; };
90 template <> struct promote_trait<int16, int32> { typedef int TP; enum { willPromote = 1 }; };
91 template <> struct promote_trait<int16, float> { typedef float TP; enum { willPromote = 1 }; };
92 template <> struct promote_trait<int16, double> { typedef double TP; enum { willPromote = 1 }; };
93 template <> struct promote_trait<int16, long double> { typedef long double TP; enum { willPromote = 1 }; };
94 
95 template <> struct promote_trait<int32, float> { typedef float TP; enum { willPromote = 1 }; };
96 template <> struct promote_trait<int32, double> { typedef double TP; enum { willPromote = 1 }; };
97 template <> struct promote_trait<int32, long double> { typedef long double TP; enum { willPromote = 1 }; };
98 
99 template <> struct promote_trait<float, double> { typedef double TP; enum { willPromote = 1 }; };
100 template <> struct promote_trait<float, long double> { typedef long double TP; enum { willPromote = 1 }; };
101 
102 template <> struct promote_trait<double, long double> { typedef long double TP; enum { willPromote = 1 }; };
103 
104 //! A macro for specializing promote_trait for template types.
105 /*! See e.g. usage in PixelsTypes.H. */
106 #define SPECIALIZE_PROMOTE_TRAIT(T_TYPE, T_PARAMS, T_ARGS) \
107 template <T_PARAMS> class T_TYPE; \
108 template <> struct promote_trait<T_TYPE<byte T_ARGS> , byte> { typedef T_TYPE<int T_ARGS> TP; enum { willPromote = 1 }; }; \
109 template <> struct promote_trait<T_TYPE<byte T_ARGS> , int16> { typedef T_TYPE<int T_ARGS> TP; enum { willPromote = 1 }; }; \
110 template <> struct promote_trait<T_TYPE<byte T_ARGS> , int32> { typedef T_TYPE<int T_ARGS> TP; enum { willPromote = 1 }; }; \
111 template <> struct promote_trait<T_TYPE<byte T_ARGS> , float> { typedef T_TYPE<float T_ARGS> TP; enum { willPromote = 1 }; }; \
112 template <> struct promote_trait<T_TYPE<byte T_ARGS> , double> { typedef T_TYPE<double T_ARGS> TP; enum { willPromote = 1 }; }; \
113 template <> struct promote_trait<T_TYPE<byte T_ARGS> , long double> { typedef T_TYPE<long double T_ARGS> TP; enum { willPromote = 1 }; }; \
114  \
115 template <> struct promote_trait<T_TYPE<int16 T_ARGS> , byte> { typedef T_TYPE<int T_ARGS> TP; enum { willPromote = 1 }; }; \
116 template <> struct promote_trait<T_TYPE<int16 T_ARGS> , int16> { typedef T_TYPE<int T_ARGS> TP; enum { willPromote = 1 }; }; \
117 template <> struct promote_trait<T_TYPE<int16 T_ARGS> , int32> { typedef T_TYPE<int T_ARGS> TP; enum { willPromote = 1 }; }; \
118 template <> struct promote_trait<T_TYPE<int16 T_ARGS> , float> { typedef T_TYPE<float T_ARGS> TP; enum { willPromote = 1 }; }; \
119 template <> struct promote_trait<T_TYPE<int16 T_ARGS> , double> { typedef T_TYPE<double T_ARGS> TP; enum { willPromote = 1 }; }; \
120 template <> struct promote_trait<T_TYPE<int16 T_ARGS> , long double> { typedef T_TYPE<long double T_ARGS> TP; enum { willPromote = 1 }; }; \
121  \
122 template <> struct promote_trait<T_TYPE<int32 T_ARGS> , float> { typedef T_TYPE<float T_ARGS> TP; enum { willPromote = 1 }; }; \
123 template <> struct promote_trait<T_TYPE<int32 T_ARGS> , double> { typedef T_TYPE<double T_ARGS> TP; enum { willPromote = 1 }; }; \
124 template <> struct promote_trait<T_TYPE<int32 T_ARGS> , long double> { typedef T_TYPE<long double T_ARGS> TP; enum { willPromote = 1 }; }; \
125  \
126 template <> struct promote_trait<T_TYPE<float T_ARGS> , double> { typedef T_TYPE<double T_ARGS> TP; enum { willPromote = 1 }; }; \
127 template <> struct promote_trait<T_TYPE<float T_ARGS> , long double> { typedef T_TYPE<long double T_ARGS> TP; enum { willPromote = 1 }; }; \
128  \
129 template <> struct promote_trait<T_TYPE<double T_ARGS> , long double> { typedef T_TYPE<long double T_ARGS> TP; enum { willPromote = 1 }; }; \
130  \
131 template <> struct promote_trait<T_TYPE<byte T_ARGS> , T_TYPE<byte T_ARGS> > { typedef T_TYPE<int T_ARGS> TP; enum { willPromote = 1 }; }; \
132 template <> struct promote_trait<T_TYPE<byte T_ARGS> , T_TYPE<int16 T_ARGS> > { typedef T_TYPE<int T_ARGS> TP; enum { willPromote = 1 }; }; \
133 template <> struct promote_trait<T_TYPE<byte T_ARGS> , T_TYPE<int32 T_ARGS> > { typedef T_TYPE<int T_ARGS> TP; enum { willPromote = 1 }; }; \
134 template <> struct promote_trait<T_TYPE<byte T_ARGS> , T_TYPE<float T_ARGS> > { typedef T_TYPE<float T_ARGS> TP; enum { willPromote = 1 }; }; \
135 template <> struct promote_trait<T_TYPE<byte T_ARGS> , T_TYPE<double T_ARGS> > { typedef T_TYPE<double T_ARGS> TP; enum { willPromote = 1 }; }; \
136 template <> struct promote_trait<T_TYPE<byte T_ARGS> , T_TYPE<long double T_ARGS> > { typedef T_TYPE<long double T_ARGS> TP; enum { willPromote = 1 }; }; \
137  \
138 template <> struct promote_trait<T_TYPE<int16 T_ARGS> , T_TYPE<byte T_ARGS> > { typedef T_TYPE<int T_ARGS> TP; enum { willPromote = 1 }; }; \
139 template <> struct promote_trait<T_TYPE<int16 T_ARGS> , T_TYPE<int16 T_ARGS> > { typedef T_TYPE<int T_ARGS> TP; enum { willPromote = 1 }; }; \
140 template <> struct promote_trait<T_TYPE<int16 T_ARGS> , T_TYPE<int32 T_ARGS> > { typedef T_TYPE<int T_ARGS> TP; enum { willPromote = 1 }; }; \
141 template <> struct promote_trait<T_TYPE<int16 T_ARGS> , T_TYPE<float T_ARGS> > { typedef T_TYPE<float T_ARGS> TP; enum { willPromote = 1 }; }; \
142 template <> struct promote_trait<T_TYPE<int16 T_ARGS> , T_TYPE<double T_ARGS> > { typedef T_TYPE<double T_ARGS> TP; enum { willPromote = 1 }; }; \
143 template <> struct promote_trait<T_TYPE<int16 T_ARGS> , T_TYPE<long double T_ARGS> > { typedef T_TYPE<long double T_ARGS> TP; enum { willPromote = 1 }; }; \
144  \
145 template <> struct promote_trait<T_TYPE<int32 T_ARGS> , T_TYPE<float T_ARGS> > { typedef T_TYPE<float T_ARGS> TP; enum { willPromote = 1 }; }; \
146 template <> struct promote_trait<T_TYPE<int32 T_ARGS> , T_TYPE<double T_ARGS> > { typedef T_TYPE<double T_ARGS> TP; enum { willPromote = 1 }; }; \
147 template <> struct promote_trait<T_TYPE<int32 T_ARGS> , T_TYPE<long double T_ARGS> > { typedef T_TYPE<long double T_ARGS> TP; enum { willPromote = 1 }; }; \
148  \
149 template <> struct promote_trait<T_TYPE<float T_ARGS> , T_TYPE<double T_ARGS> > { typedef T_TYPE<double T_ARGS> TP; enum { willPromote = 1 }; }; \
150 template <> struct promote_trait<T_TYPE<float T_ARGS> , T_TYPE<long double T_ARGS> > { typedef T_TYPE<long double T_ARGS> TP; enum { willPromote = 1 }; }; \
151  \
152 template <> struct promote_trait<T_TYPE<double T_ARGS> , T_TYPE<long double T_ARGS> > { typedef T_TYPE<long double T_ARGS> TP; enum { willPromote = 1 }; };
153 
154 // ######################################################################
155 
156 // The following defines rules to safely convert from type TT to type
157 // T, clamping the values to the destination type's range if
158 // necessary. The function to use is clamped_convert<T>(xx), which
159 // will convert xx from type TT to type T, clamping its value to the
160 // acceptable range for T if necessary.
161 
162 // Basically there's a promoteFromTo<T1,T2> struct that exposes an
163 // enum is_preserving which is set to 1 or 0 depending on whether T1
164 // --> T2 is value-preserving or not. Then defined a convert_helper
165 // struct that has a convert() function that does the real work,
166 // except the struct can be specialized on whether the conversion is
167 // preserving or not. Then the actual clamped_convert function just
168 // forwards to convert_helper<T1,T2>::convert(), which picks the right
169 // implementation. This way all of the important information is
170 // specified by how we define promoteFromTo<T1,T2>::is_preserving, and
171 // this specification is cleanly separated from the implementation
172 // that uses it.
173 
174 // by default, promotion is considered range-preserving (will not
175 // require clamping by us in clamped_convert). The rationale for this
176 // weirdness is that for unknown types we will leave it to the
177 // converting operator=() of that type to deal with the clamping.
178 template <class T1, class T2>
179 struct promoteFromTo { enum { is_preserving = 1 }; };
180 
181 // promote from T to itself is a range-preserving no-op:
182 template <class T>
183 struct promoteFromTo<T, T> { enum { is_preserving = 1 }; };
184 
185 // these rules declare which conversions are not range-preserving and
186 // will require clamping within clamped_convert; they are used to
187 // enforce clamping of builtin types:
188 
189 template <> struct promoteFromTo<int16 , byte> { enum { is_preserving = 0 }; };
190 template <> struct promoteFromTo<int32 , byte> { enum { is_preserving = 0 }; };
191 template <> struct promoteFromTo<float , byte> { enum { is_preserving = 0 }; };
192 template <> struct promoteFromTo<double , byte> { enum { is_preserving = 0 }; };
193 template <> struct promoteFromTo<long double, byte> { enum { is_preserving = 0 }; };
194 
195 template <> struct promoteFromTo<int32 , int16> { enum { is_preserving = 0 }; };
196 template <> struct promoteFromTo<float , int16> { enum { is_preserving = 0 }; };
197 template <> struct promoteFromTo<double , int16> { enum { is_preserving = 0 }; };
198 template <> struct promoteFromTo<long double, int16> { enum { is_preserving = 0 }; };
199 
200 template <> struct promoteFromTo<float , int32> { enum { is_preserving = 0 }; };
201 template <> struct promoteFromTo<double , int32> { enum { is_preserving = 0 }; };
202 template <> struct promoteFromTo<long double, int32> { enum { is_preserving = 0 }; };
203 
204 template <> struct promoteFromTo<double , float> { enum { is_preserving = 0 }; };
205 template <> struct promoteFromTo<long double, float> { enum { is_preserving = 0 }; };
206 
207 template <> struct promoteFromTo<long double, double> { enum { is_preserving = 0 }; };
208 
209 //! Helper struct to handle rounding between different types
210 /*! Note that we aren't worried about clamping here, that is handled
211  separately by convert_helper (see below). We have different
212  specializations of round_helper depending on whether the src and
213  dest types are integral or floating-point. The only case where we
214  have to do any actual rounding is when we're going from
215  floating->integral. */
216 template <class dst_type, class src_type,
217  bool need_rounding =
218  (std::numeric_limits<dst_type>::is_integer
219  && !std::numeric_limits<src_type>::is_integer)>
221 
222 template <class dst_type, class src_type>
223 struct round_helper<dst_type, src_type, false> // no rounding needed
224 {
225  inline static dst_type round(src_type x)
226  { return dst_type(x); }
227 };
228 
229 template <class dst_type, class src_type>
230 struct round_helper<dst_type, src_type, true> // rounding needed
231 {
232  inline static dst_type round(src_type x)
233  {
234  if (x > 0) return dst_type(x+0.5); // round toward +Inf
235  else if (x < 0) return dst_type(x-0.5); // round toward -Inf
236  else return dst_type(0);
237  }
238 };
239 
240 //! Helper struct to handle type conversions at compile time.
241 /*! Helps decide whether to clamp or not at compile time so that we don't waste time in a test at run time; because
242  std::numeric_limits is a pile of trash, we also need to parameterize the helper by a boolean indicating whether the
243  type we convert to is integer or not. This will determine which numeric limits we use to do the clamping: */
244 template <class dst_type, class src_type,
246  bool dst_type_is_integer = std::numeric_limits<dst_type>::is_integer>
248 
249 // clamp and convert if non-preserving; dest type is integral:
250 template <class dst_type, class src_type>
251 struct convert_helper<dst_type, src_type,
252  /* is_preserving = */ false,
253  /* dst_type_is_integer = */ true>
254 {
255  inline static dst_type convert(src_type x)
256  {
257  if (x < std::numeric_limits<dst_type>::min()) return std::numeric_limits<dst_type>::min();
258  if (x > std::numeric_limits<dst_type>::max()) return std::numeric_limits<dst_type>::max();
259  return dst_type(x);
260  }
261 
262  inline static dst_type rounded_convert(src_type x)
263  {
264  if (x < std::numeric_limits<dst_type>::min()) return std::numeric_limits<dst_type>::min();
265  if (x > std::numeric_limits<dst_type>::max()) return std::numeric_limits<dst_type>::max();
266 
268  }
269 };
270 
271 // clamp and convert if non-preserving; dest type is non-integral:
272 template <class dst_type, class src_type>
273 struct convert_helper<dst_type, src_type,
274  /* is_preserving = */ false,
275  /* dst_type_is_integer = */ false>
276 {
277  inline static dst_type convert(src_type x)
278  {
279  if (x < -std::numeric_limits<dst_type>::max()) return -std::numeric_limits<dst_type>::max();
280  if (x > std::numeric_limits<dst_type>::max()) return std::numeric_limits<dst_type>::max();
281  return dst_type(x);
282  }
283 
284  inline static dst_type rounded_convert(src_type x)
285  {
286  if (x < -std::numeric_limits<dst_type>::max()) return -std::numeric_limits<dst_type>::max();
287  if (x > std::numeric_limits<dst_type>::max()) return std::numeric_limits<dst_type>::max();
288 
290  }
291 };
292 
293 // cast without checking range if preserving; for builtin types, this
294 // means that we know that we can safely cast (the destination types
295 // can represent all values of the source type); for other types, we
296 // here assume that the conversion constructor will take care of the
297 // clamping:
298 template <class dst_type, class src_type>
299 struct convert_helper<dst_type, src_type,
300  /* is_preserving = */ true,
301  /* dst_type_is_integer = */ true>
302 {
303  inline static dst_type convert(src_type x)
304  {
305  return dst_type(x);
306  }
307 
308  inline static dst_type rounded_convert(src_type x)
309  {
311  }
312 };
313 
314 template <class dst_type, class src_type>
315 struct convert_helper<dst_type, src_type,
316  /* is_preserving = */ true,
317  /* dst_type_is_integer = */ false>
318 {
319  inline static dst_type convert(src_type x)
320  {
321  return dst_type(x);
322  }
323 
324  inline static dst_type rounded_convert(src_type x)
325  {
327  }
328 };
329 
330 //! Convert safely from src_type to type dst_type, clamping if necessary.
331 template <class dst_type, class src_type>
332 inline
333 dst_type clamped_convert(src_type x)
334 {
336 }
337 
338 //! Convert safely from src_type to type dst_type, clamping and rounding as needed.
339 template <class dst_type, class src_type>
340 inline
341 dst_type clamped_rounded_convert(src_type x)
342 {
344 }
static dst_type round(src_type x)
Definition: Promotions.H:225
static dst_type rounded_convert(src_type x)
Definition: Promotions.H:308
Helper struct to handle type conversions at compile time.
Definition: Promotions.H:247
Helper struct to handle rounding between different types.
Definition: Promotions.H:220
static dst_type round(src_type x)
Definition: Promotions.H:232
dst_type clamped_convert(src_type x)
Convert safely from src_type to type dst_type, clamping if necessary.
Definition: Promotions.H:333
type_with_N_bits< unsigned char, 8 >::type byte
8-bit unsigned integer
Definition: Types.H:86
static dst_type rounded_convert(src_type x)
Definition: Promotions.H:262
type_with_N_bits< int, 32 >::type int32
32-bit signed integer
Definition: Types.H:104
type_with_N_bits< short, 16 >::type int16
16-bit signed integer
Definition: Types.H:92
Promote from T1 and T2 to a type than can hold T1 * T2.
Definition: Promotions.H:75
dst_type clamped_rounded_convert(src_type x)
Convert safely from src_type to type dst_type, clamping and rounding as needed.
Definition: Promotions.H:341
static dst_type rounded_convert(src_type x)
Definition: Promotions.H:324