Home | History | Annotate | Download | only in object_tracking
      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