JeVoisBase  1.22
JeVois Smart Embedded Machine Vision Toolkit Base Modules
Share this page:
Loading...
Searching...
No Matches
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.,
62byte to float, or PixRGB<byte> to PixRGB<float>), typically to hold the result of some operation that may exceed the
63capacity of the original type (e.g., the result of adding two bytes may not fit within the range of possible values for
64byte). See http://www.oonumerics.org/blitz/traits.html for further details. The way to use this is as follows: if you
65have 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:
67promote_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). */
74template <class T1, class T2>
75struct 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
81template <> struct promote_trait<byte, byte> { typedef int TP; enum { willPromote = 1 }; };
82template <> struct promote_trait<byte, int16> { typedef int TP; enum { willPromote = 1 }; };
83template <> struct promote_trait<byte, int32> { typedef int TP; enum { willPromote = 1 }; };
84template <> struct promote_trait<byte, float> { typedef float TP; enum { willPromote = 1 }; };
85template <> struct promote_trait<byte, double> { typedef double TP; enum { willPromote = 1 }; };
86template <> struct promote_trait<byte, long double> { typedef long double TP; enum { willPromote = 1 }; };
87
88template <> struct promote_trait<int16, byte> { typedef int TP; enum { willPromote = 1 }; };
89template <> struct promote_trait<int16, int16> { typedef int TP; enum { willPromote = 1 }; };
90template <> struct promote_trait<int16, int32> { typedef int TP; enum { willPromote = 1 }; };
91template <> struct promote_trait<int16, float> { typedef float TP; enum { willPromote = 1 }; };
92template <> struct promote_trait<int16, double> { typedef double TP; enum { willPromote = 1 }; };
93template <> struct promote_trait<int16, long double> { typedef long double TP; enum { willPromote = 1 }; };
94
95template <> struct promote_trait<int32, float> { typedef float TP; enum { willPromote = 1 }; };
96template <> struct promote_trait<int32, double> { typedef double TP; enum { willPromote = 1 }; };
97template <> struct promote_trait<int32, long double> { typedef long double TP; enum { willPromote = 1 }; };
98
99template <> struct promote_trait<float, double> { typedef double TP; enum { willPromote = 1 }; };
100template <> struct promote_trait<float, long double> { typedef long double TP; enum { willPromote = 1 }; };
101
102template <> 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) \
107template <T_PARAMS> class T_TYPE; \
108template <> struct promote_trait<T_TYPE<byte T_ARGS> , byte> { typedef T_TYPE<int T_ARGS> TP; enum { willPromote = 1 }; }; \
109template <> struct promote_trait<T_TYPE<byte T_ARGS> , int16> { typedef T_TYPE<int T_ARGS> TP; enum { willPromote = 1 }; }; \
110template <> struct promote_trait<T_TYPE<byte T_ARGS> , int32> { typedef T_TYPE<int T_ARGS> TP; enum { willPromote = 1 }; }; \
111template <> struct promote_trait<T_TYPE<byte T_ARGS> , float> { typedef T_TYPE<float T_ARGS> TP; enum { willPromote = 1 }; }; \
112template <> struct promote_trait<T_TYPE<byte T_ARGS> , double> { typedef T_TYPE<double T_ARGS> TP; enum { willPromote = 1 }; }; \
113template <> struct promote_trait<T_TYPE<byte T_ARGS> , long double> { typedef T_TYPE<long double T_ARGS> TP; enum { willPromote = 1 }; }; \
114 \
115template <> struct promote_trait<T_TYPE<int16 T_ARGS> , byte> { typedef T_TYPE<int T_ARGS> TP; enum { willPromote = 1 }; }; \
116template <> struct promote_trait<T_TYPE<int16 T_ARGS> , int16> { typedef T_TYPE<int T_ARGS> TP; enum { willPromote = 1 }; }; \
117template <> struct promote_trait<T_TYPE<int16 T_ARGS> , int32> { typedef T_TYPE<int T_ARGS> TP; enum { willPromote = 1 }; }; \
118template <> struct promote_trait<T_TYPE<int16 T_ARGS> , float> { typedef T_TYPE<float T_ARGS> TP; enum { willPromote = 1 }; }; \
119template <> struct promote_trait<T_TYPE<int16 T_ARGS> , double> { typedef T_TYPE<double T_ARGS> TP; enum { willPromote = 1 }; }; \
120template <> struct promote_trait<T_TYPE<int16 T_ARGS> , long double> { typedef T_TYPE<long double T_ARGS> TP; enum { willPromote = 1 }; }; \
121 \
122template <> struct promote_trait<T_TYPE<int32 T_ARGS> , float> { typedef T_TYPE<float T_ARGS> TP; enum { willPromote = 1 }; }; \
123template <> struct promote_trait<T_TYPE<int32 T_ARGS> , double> { typedef T_TYPE<double T_ARGS> TP; enum { willPromote = 1 }; }; \
124template <> struct promote_trait<T_TYPE<int32 T_ARGS> , long double> { typedef T_TYPE<long double T_ARGS> TP; enum { willPromote = 1 }; }; \
125 \
126template <> struct promote_trait<T_TYPE<float T_ARGS> , double> { typedef T_TYPE<double T_ARGS> TP; enum { willPromote = 1 }; }; \
127template <> struct promote_trait<T_TYPE<float T_ARGS> , long double> { typedef T_TYPE<long double T_ARGS> TP; enum { willPromote = 1 }; }; \
128 \
129template <> struct promote_trait<T_TYPE<double T_ARGS> , long double> { typedef T_TYPE<long double T_ARGS> TP; enum { willPromote = 1 }; }; \
130 \
131template <> struct promote_trait<T_TYPE<byte T_ARGS> , T_TYPE<byte T_ARGS> > { typedef T_TYPE<int T_ARGS> TP; enum { willPromote = 1 }; }; \
132template <> struct promote_trait<T_TYPE<byte T_ARGS> , T_TYPE<int16 T_ARGS> > { typedef T_TYPE<int T_ARGS> TP; enum { willPromote = 1 }; }; \
133template <> struct promote_trait<T_TYPE<byte T_ARGS> , T_TYPE<int32 T_ARGS> > { typedef T_TYPE<int T_ARGS> TP; enum { willPromote = 1 }; }; \
134template <> struct promote_trait<T_TYPE<byte T_ARGS> , T_TYPE<float T_ARGS> > { typedef T_TYPE<float T_ARGS> TP; enum { willPromote = 1 }; }; \
135template <> struct promote_trait<T_TYPE<byte T_ARGS> , T_TYPE<double T_ARGS> > { typedef T_TYPE<double T_ARGS> TP; enum { willPromote = 1 }; }; \
136template <> 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 \
138template <> struct promote_trait<T_TYPE<int16 T_ARGS> , T_TYPE<byte T_ARGS> > { typedef T_TYPE<int T_ARGS> TP; enum { willPromote = 1 }; }; \
139template <> struct promote_trait<T_TYPE<int16 T_ARGS> , T_TYPE<int16 T_ARGS> > { typedef T_TYPE<int T_ARGS> TP; enum { willPromote = 1 }; }; \
140template <> struct promote_trait<T_TYPE<int16 T_ARGS> , T_TYPE<int32 T_ARGS> > { typedef T_TYPE<int T_ARGS> TP; enum { willPromote = 1 }; }; \
141template <> struct promote_trait<T_TYPE<int16 T_ARGS> , T_TYPE<float T_ARGS> > { typedef T_TYPE<float T_ARGS> TP; enum { willPromote = 1 }; }; \
142template <> struct promote_trait<T_TYPE<int16 T_ARGS> , T_TYPE<double T_ARGS> > { typedef T_TYPE<double T_ARGS> TP; enum { willPromote = 1 }; }; \
143template <> 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 \
145template <> struct promote_trait<T_TYPE<int32 T_ARGS> , T_TYPE<float T_ARGS> > { typedef T_TYPE<float T_ARGS> TP; enum { willPromote = 1 }; }; \
146template <> struct promote_trait<T_TYPE<int32 T_ARGS> , T_TYPE<double T_ARGS> > { typedef T_TYPE<double T_ARGS> TP; enum { willPromote = 1 }; }; \
147template <> 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 \
149template <> struct promote_trait<T_TYPE<float T_ARGS> , T_TYPE<double T_ARGS> > { typedef T_TYPE<double T_ARGS> TP; enum { willPromote = 1 }; }; \
150template <> 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 \
152template <> 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.
178template <class T1, class T2>
179struct promoteFromTo { enum { is_preserving = 1 }; };
180
181// promote from T to itself is a range-preserving no-op:
182template <class T>
183struct 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
189template <> struct promoteFromTo<int16 , byte> { enum { is_preserving = 0 }; };
190template <> struct promoteFromTo<int32 , byte> { enum { is_preserving = 0 }; };
191template <> struct promoteFromTo<float , byte> { enum { is_preserving = 0 }; };
192template <> struct promoteFromTo<double , byte> { enum { is_preserving = 0 }; };
193template <> struct promoteFromTo<long double, byte> { enum { is_preserving = 0 }; };
194
195template <> struct promoteFromTo<int32 , int16> { enum { is_preserving = 0 }; };
196template <> struct promoteFromTo<float , int16> { enum { is_preserving = 0 }; };
197template <> struct promoteFromTo<double , int16> { enum { is_preserving = 0 }; };
198template <> struct promoteFromTo<long double, int16> { enum { is_preserving = 0 }; };
199
200template <> struct promoteFromTo<float , int32> { enum { is_preserving = 0 }; };
201template <> struct promoteFromTo<double , int32> { enum { is_preserving = 0 }; };
202template <> struct promoteFromTo<long double, int32> { enum { is_preserving = 0 }; };
203
204template <> struct promoteFromTo<double , float> { enum { is_preserving = 0 }; };
205template <> struct promoteFromTo<long double, float> { enum { is_preserving = 0 }; };
206
207template <> 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. */
216template <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
222template <class dst_type, class src_type>
223struct 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
229template <class dst_type, class src_type>
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: */
244template <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:
250template <class dst_type, class src_type>
251struct 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:
272template <class dst_type, class src_type>
273struct 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:
298template <class dst_type, class src_type>
299struct 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
314template <class dst_type, class src_type>
315struct 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.
331template <class dst_type, class src_type>
332inline
333dst_type clamped_convert(src_type x)
334{
336}
337
338//! Convert safely from src_type to type dst_type, clamping and rounding as needed.
339template <class dst_type, class src_type>
340inline
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
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< int, 32 >::type int32
32-bit signed integer
Definition Types.H:104
type_with_N_bits< unsignedchar, 8 >::type byte
8-bit unsigned integer
Definition Types.H:86
type_with_N_bits< short, 16 >::type int16
16-bit signed integer
Definition Types.H:92
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
Promote from T1 and T2 to a type than can hold T1 * T2.
Definition Promotions.H:75
static dst_type round(src_type x)
Definition Promotions.H:225
static dst_type round(src_type x)
Definition Promotions.H:232
Helper struct to handle rounding between different types.
Definition Promotions.H:220