Sundry tweaks to aos/vision libs

Change-Id: Ia5578dcf2d42ac53b81af239bf329eb084fcf1d9
diff --git a/aos/vision/blob/move_scale.h b/aos/vision/blob/move_scale.h
index c113bca..e45e14d 100644
--- a/aos/vision/blob/move_scale.h
+++ b/aos/vision/blob/move_scale.h
@@ -1,8 +1,8 @@
 #ifndef AOS_VISION_BLOB_MOVE_SCALE_H_
 #define AOS_VISION_BLOB_MOVE_SCALE_H_
 
-#include <vector>
 #include <limits>
+#include <vector>
 
 #include "aos/vision/blob/range_image.h"
 
diff --git a/aos/vision/blob/range_image.cc b/aos/vision/blob/range_image.cc
index 5f2f29f..946859d 100644
--- a/aos/vision/blob/range_image.cc
+++ b/aos/vision/blob/range_image.cc
@@ -75,7 +75,7 @@
       if (span.ed > maxx) maxx = span.ed;
     }
   }
-  LOG(INFO, "maxx: %d minx: %d\n", maxx, minx);
+  printf("maxx: %d minx: %d\n", maxx, minx);
   char buf[maxx - minx];
   for (const auto &range : rimg.ranges()) {
     int i = minx;
@@ -84,7 +84,7 @@
       for (; i < span.ed; ++i) buf[i - minx] = '#';
     }
     for (; i < maxx; ++i) buf[i - minx] = ' ';
-    LOG(INFO, "%.*s\n", maxx - minx, buf);
+    printf("%.*s\n", maxx - minx, buf);
   }
 }
 
diff --git a/aos/vision/blob/stream_view.h b/aos/vision/blob/stream_view.h
index 2ae56ac..a6a661a 100644
--- a/aos/vision/blob/stream_view.h
+++ b/aos/vision/blob/stream_view.h
@@ -29,56 +29,51 @@
     memset(image_.data(), 0, fmt.ImgSize() * sizeof(PixelRef));
   }
 
-  inline void DrawBlobList(const BlobList &blob_list, PixelRef color) {
+  template <typename PixelCallback>
+  inline void ForPxInBlobList(const BlobList &blob_list,
+                              PixelCallback pixel_callback) {
     ImagePtr ptr = img();
-    for (const RangeImage &blob : blob_list) {
+    auto fmt = ptr.fmt();
+    for (const auto &blob : blob_list) {
       for (int i = 0; i < (int)blob.ranges().size(); ++i) {
-        for (const auto &range : blob.ranges()[i]) {
-          for (int j = range.st; j < range.ed; ++j) {
-            ptr.get_px(j, i + blob.min_y()) = color;
+        int y = blob.min_y() + i;
+        if (y >= 0 && y < fmt.h) {
+          for (const auto &range : blob.ranges()[i]) {
+            for (int j = std::max(0, range.st); j < std::min(fmt.w, range.ed);
+                 ++j) {
+              pixel_callback(ptr.get_px(j, y));
+            }
           }
         }
       }
     }
   }
 
+  inline void DrawBlobList(const BlobList &blob_list, PixelRef color) {
+    ForPxInBlobList(blob_list, [&](PixelRef &px) { px = color; });
+  }
+
   inline void DrawSecondBlobList(const BlobList &blob_list, PixelRef color1,
                                  PixelRef color2) {
-    ImagePtr ptr = img();
-    for (const auto &blob : blob_list) {
-      for (int i = 0; i < (int)blob.ranges().size(); ++i) {
-        for (const auto &range : blob.ranges()[i]) {
-          for (int j = range.st; j < range.ed; ++j) {
-            auto px = ptr.get_px(j, i + blob.min_y());
-            if (px.r == 0 && px.g == 0 && px.b == 0) {
-              ptr.get_px(j, i + blob.min_y()) = color1;
-            } else {
-              ptr.get_px(j, i + blob.min_y()) = color2;
-            }
-          }
-        }
+    ForPxInBlobList(blob_list, [&](PixelRef &px) {
+      if (px.r == 0 && px.g == 0 && px.b == 0) {
+        px = color1;
+      } else {
+        px = color2;
       }
-    }
+    });
   }
 
   inline void DrawSecondBlobList(const BlobList &blob_list, PixelRef color1,
                                  PixelRef color2, PixelRef prev_color) {
-    ImagePtr ptr = img();
-    for (const auto &blob : blob_list) {
-      for (int i = 0; i < (int)blob.ranges().size(); ++i) {
-        for (const auto &range : blob.ranges()[i]) {
-          for (int j = range.st; j < range.ed; ++j) {
-            auto px = ptr.get_px(j, i + blob.min_y());
-            if (px.r == prev_color.r && px.g == prev_color.g &&
-                px.b == prev_color.b) {
-              ptr.get_px(j, i + blob.min_y()) = color2;
-            } else {
-              ptr.get_px(j, i + blob.min_y()) = color1;
-            }
-          }
-        }
+    ForPxInBlobList(blob_list, [&](PixelRef &px) {
+      if (px.r == prev_color.r && px.g == prev_color.g &&
+          px.b == prev_color.b) {
+        px = color2;
+      } else {
+        px = color1;
       }
-    }
+    });
   }
 
   // Backwards compatible.
diff --git a/aos/vision/blob/transpose.cc b/aos/vision/blob/transpose.cc
index 19ac965..72e1cc1 100644
--- a/aos/vision/blob/transpose.cc
+++ b/aos/vision/blob/transpose.cc
@@ -1,6 +1,7 @@
 #include "aos/vision/blob/transpose.h"
 
 #include <algorithm>
+#include <limits>
 
 namespace aos {
 namespace vision {
@@ -14,27 +15,30 @@
     kPointAdd = 3,
     kPointDel = 2,
   };
+  int min_y = std::numeric_limits<int>::max();
+  for (const std::vector<ImageRange> &row : img) {
+    if (!row.empty()) min_y = std::min(row[0].st, min_y);
+  }
+
   std::vector<std::vector<std::pair<int, EventT>>> events;
   int y = img.min_y();
   for (const std::vector<ImageRange> &row : img) {
     for (const ImageRange &range : row) {
-      if (range.ed >= static_cast<int>(events.size()))
-        events.resize(range.ed + 1);
-      events[range.st].emplace_back(y, kPointAdd);
-      events[range.ed].emplace_back(y, kPointDel);
+      if (range.ed - min_y >= static_cast<int>(events.size())) {
+        events.resize(range.ed - min_y + 1);
+      }
+      events[range.st - min_y].emplace_back(y, kPointAdd);
+      events[range.ed - min_y].emplace_back(y, kPointDel);
     }
     ++y;
   }
 
-  int min_y = 0;
-  while (min_y < (int)events.size() && events[min_y].empty()) ++min_y;
-
   std::vector<ImageRange> prev_ranges;
   std::vector<ImageRange> cur_ranges;
 
   std::vector<std::vector<ImageRange>> rows;
-  for (int y = min_y; y < static_cast<int>(events.size()) - 1; ++y) {
-    auto row_events = std::move(events[y]);
+  for (int dy = 0; dy < static_cast<int>(events.size()) - 1; ++dy) {
+    auto row_events = std::move(events[dy]);
     for (const auto &range : prev_ranges) {
       row_events.emplace_back(range.st, kRangeStart);
       row_events.emplace_back(range.ed, kRangeEnd);