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_INTEGRAL_IMAGE_H_ 17 #define TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_INTEGRAL_IMAGE_H_ 18 19 #include "tensorflow/tools/android/test/jni/object_tracking/geom.h" 20 #include "tensorflow/tools/android/test/jni/object_tracking/image-inl.h" 21 #include "tensorflow/tools/android/test/jni/object_tracking/image.h" 22 #include "tensorflow/tools/android/test/jni/object_tracking/utils.h" 23 24 namespace tf_tracking { 25 26 typedef uint8_t Code; 27 28 class IntegralImage : public Image<uint32_t> { 29 public: IntegralImage(const Image<uint8_t> & image_base)30 explicit IntegralImage(const Image<uint8_t>& image_base) 31 : Image<uint32_t>(image_base.GetWidth(), image_base.GetHeight()) { 32 Recompute(image_base); 33 } 34 IntegralImage(const int width,const int height)35 IntegralImage(const int width, const int height) 36 : Image<uint32_t>(width, height) {} 37 Recompute(const Image<uint8_t> & image_base)38 void Recompute(const Image<uint8_t>& image_base) { 39 SCHECK(image_base.GetWidth() == GetWidth() && 40 image_base.GetHeight() == GetHeight(), "Dimensions don't match!"); 41 42 // Sum along first row. 43 { 44 int x_sum = 0; 45 for (int x = 0; x < image_base.GetWidth(); ++x) { 46 x_sum += image_base[0][x]; 47 (*this)[0][x] = x_sum; 48 } 49 } 50 51 // Sum everything else. 52 for (int y = 1; y < image_base.GetHeight(); ++y) { 53 uint32_t* curr_sum = (*this)[y]; 54 55 // Previously summed pointers. 56 const uint32_t* up_one = (*this)[y - 1]; 57 58 // Current value pointer. 59 const uint8_t* curr_delta = image_base[y]; 60 61 uint32_t row_till_now = 0; 62 63 for (int x = 0; x < GetWidth(); ++x) { 64 // Add the one above and the one to the left. 65 row_till_now += *curr_delta; 66 *curr_sum = *up_one + row_till_now; 67 68 // Scoot everything along. 69 ++curr_sum; 70 ++up_one; 71 ++curr_delta; 72 } 73 } 74 75 SCHECK(VerifyData(image_base), "Images did not match!"); 76 } 77 VerifyData(const Image<uint8_t> & image_base)78 bool VerifyData(const Image<uint8_t>& image_base) { 79 for (int y = 0; y < GetHeight(); ++y) { 80 for (int x = 0; x < GetWidth(); ++x) { 81 uint32_t curr_val = (*this)[y][x]; 82 83 if (x > 0) { 84 curr_val -= (*this)[y][x - 1]; 85 } 86 87 if (y > 0) { 88 curr_val -= (*this)[y - 1][x]; 89 } 90 91 if (x > 0 && y > 0) { 92 curr_val += (*this)[y - 1][x - 1]; 93 } 94 95 if (curr_val != image_base[y][x]) { 96 LOGE("Mismatch! %d vs %d", curr_val, image_base[y][x]); 97 return false; 98 } 99 100 if (GetRegionSum(x, y, x, y) != curr_val) { 101 LOGE("Mismatch!"); 102 } 103 } 104 } 105 106 return true; 107 } 108 109 // Returns the sum of all pixels in the specified region. GetRegionSum(const int x1,const int y1,const int x2,const int y2)110 inline uint32_t GetRegionSum(const int x1, const int y1, const int x2, 111 const int y2) const { 112 SCHECK(x1 >= 0 && y1 >= 0 && 113 x2 >= x1 && y2 >= y1 && x2 < GetWidth() && y2 < GetHeight(), 114 "indices out of bounds! %d-%d / %d, %d-%d / %d, ", 115 x1, x2, GetWidth(), y1, y2, GetHeight()); 116 117 const uint32_t everything = (*this)[y2][x2]; 118 119 uint32_t sum = everything; 120 if (x1 > 0 && y1 > 0) { 121 // Most common case. 122 const uint32_t left = (*this)[y2][x1 - 1]; 123 const uint32_t top = (*this)[y1 - 1][x2]; 124 const uint32_t top_left = (*this)[y1 - 1][x1 - 1]; 125 126 sum = everything - left - top + top_left; 127 SCHECK(sum >= 0, "Both: %d - %d - %d + %d => %d! indices: %d %d %d %d", 128 everything, left, top, top_left, sum, x1, y1, x2, y2); 129 } else if (x1 > 0) { 130 // Flush against top of image. 131 // Subtract out the region to the left only. 132 const uint32_t top = (*this)[y2][x1 - 1]; 133 sum = everything - top; 134 SCHECK(sum >= 0, "Top: %d - %d => %d!", everything, top, sum); 135 } else if (y1 > 0) { 136 // Flush against left side of image. 137 // Subtract out the region above only. 138 const uint32_t left = (*this)[y1 - 1][x2]; 139 sum = everything - left; 140 SCHECK(sum >= 0, "Left: %d - %d => %d!", everything, left, sum); 141 } 142 143 SCHECK(sum >= 0, "Negative sum!"); 144 145 return sum; 146 } 147 148 // Returns the 2bit code associated with this region, which represents 149 // the overall gradient. GetCode(const BoundingBox & bounding_box)150 inline Code GetCode(const BoundingBox& bounding_box) const { 151 return GetCode(bounding_box.left_, bounding_box.top_, 152 bounding_box.right_, bounding_box.bottom_); 153 } 154 GetCode(const int x1,const int y1,const int x2,const int y2)155 inline Code GetCode(const int x1, const int y1, 156 const int x2, const int y2) const { 157 SCHECK(x1 < x2 && y1 < y2, "Bounds out of order!! TL:%d,%d BR:%d,%d", 158 x1, y1, x2, y2); 159 160 // Gradient computed vertically. 161 const int box_height = (y2 - y1) / 2; 162 const int top_sum = GetRegionSum(x1, y1, x2, y1 + box_height); 163 const int bottom_sum = GetRegionSum(x1, y2 - box_height, x2, y2); 164 const bool vertical_code = top_sum > bottom_sum; 165 166 // Gradient computed horizontally. 167 const int box_width = (x2 - x1) / 2; 168 const int left_sum = GetRegionSum(x1, y1, x1 + box_width, y2); 169 const int right_sum = GetRegionSum(x2 - box_width, y1, x2, y2); 170 const bool horizontal_code = left_sum > right_sum; 171 172 const Code final_code = (vertical_code << 1) | horizontal_code; 173 174 SCHECK(InRange(final_code, static_cast<Code>(0), static_cast<Code>(3)), 175 "Invalid code! %d", final_code); 176 177 // Returns a value 0-3. 178 return final_code; 179 } 180 181 private: 182 TF_DISALLOW_COPY_AND_ASSIGN(IntegralImage); 183 }; 184 185 } // namespace tf_tracking 186 187 #endif // TENSORFLOW_EXAMPLES_ANDROID_JNI_OBJECT_TRACKING_INTEGRAL_IMAGE_H_ 188