1 /* Copyright 2016 The TensorFlow Authors. All Rights Reserved. 2 3 Licensed under the Apache License, Version 2.0 (the "License"); 4 you may not use this file except in compliance with the License. 5 You may obtain a copy of the License at 6 7 http://www.apache.org/licenses/LICENSE-2.0 8 9 Unless required by applicable law or agreed to in writing, software 10 distributed under the License is distributed on an "AS IS" BASIS, 11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 See the License for the specific language governing permissions and 13 limitations under the License. 14 ==============================================================================*/ 15 16 #ifndef TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_UTILS_H_ 17 #define TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_UTILS_H_ 18 19 #include <math.h> 20 #include <stdint.h> 21 #include <stdlib.h> 22 #include <time.h> 23 24 #include <cmath> // for std::abs(float) 25 26 #ifndef HAVE_CLOCK_GETTIME 27 // Use gettimeofday() instead of clock_gettime(). 28 #include <sys/time.h> 29 #endif // ifdef HAVE_CLOCK_GETTIME 30 31 #include "tensorflow/examples/android/jni/object_tracking/logging.h" 32 33 // TODO(andrewharp): clean up these macros to use the codebase statndard. 34 35 // A very small number, generally used as the tolerance for accumulated 36 // floating point errors in bounds-checks. 37 #define EPSILON 0.00001f 38 39 #define SAFE_DELETE(pointer) {\ 40 if ((pointer) != NULL) {\ 41 LOGV("Safe deleting pointer: %s", #pointer);\ 42 delete (pointer);\ 43 (pointer) = NULL;\ 44 } else {\ 45 LOGV("Pointer already null: %s", #pointer);\ 46 }\ 47 } 48 49 50 #ifdef __GOOGLE__ 51 52 #define CHECK_ALWAYS(condition, format, ...) {\ 53 CHECK(condition) << StringPrintf(format, ##__VA_ARGS__);\ 54 } 55 56 #define SCHECK(condition, format, ...) {\ 57 DCHECK(condition) << StringPrintf(format, ##__VA_ARGS__);\ 58 } 59 60 #else 61 62 #define CHECK_ALWAYS(condition, format, ...) {\ 63 if (!(condition)) {\ 64 LOGE("CHECK FAILED (%s): " format, #condition, ##__VA_ARGS__);\ 65 abort();\ 66 }\ 67 } 68 69 #ifdef SANITY_CHECKS 70 #define SCHECK(condition, format, ...) {\ 71 CHECK_ALWAYS(condition, format, ##__VA_ARGS__);\ 72 } 73 #else 74 #define SCHECK(condition, format, ...) {} 75 #endif // SANITY_CHECKS 76 77 #endif // __GOOGLE__ 78 79 80 #ifndef MAX 81 #define MAX(a, b) (((a) > (b)) ? (a) : (b)) 82 #endif 83 #ifndef MIN 84 #define MIN(a, b) (((a) > (b)) ? (b) : (a)) 85 #endif 86 87 inline static int64_t CurrentThreadTimeNanos() { 88 #ifdef HAVE_CLOCK_GETTIME 89 struct timespec tm; 90 clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tm); 91 return tm.tv_sec * 1000000000LL + tm.tv_nsec; 92 #else 93 struct timeval tv; 94 gettimeofday(&tv, NULL); 95 return tv.tv_sec * 1000000000 + tv.tv_usec * 1000; 96 #endif 97 } 98 99 inline static int64_t CurrentRealTimeMillis() { 100 #ifdef HAVE_CLOCK_GETTIME 101 struct timespec tm; 102 clock_gettime(CLOCK_MONOTONIC, &tm); 103 return tm.tv_sec * 1000LL + tm.tv_nsec / 1000000LL; 104 #else 105 struct timeval tv; 106 gettimeofday(&tv, NULL); 107 return tv.tv_sec * 1000 + tv.tv_usec / 1000; 108 #endif 109 } 110 111 112 template<typename T> 113 inline static T Square(const T a) { 114 return a * a; 115 } 116 117 118 template<typename T> 119 inline static T Clip(const T a, const T floor, const T ceil) { 120 SCHECK(ceil >= floor, "Bounds mismatch!"); 121 return (a <= floor) ? floor : ((a >= ceil) ? ceil : a); 122 } 123 124 125 template<typename T> 126 inline static int Floor(const T a) { 127 return static_cast<int>(a); 128 } 129 130 131 template<typename T> 132 inline static int Ceil(const T a) { 133 return Floor(a) + 1; 134 } 135 136 137 template<typename T> 138 inline static bool InRange(const T a, const T min, const T max) { 139 return (a >= min) && (a <= max); 140 } 141 142 143 inline static bool ValidIndex(const int a, const int max) { 144 return (a >= 0) && (a < max); 145 } 146 147 148 inline bool NearlyEqual(const float a, const float b, const float tolerance) { 149 return std::abs(a - b) < tolerance; 150 } 151 152 153 inline bool NearlyEqual(const float a, const float b) { 154 return NearlyEqual(a, b, EPSILON); 155 } 156 157 158 template<typename T> 159 inline static int Round(const float a) { 160 return (a - static_cast<float>(floor(a) > 0.5f) ? ceil(a) : floor(a)); 161 } 162 163 164 template<typename T> 165 inline static void Swap(T* const a, T* const b) { 166 // Cache out the VALUE of what's at a. 167 T tmp = *a; 168 *a = *b; 169 170 *b = tmp; 171 } 172 173 174 static inline float randf() { 175 return rand() / static_cast<float>(RAND_MAX); 176 } 177 178 static inline float randf(const float min_value, const float max_value) { 179 return randf() * (max_value - min_value) + min_value; 180 } 181 182 static inline uint16_t RealToFixed115(const float real_number) { 183 SCHECK(InRange(real_number, 0.0f, 2048.0f), 184 "Value out of range! %.2f", real_number); 185 186 static const float kMult = 32.0f; 187 const float round_add = (real_number > 0.0f) ? 0.5f : -0.5f; 188 return static_cast<uint16_t>(real_number * kMult + round_add); 189 } 190 191 static inline float FixedToFloat115(const uint16_t fp_number) { 192 const float kDiv = 32.0f; 193 return (static_cast<float>(fp_number) / kDiv); 194 } 195 196 static inline int RealToFixed1616(const float real_number) { 197 static const float kMult = 65536.0f; 198 SCHECK(InRange(real_number, -kMult, kMult), 199 "Value out of range! %.2f", real_number); 200 201 const float round_add = (real_number > 0.0f) ? 0.5f : -0.5f; 202 return static_cast<int>(real_number * kMult + round_add); 203 } 204 205 static inline float FixedToFloat1616(const int fp_number) { 206 const float kDiv = 65536.0f; 207 return (static_cast<float>(fp_number) / kDiv); 208 } 209 210 template<typename T> 211 // produces numbers in range [0,2*M_PI] (rather than -PI,PI) 212 inline T FastAtan2(const T y, const T x) { 213 static const T coeff_1 = (T)(M_PI / 4.0); 214 static const T coeff_2 = (T)(3.0 * coeff_1); 215 const T abs_y = fabs(y); 216 T angle; 217 if (x >= 0) { 218 T r = (x - abs_y) / (x + abs_y); 219 angle = coeff_1 - coeff_1 * r; 220 } else { 221 T r = (x + abs_y) / (abs_y - x); 222 angle = coeff_2 - coeff_1 * r; 223 } 224 static const T PI_2 = 2.0 * M_PI; 225 return y < 0 ? PI_2 - angle : angle; 226 } 227 228 #define NELEMS(X) (sizeof(X) / sizeof(X[0])) 229 230 namespace tf_tracking { 231 232 #ifdef __ARM_NEON 233 float ComputeMeanNeon(const float* const values, const int num_vals); 234 235 float ComputeStdDevNeon(const float* const values, const int num_vals, 236 const float mean); 237 238 float ComputeWeightedMeanNeon(const float* const values, 239 const float* const weights, const int num_vals); 240 241 float ComputeCrossCorrelationNeon(const float* const values1, 242 const float* const values2, 243 const int num_vals); 244 #endif 245 246 inline float ComputeMeanCpu(const float* const values, const int num_vals) { 247 // Get mean. 248 float sum = values[0]; 249 for (int i = 1; i < num_vals; ++i) { 250 sum += values[i]; 251 } 252 return sum / static_cast<float>(num_vals); 253 } 254 255 256 inline float ComputeMean(const float* const values, const int num_vals) { 257 return 258 #ifdef __ARM_NEON 259 (num_vals >= 8) ? ComputeMeanNeon(values, num_vals) : 260 #endif 261 ComputeMeanCpu(values, num_vals); 262 } 263 264 265 inline float ComputeStdDevCpu(const float* const values, 266 const int num_vals, 267 const float mean) { 268 // Get Std dev. 269 float squared_sum = 0.0f; 270 for (int i = 0; i < num_vals; ++i) { 271 squared_sum += Square(values[i] - mean); 272 } 273 return sqrt(squared_sum / static_cast<float>(num_vals)); 274 } 275 276 277 inline float ComputeStdDev(const float* const values, 278 const int num_vals, 279 const float mean) { 280 return 281 #ifdef __ARM_NEON 282 (num_vals >= 8) ? ComputeStdDevNeon(values, num_vals, mean) : 283 #endif 284 ComputeStdDevCpu(values, num_vals, mean); 285 } 286 287 288 // TODO(andrewharp): Accelerate with NEON. 289 inline float ComputeWeightedMean(const float* const values, 290 const float* const weights, 291 const int num_vals) { 292 float sum = 0.0f; 293 float total_weight = 0.0f; 294 for (int i = 0; i < num_vals; ++i) { 295 sum += values[i] * weights[i]; 296 total_weight += weights[i]; 297 } 298 return sum / num_vals; 299 } 300 301 302 inline float ComputeCrossCorrelationCpu(const float* const values1, 303 const float* const values2, 304 const int num_vals) { 305 float sxy = 0.0f; 306 for (int offset = 0; offset < num_vals; ++offset) { 307 sxy += values1[offset] * values2[offset]; 308 } 309 310 const float cross_correlation = sxy / num_vals; 311 312 return cross_correlation; 313 } 314 315 316 inline float ComputeCrossCorrelation(const float* const values1, 317 const float* const values2, 318 const int num_vals) { 319 return 320 #ifdef __ARM_NEON 321 (num_vals >= 8) ? ComputeCrossCorrelationNeon(values1, values2, num_vals) 322 : 323 #endif 324 ComputeCrossCorrelationCpu(values1, values2, num_vals); 325 } 326 327 328 inline void NormalizeNumbers(float* const values, const int num_vals) { 329 // Find the mean and then subtract so that the new mean is 0.0. 330 const float mean = ComputeMean(values, num_vals); 331 VLOG(2) << "Mean is " << mean; 332 float* curr_data = values; 333 for (int i = 0; i < num_vals; ++i) { 334 *curr_data -= mean; 335 curr_data++; 336 } 337 338 // Now divide by the std deviation so the new standard deviation is 1.0. 339 // The numbers might all be identical (and thus shifted to 0.0 now), 340 // so only scale by the standard deviation if this is not the case. 341 const float std_dev = ComputeStdDev(values, num_vals, 0.0f); 342 if (std_dev > 0.0f) { 343 VLOG(2) << "Std dev is " << std_dev; 344 curr_data = values; 345 for (int i = 0; i < num_vals; ++i) { 346 *curr_data /= std_dev; 347 curr_data++; 348 } 349 } 350 } 351 352 353 // Returns the determinant of a 2x2 matrix. 354 template<class T> 355 inline T FindDeterminant2x2(const T* const a) { 356 // Determinant: (ad - bc) 357 return a[0] * a[3] - a[1] * a[2]; 358 } 359 360 361 // Finds the inverse of a 2x2 matrix. 362 // Returns true upon success, false if the matrix is not invertible. 363 template<class T> 364 inline bool Invert2x2(const T* const a, float* const a_inv) { 365 const float det = static_cast<float>(FindDeterminant2x2(a)); 366 if (fabs(det) < EPSILON) { 367 return false; 368 } 369 const float inv_det = 1.0f / det; 370 371 a_inv[0] = inv_det * static_cast<float>(a[3]); // d 372 a_inv[1] = inv_det * static_cast<float>(-a[1]); // -b 373 a_inv[2] = inv_det * static_cast<float>(-a[2]); // -c 374 a_inv[3] = inv_det * static_cast<float>(a[0]); // a 375 376 return true; 377 } 378 379 } // namespace tf_tracking 380 381 #endif // TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_UTILS_H_ 382