Parker Schuh | d7db83d | 2017-02-08 20:49:15 -0800 | [diff] [blame] | 1 | #include <stdio.h> |
| 2 | #include <stdlib.h> |
| 3 | |
| 4 | #include <vector> |
| 5 | #include <memory> |
| 6 | #include <endian.h> |
Parker Schuh | 24ee58d | 2017-03-11 16:13:23 -0800 | [diff] [blame] | 7 | #include <sys/stat.h> |
Parker Schuh | d7db83d | 2017-02-08 20:49:15 -0800 | [diff] [blame] | 8 | #include <fstream> |
| 9 | #include <gdk/gdk.h> |
| 10 | #include <gtk/gtk.h> |
| 11 | |
| 12 | #include "aos/vision/image/reader.h" |
| 13 | #include "aos/vision/image/jpeg_routines.h" |
| 14 | #include "aos/vision/image/image_stream.h" |
| 15 | #include "aos/vision/events/epoll_events.h" |
| 16 | #include "aos/vision/events/tcp_server.h" |
Parker Schuh | d7db83d | 2017-02-08 20:49:15 -0800 | [diff] [blame] | 17 | #include "aos/vision/blob/stream_view.h" |
| 18 | #include "y2016/vision/blob_filters.h" |
| 19 | // #include "y2016/vision/process_targets.h" |
| 20 | |
| 21 | namespace y2016 { |
| 22 | namespace vision { |
| 23 | using namespace aos::vision; |
| 24 | |
| 25 | ::aos::vision::Vector<2> CreateCenterFromTarget(double lx, double ly, double rx, double ry) { |
| 26 | return ::aos::vision::Vector<2>((lx + rx) / 2.0, (ly + ry) / 2.0); |
| 27 | } |
| 28 | |
| 29 | double TargetWidth(double lx, double ly, double rx, double ry) { |
| 30 | double dx = lx - rx; |
| 31 | double dy = ly - ry; |
| 32 | return ::std::hypot(dx, dy); |
| 33 | } |
| 34 | |
| 35 | void SelectTargets(std::vector<std::pair<Vector<2>, Vector<2>>>& left_target, |
| 36 | std::vector<std::pair<Vector<2>, Vector<2>>>&right_target, |
| 37 | ::aos::vision::Vector<2> *center_left, |
| 38 | ::aos::vision::Vector<2> *center_right) { |
| 39 | // No good targets. Let the caller decide defaults. |
| 40 | if (right_target.size() == 0 || left_target.size() == 0) { |
| 41 | return; |
| 42 | } |
| 43 | |
| 44 | // Only one option, we have to go with it. |
| 45 | if (right_target.size() == 1 && left_target.size() == 1) { |
| 46 | *center_left = |
| 47 | CreateCenterFromTarget(left_target[0].first.x(), left_target[0].first.y(), |
| 48 | left_target[0].second.x(), left_target[0].second.y()); |
| 49 | *center_right = CreateCenterFromTarget( |
| 50 | right_target[0].first.x(), right_target[0].first.y(), right_target[0].second.x(), |
| 51 | right_target[0].second.y()); |
| 52 | return; |
| 53 | } |
| 54 | |
| 55 | // Now we have to make a decision. |
| 56 | double min_angle = -1.0; |
| 57 | int left_index = 0; |
| 58 | // First pick the widest target from the left. |
| 59 | for (size_t i = 0; i < left_target.size(); i++) { |
| 60 | const double h = left_target[i].first.y() - |
| 61 | left_target[i].second.y(); |
| 62 | const double wid1 = TargetWidth(left_target[i].first.x(), |
| 63 | left_target[i].first.y(), |
| 64 | left_target[i].second.x(), |
| 65 | left_target[i].second.y()); |
| 66 | const double angle = h / wid1; |
| 67 | if (min_angle == -1.0 || ::std::abs(angle) < ::std::abs(min_angle)) { |
| 68 | min_angle = angle; |
| 69 | left_index = i; |
| 70 | } |
| 71 | } |
| 72 | // Calculate the angle of the bottom edge for the left. |
| 73 | double h = left_target[left_index].first.y() - |
| 74 | left_target[left_index].second.y(); |
| 75 | |
| 76 | double good_ang = min_angle; |
| 77 | double min_ang_err = -1.0; |
| 78 | int right_index = -1; |
| 79 | // Now pick the bottom edge angle from the right that lines up best with the left. |
| 80 | for (size_t j = 0; j < right_target.size(); j++) { |
| 81 | double wid2 = TargetWidth(right_target[j].first.x(), |
| 82 | right_target[j].first.y(), |
| 83 | right_target[j].second.x(), |
| 84 | right_target[j].second.y()); |
| 85 | h = right_target[j].first.y() - |
| 86 | right_target[j].second.y(); |
| 87 | double ang = h/ wid2; |
| 88 | double ang_err = ::std::abs(good_ang - ang); |
| 89 | if (min_ang_err == -1.0 || min_ang_err > ang_err) { |
| 90 | min_ang_err = ang_err; |
| 91 | right_index = j; |
| 92 | } |
| 93 | } |
| 94 | |
| 95 | *center_left = |
| 96 | CreateCenterFromTarget(left_target[left_index].first.x(), |
| 97 | left_target[left_index].first.y(), |
| 98 | left_target[left_index].second.x(), |
| 99 | left_target[left_index].second.y()); |
| 100 | *center_right = |
| 101 | CreateCenterFromTarget(right_target[right_index].first.x(), |
| 102 | right_target[right_index].first.y(), |
| 103 | right_target[right_index].second.x(), |
| 104 | right_target[right_index].second.y()); |
| 105 | } |
| 106 | |
| 107 | |
| 108 | long GetFileSize(std::string filename) { |
| 109 | struct stat stat_buf; |
| 110 | int rc = stat(filename.c_str(), &stat_buf); |
| 111 | return rc == 0 ? stat_buf.st_size : -1; |
| 112 | } |
| 113 | |
| 114 | class OutputFile { |
| 115 | public: |
| 116 | OutputFile(const std::string &fname) : ofs(fname, std::ofstream::out) {} |
| 117 | |
| 118 | void Emit(const BlobList &blobl, int64_t timestamp) { |
| 119 | int tmp_size = CalculateSize(blobl) + sizeof(int32_t) + sizeof(uint64_t); |
| 120 | tmp_buf.resize(tmp_size, 0); |
| 121 | { |
| 122 | char *buf = Int64Codec::Write(&tmp_buf[0], tmp_size); |
| 123 | buf = Int64Codec::Write(buf, timestamp); |
| 124 | SerializeBlob(blobl, buf); |
| 125 | } |
| 126 | ofs.write(&tmp_buf[0], tmp_size); |
| 127 | printf("blob_size: %d\n", tmp_size); |
| 128 | } |
| 129 | |
| 130 | std::vector<char> tmp_buf; |
| 131 | |
| 132 | std::ofstream ofs; |
| 133 | }; |
| 134 | |
| 135 | class InputFile { |
| 136 | public: |
| 137 | InputFile(const std::string &fname) |
| 138 | : ifs_(fname, std::ifstream::in), len_(GetFileSize(fname)) { |
| 139 | if (len_ <= 0) { |
| 140 | printf("File (%s) not found. Size (%d)\n", fname.c_str(), (int)len_); |
| 141 | fflush(stdout); |
| 142 | } |
| 143 | assert(len_ > 0); |
| 144 | tmp_buf_.resize(len_, 0); |
| 145 | ifs_.read(&tmp_buf_[0], len_); |
| 146 | buf_ = &tmp_buf_[0]; |
| 147 | } |
| 148 | |
| 149 | bool ReadNext(BlobList *blob_list, uint64_t *timestamp) { |
| 150 | if (buf_ - &tmp_buf_[0] >= len_) return false; |
| 151 | if (prev_ != nullptr) prev_frames_.emplace_back(prev_); |
| 152 | prev_ = buf_; |
| 153 | buf_ += sizeof(uint32_t); |
| 154 | *timestamp = Int64Codec::Read(&buf_); |
| 155 | // auto* buf_tmp = buf_; |
| 156 | buf_ = ParseBlobList(blob_list, buf_); |
| 157 | // fprintf(stderr, "read frame: %lu, buf_size: %lu\n", *timestamp, buf_ - buf_tmp); |
| 158 | return true; |
| 159 | } |
| 160 | |
| 161 | bool ReadPrev(BlobList *blob_list, uint64_t *timestamp) { |
| 162 | if (prev_frames_.empty()) return false; |
| 163 | buf_ = prev_frames_.back(); |
| 164 | prev_frames_.pop_back(); |
| 165 | buf_ += sizeof(uint32_t); |
| 166 | *timestamp = Int64Codec::Read(&buf_); |
| 167 | buf_ = ParseBlobList(blob_list, buf_); |
| 168 | prev_ = nullptr; |
| 169 | return true; |
| 170 | } |
| 171 | |
| 172 | private: |
| 173 | std::vector<const char *> prev_frames_; |
| 174 | const char *buf_; |
| 175 | const char *prev_ = nullptr; |
| 176 | std::ifstream ifs_; |
| 177 | |
| 178 | long len_; |
| 179 | std::vector<char> tmp_buf_; |
| 180 | }; |
| 181 | |
| 182 | class BlobStreamFrame { |
| 183 | public: |
| 184 | BlobList blob_list; |
| 185 | uint64_t timestamp; |
| 186 | void ReadNext(InputFile *fin) { |
| 187 | blob_list.clear(); |
| 188 | if (!fin->ReadNext(&blob_list, ×tamp)) { |
| 189 | exit(0); |
| 190 | return; |
| 191 | } |
| 192 | } |
| 193 | bool ReadPrev(InputFile *fin) { |
| 194 | blob_list.clear(); |
| 195 | return fin->ReadPrev(&blob_list, ×tamp); |
| 196 | } |
| 197 | }; |
| 198 | |
| 199 | const char *kHudText = |
| 200 | "commands:\n" |
| 201 | " SPACE - pause\n" |
| 202 | " c - continue to next target\n" |
| 203 | " s - single step while paused\n" |
| 204 | " k - pause on next target frame\n" |
| 205 | " u - change window scaling\n" |
| 206 | " a - single step backward\n" |
| 207 | " q - quit\n" |
| 208 | " h - help\n"; |
| 209 | |
| 210 | class NetworkForwardingImageStream : public aos::events::EpollWait { |
| 211 | public: |
| 212 | NetworkForwardingImageStream(ImageFormat fmt, int debug_level, |
| 213 | const std::string &fname1, |
| 214 | const std::string &fname2) |
| 215 | : fmt_(fmt), |
| 216 | ifs1_(fname1), |
| 217 | ifs2_(fname2), |
| 218 | blob_filt_(fmt, 40, 750, 250000), |
| 219 | finder_(0.25, 35) { |
| 220 | text_overlay_.draw_fn = |
| 221 | [this](RenderInterface *render, double /*width*/, double /*height*/) { |
| 222 | render->SetSourceRGB(1.0, 1.0, 1.0); |
| 223 | if (hud_text) render->Text(20, 20, 0, 0, kHudText); |
| 224 | }; |
| 225 | |
| 226 | overlays_.push_back(&overlay_); |
| 227 | overlays_.push_back(&text_overlay_); |
| 228 | view_.view()->SetOverlays(&overlays_); |
| 229 | |
| 230 | if (debug_level > 0) { |
| 231 | finder_.EnableOverlay(&overlay_); |
| 232 | } |
| 233 | if (debug_level > 1) { |
| 234 | blob_filt_.EnableOverlay(&overlay_); |
| 235 | } |
| 236 | |
| 237 | frame1.ReadNext(&ifs1_); |
| 238 | frame2.ReadNext(&ifs2_); |
| 239 | |
| 240 | std::pair<int, int> skip = |
| 241 | TickFrame(std::max(frame1.timestamp, frame2.timestamp)); |
| 242 | printf("Initialzation skipped (%d, %d)\n", skip.first, skip.second); |
| 243 | |
| 244 | ms_event_delta_ = 20; |
| 245 | play_forward = true; |
| 246 | paused = false; |
| 247 | single_step = false; |
| 248 | pause_on_next_target = true; |
| 249 | continue_to_next_target = false; |
| 250 | view_.view()->SetScale(scale_factor); |
| 251 | view_.view()->key_press_event = [this](uint32_t keyval) { |
| 252 | play_forward = true; |
| 253 | switch (keyval) { |
| 254 | case GDK_KEY_space: |
| 255 | paused = !paused; |
| 256 | pause_on_next_target = false; |
| 257 | continue_to_next_target = false; |
| 258 | break; |
| 259 | case GDK_KEY_c: |
| 260 | pause_on_next_target = true; |
| 261 | continue_to_next_target = true; |
| 262 | paused = false; |
| 263 | break; |
| 264 | case GDK_KEY_s: |
| 265 | single_step = true; |
| 266 | continue_to_next_target = false; |
| 267 | paused = true; |
| 268 | break; |
| 269 | case GDK_KEY_k: |
| 270 | pause_on_next_target = true; |
| 271 | continue_to_next_target = false; |
| 272 | paused = false; |
| 273 | break; |
| 274 | case GDK_KEY_u: |
| 275 | if (scale_factor == 1.0) { |
| 276 | scale_factor = 0.75; |
| 277 | view_.view()->SetScale(0.75); |
| 278 | } else { |
| 279 | scale_factor = 1.0; |
| 280 | view_.view()->SetScale(1.0); |
| 281 | view_.view()->MoveTo(150, -220); |
| 282 | } |
| 283 | break; |
| 284 | case GDK_KEY_a: |
| 285 | play_forward = false; |
| 286 | single_step = true; |
| 287 | paused = true; |
| 288 | break; |
| 289 | case GDK_KEY_q: |
| 290 | exit(0); |
| 291 | case GDK_KEY_h: |
| 292 | hud_text = !hud_text; |
| 293 | break; |
| 294 | default: |
| 295 | printf("pressed: %s\n", gdk_keyval_name(keyval)); |
| 296 | } |
| 297 | }; |
| 298 | } |
| 299 | |
| 300 | double scale_factor = 1.0; |
| 301 | bool hud_text = true; |
| 302 | bool play_forward; |
| 303 | bool paused; |
| 304 | bool single_step; |
| 305 | bool pause_on_next_target; |
| 306 | bool continue_to_next_target; |
| 307 | |
| 308 | std::string distance_text; |
| 309 | |
| 310 | std::pair<int, int> TickFrame(uint64_t time) { |
| 311 | timestamp_ += time; |
| 312 | return TickToFrame(timestamp_); |
| 313 | } |
| 314 | |
| 315 | std::pair<int, int> TickBackFrame(uint64_t time) { |
| 316 | timestamp_ -= time; |
| 317 | return TickBackToFrame(timestamp_); |
| 318 | } |
| 319 | |
| 320 | std::pair<int, int> TickToFrame(uint64_t timestamp) { |
| 321 | std::pair<int, int> skip(0, 0); |
| 322 | while (frame1.timestamp < timestamp) { |
| 323 | frame1.ReadNext(&ifs1_); |
| 324 | skip.first++; |
| 325 | } |
| 326 | while (frame2.timestamp < timestamp) { |
| 327 | frame2.ReadNext(&ifs2_); |
| 328 | skip.second++; |
| 329 | } |
| 330 | return skip; |
| 331 | } |
| 332 | |
| 333 | std::pair<int, int> TickBackToFrame(uint64_t timestamp) { |
| 334 | std::pair<int, int> skip(0, 0); |
| 335 | while (frame1.timestamp >= timestamp) { |
| 336 | if (!frame1.ReadPrev(&ifs1_)) break; |
| 337 | skip.first++; |
| 338 | } |
| 339 | while (frame2.timestamp >= timestamp) { |
| 340 | if (!frame2.ReadPrev(&ifs2_)) break; |
| 341 | skip.second++; |
| 342 | } |
| 343 | frame1.ReadPrev(&ifs1_); |
| 344 | frame2.ReadPrev(&ifs2_); |
| 345 | return skip; |
| 346 | } |
| 347 | BlobStreamFrame frame1; |
| 348 | BlobStreamFrame frame2; |
| 349 | uint64_t timestamp_ = 0; |
| 350 | |
| 351 | Vector<2> GetCenter(const BlobList &blob_list) { |
| 352 | std::vector<std::pair<Vector<2>, Vector<2>>> corners = |
| 353 | finder_.Find(blob_filt_.FilterBlobs(blob_list)); |
| 354 | |
| 355 | if (corners.size() == 1) { |
| 356 | Vector<2> center = (corners[0].first + corners[0].second) * (0.5); |
| 357 | return center; |
| 358 | } |
| 359 | return {0, 0}; |
| 360 | } |
| 361 | |
| 362 | void DrawSuperSpeed() { |
| 363 | PixelRef color = {0, 255, 255}; |
| 364 | // S |
Parker Schuh | 24ee58d | 2017-03-11 16:13:23 -0800 | [diff] [blame] | 365 | overlay_.AddLine(Vector<2>(200, 100), Vector<2>(100, 100), color); |
| 366 | overlay_.AddLine(Vector<2>(100, 100), Vector<2>(100, 300), color); |
| 367 | overlay_.AddLine(Vector<2>(100, 300), Vector<2>(200, 300), color); |
| 368 | overlay_.AddLine(Vector<2>(200, 300), Vector<2>(200, 500), color); |
| 369 | overlay_.AddLine(Vector<2>(200, 500), Vector<2>(100, 500), color); |
Parker Schuh | d7db83d | 2017-02-08 20:49:15 -0800 | [diff] [blame] | 370 | // U |
Parker Schuh | 24ee58d | 2017-03-11 16:13:23 -0800 | [diff] [blame] | 371 | overlay_.AddLine(Vector<2>(250, 100), Vector<2>(250, 500), color); |
| 372 | overlay_.AddLine(Vector<2>(250, 500), Vector<2>(350, 500), color); |
| 373 | overlay_.AddLine(Vector<2>(350, 500), Vector<2>(350, 100), color); |
Parker Schuh | d7db83d | 2017-02-08 20:49:15 -0800 | [diff] [blame] | 374 | // P |
Parker Schuh | 24ee58d | 2017-03-11 16:13:23 -0800 | [diff] [blame] | 375 | overlay_.AddLine(Vector<2>(400, 100), Vector<2>(400, 500), color); |
| 376 | overlay_.AddLine(Vector<2>(400, 100), Vector<2>(500, 100), color); |
| 377 | overlay_.AddLine(Vector<2>(500, 100), Vector<2>(500, 300), color); |
| 378 | overlay_.AddLine(Vector<2>(500, 300), Vector<2>(400, 300), color); |
Parker Schuh | d7db83d | 2017-02-08 20:49:15 -0800 | [diff] [blame] | 379 | // E |
Parker Schuh | 24ee58d | 2017-03-11 16:13:23 -0800 | [diff] [blame] | 380 | overlay_.AddLine(Vector<2>(550, 100), Vector<2>(550, 500), color); |
| 381 | overlay_.AddLine(Vector<2>(550, 100), Vector<2>(650, 100), color); |
| 382 | overlay_.AddLine(Vector<2>(550, 300), Vector<2>(650, 300), color); |
| 383 | overlay_.AddLine(Vector<2>(550, 500), Vector<2>(650, 500), color); |
Parker Schuh | d7db83d | 2017-02-08 20:49:15 -0800 | [diff] [blame] | 384 | // R |
Parker Schuh | 24ee58d | 2017-03-11 16:13:23 -0800 | [diff] [blame] | 385 | overlay_.AddLine(Vector<2>(700, 100), Vector<2>(700, 500), color); |
| 386 | overlay_.AddLine(Vector<2>(700, 100), Vector<2>(800, 100), color); |
| 387 | overlay_.AddLine(Vector<2>(800, 100), Vector<2>(800, 300), color); |
| 388 | overlay_.AddLine(Vector<2>(800, 300), Vector<2>(700, 300), color); |
| 389 | overlay_.AddLine(Vector<2>(700, 350), Vector<2>(800, 500), color); |
Parker Schuh | d7db83d | 2017-02-08 20:49:15 -0800 | [diff] [blame] | 390 | // S |
Parker Schuh | 24ee58d | 2017-03-11 16:13:23 -0800 | [diff] [blame] | 391 | overlay_.AddLine(Vector<2>(200, 550), Vector<2>(100, 550), color); |
| 392 | overlay_.AddLine(Vector<2>(100, 550), Vector<2>(100, 750), color); |
| 393 | overlay_.AddLine(Vector<2>(100, 750), Vector<2>(200, 750), color); |
| 394 | overlay_.AddLine(Vector<2>(200, 750), Vector<2>(200, 950), color); |
| 395 | overlay_.AddLine(Vector<2>(200, 950), Vector<2>(100, 950), color); |
Parker Schuh | d7db83d | 2017-02-08 20:49:15 -0800 | [diff] [blame] | 396 | // P |
Parker Schuh | 24ee58d | 2017-03-11 16:13:23 -0800 | [diff] [blame] | 397 | overlay_.AddLine(Vector<2>(250, 550), Vector<2>(250, 950), color); |
| 398 | overlay_.AddLine(Vector<2>(250, 550), Vector<2>(350, 550), color); |
| 399 | overlay_.AddLine(Vector<2>(350, 550), Vector<2>(350, 750), color); |
| 400 | overlay_.AddLine(Vector<2>(350, 750), Vector<2>(250, 750), color); |
Parker Schuh | d7db83d | 2017-02-08 20:49:15 -0800 | [diff] [blame] | 401 | // E |
Parker Schuh | 24ee58d | 2017-03-11 16:13:23 -0800 | [diff] [blame] | 402 | overlay_.AddLine(Vector<2>(400, 550), Vector<2>(400, 950), color); |
| 403 | overlay_.AddLine(Vector<2>(400, 550), Vector<2>(500, 550), color); |
| 404 | overlay_.AddLine(Vector<2>(400, 750), Vector<2>(500, 750), color); |
| 405 | overlay_.AddLine(Vector<2>(400, 950), Vector<2>(500, 950), color); |
Parker Schuh | d7db83d | 2017-02-08 20:49:15 -0800 | [diff] [blame] | 406 | // E |
Parker Schuh | 24ee58d | 2017-03-11 16:13:23 -0800 | [diff] [blame] | 407 | overlay_.AddLine(Vector<2>(550, 550), Vector<2>(550, 950), color); |
| 408 | overlay_.AddLine(Vector<2>(550, 550), Vector<2>(650, 550), color); |
| 409 | overlay_.AddLine(Vector<2>(550, 750), Vector<2>(650, 750), color); |
| 410 | overlay_.AddLine(Vector<2>(550, 950), Vector<2>(650, 950), color); |
Parker Schuh | d7db83d | 2017-02-08 20:49:15 -0800 | [diff] [blame] | 411 | // D |
Parker Schuh | 24ee58d | 2017-03-11 16:13:23 -0800 | [diff] [blame] | 412 | overlay_.AddLine(Vector<2>(700, 550), Vector<2>(700, 950), color); |
| 413 | overlay_.AddLine(Vector<2>(700, 550), Vector<2>(800, 575), color); |
| 414 | overlay_.AddLine(Vector<2>(800, 575), Vector<2>(800, 925), color); |
| 415 | overlay_.AddLine(Vector<2>(800, 925), Vector<2>(700, 950), color); |
Parker Schuh | d7db83d | 2017-02-08 20:49:15 -0800 | [diff] [blame] | 416 | } |
| 417 | |
| 418 | void UpdateNewTime(int new_delta) { |
| 419 | if (new_delta != ms_event_delta_) { |
| 420 | ms_event_delta_ = new_delta; |
| 421 | SetTime(::std::chrono::milliseconds(ms_event_delta_) + aos::monotonic_clock::now()); |
| 422 | } |
| 423 | } |
| 424 | |
| 425 | void Done() override { |
| 426 | SetTime(::std::chrono::milliseconds(ms_event_delta_) + aos::monotonic_clock::now()); |
| 427 | if (paused && !single_step) return; |
| 428 | single_step = false; |
| 429 | frame_count_++; |
| 430 | |
| 431 | while (true) { |
| 432 | overlay_.Reset(); |
| 433 | view_.SetFormatAndClear(fmt_); |
| 434 | std::pair<int, int> skipped(1, 1); |
| 435 | // how far we will step to look for the next target |
| 436 | int nano_step = 300 * 1e6; |
| 437 | if (play_forward && seeking_target_) { |
| 438 | skipped = TickFrame(nano_step); |
| 439 | } else if (seeking_target_) { |
| 440 | skipped = TickBackFrame(nano_step); |
| 441 | } else if (play_forward) { |
| 442 | frame1.ReadNext(&ifs1_); |
| 443 | frame2.ReadNext(&ifs2_); |
| 444 | } else { |
| 445 | frame1.ReadPrev(&ifs1_); |
| 446 | frame2.ReadPrev(&ifs2_); |
| 447 | } |
| 448 | // printf("skipped (%d, %d)\n", skipped.first, skipped.second); |
| 449 | |
| 450 | std::vector<std::pair<Vector<2>, Vector<2>>> corner1 = |
| 451 | finder_.Find(blob_filt_.FilterBlobs(frame1.blob_list)); |
| 452 | std::vector<std::pair<Vector<2>, Vector<2>>> corner2 = |
| 453 | finder_.Find(blob_filt_.FilterBlobs(frame2.blob_list)); |
| 454 | |
| 455 | Vector<2> cent1; |
| 456 | Vector<2> cent2; |
| 457 | SelectTargets(corner1, corner2, ¢1, ¢2); |
| 458 | |
| 459 | /* |
| 460 | int target_count_; |
| 461 | if (cent1 == Vector<2>(0, 0) && cent2 == Vector<2>(0, 0)) { |
| 462 | missed_count_ += std::min(skipped.first, skipped.second); |
| 463 | if (missed_count_ > 15) { |
| 464 | seeking_target_ = true; |
| 465 | DrawSuperSpeed(); |
| 466 | SetTime(aos::vision::MsTime(1)); |
| 467 | if (line_break_) { |
| 468 | printf("_-_-_-%d_-_-_-_\n", target_count_); |
| 469 | target_count_++; |
| 470 | line_break_ = false; |
| 471 | } |
| 472 | if (continue_to_next_target) { |
| 473 | continue_to_next_target = false; |
| 474 | } |
| 475 | continue; |
| 476 | } |
| 477 | } else { |
| 478 | missed_count_ = 0; |
| 479 | } |
| 480 | */ |
| 481 | |
| 482 | if (seeking_target_) { |
| 483 | if (play_forward) { |
| 484 | // Go back to the last time we didn't see a target and play from there. |
| 485 | TickBackFrame(nano_step); |
| 486 | seeking_target_ = false; |
| 487 | } else if (seeking_target_) { |
| 488 | TickFrame(nano_step); |
| 489 | seeking_target_ = false; |
| 490 | } |
| 491 | continue; |
| 492 | } |
| 493 | |
| 494 | // comment out to turn off full blob drawing |
| 495 | view_.DrawBlobList(frame1.blob_list, {0, 0, 255}); |
| 496 | view_.DrawSecondBlobList(frame2.blob_list, {0, 255, 0}, {0, 255, 255}); |
| 497 | |
| 498 | DrawCross(overlay_, Vector<2>(fmt_.w / 2.0, fmt_.h / 2.0), {255, 0, 0}); |
| 499 | |
| 500 | double timeFromEpoch = |
| 501 | 1e-9 * ((double)frame1.timestamp + (double)frame2.timestamp) / 2; |
| 502 | printf("timestamp: %g skew: %g\n", timeFromEpoch, |
| 503 | 1e-9 * ((double)frame1.timestamp - (double)frame2.timestamp)); |
| 504 | /* |
| 505 | if (cent1 == Vector<2>(0, 0) && cent2 == Vector<2>(0, 0)) { |
| 506 | } else { |
| 507 | DrawCross(overlay_, cent1, {255, 255, 255}); |
| 508 | DrawCross(overlay_, cent2, {255, 255, 255}); |
| 509 | double x = (cent1.x() + cent2.x()) / 2.0; |
| 510 | DrawCross(overlay_, Vector<2>(x, fmt_.h / 2.0), {255, 255, 255}); |
| 511 | SetTime(aos::vision::MsTime(100)); |
| 512 | if (pause_on_next_target && !continue_to_next_target) { |
| 513 | paused = true; |
| 514 | pause_on_next_target = false; |
| 515 | } |
| 516 | line_break_ = true; |
| 517 | missed_count_ = 0; |
| 518 | } |
| 519 | fflush(stdout); |
| 520 | */ |
| 521 | view_.view()->Redraw(); |
| 522 | break; |
| 523 | } |
| 524 | } |
| 525 | |
| 526 | void DrawCross(PixelLinesOverlay &overlay, Vector<2> center, PixelRef color) { |
Parker Schuh | 24ee58d | 2017-03-11 16:13:23 -0800 | [diff] [blame] | 527 | overlay.AddLine(Vector<2>(center.x() - 25, center.y()), |
Parker Schuh | d7db83d | 2017-02-08 20:49:15 -0800 | [diff] [blame] | 528 | Vector<2>(center.x() + 25, center.y()), color); |
Parker Schuh | 24ee58d | 2017-03-11 16:13:23 -0800 | [diff] [blame] | 529 | overlay.AddLine(Vector<2>(center.x(), center.y() - 25), |
Parker Schuh | d7db83d | 2017-02-08 20:49:15 -0800 | [diff] [blame] | 530 | Vector<2>(center.x(), center.y() + 25), color); |
| 531 | } |
| 532 | |
| 533 | void AddTo(aos::events::EpollLoop *loop) { |
| 534 | Done(); |
| 535 | loop->AddWait(this); |
| 536 | } |
| 537 | |
| 538 | std::unique_ptr<PixelRef[]> outbuf; |
| 539 | ImagePtr ptr; |
| 540 | |
| 541 | BlobStreamViewer view_; |
| 542 | |
| 543 | private: |
| 544 | int ms_event_delta_ = 200; |
| 545 | public: |
| 546 | // basic image size |
| 547 | ImageFormat fmt_; |
| 548 | |
| 549 | // where we darw for debugging |
| 550 | PixelLinesOverlay overlay_; |
| 551 | |
| 552 | // Where we draw text on the screen. |
| 553 | LambdaOverlay text_overlay_; |
| 554 | // container for viewer |
| 555 | std::vector<OverlayBase *> overlays_; |
| 556 | |
| 557 | InputFile ifs1_; |
| 558 | InputFile ifs2_; |
| 559 | |
| 560 | // our blob processing object |
| 561 | HistogramBlobFilter blob_filt_; |
| 562 | |
| 563 | // corner finder to align aiming |
| 564 | CornerFinder finder_; |
| 565 | |
| 566 | // indicates we have lost a target |
| 567 | bool line_break_ = false; |
| 568 | |
| 569 | // indicates we are looking for the next target |
| 570 | bool seeking_target_ = false; |
| 571 | |
| 572 | int frame_count_ = 0; |
| 573 | |
| 574 | // count how many frames we miss in a row. |
| 575 | int missed_count_ = 16; |
| 576 | }; |
| 577 | } |
| 578 | } // namespace y2016::vision |
| 579 | |
| 580 | int main(int argc, char *argv[]) { |
| 581 | using namespace y2016::vision; |
| 582 | aos::events::EpollLoop loop; |
| 583 | gtk_init(&argc, &argv); |
| 584 | |
| 585 | if (argc != 3) { |
| 586 | printf("Wrong number of arguments. Got (%d) expected 3.\n", argc); |
| 587 | printf( |
| 588 | " arguments are debug level as {0, 1, 2} and then filename without the " |
| 589 | "{_0.dat,_1.dat} suffixes\n"); |
| 590 | } |
| 591 | |
| 592 | int dbg = std::stoi(argv[1]); |
| 593 | |
| 594 | std::string file(argv[2]); |
| 595 | aos::vision::ImageFormat fmt = {640 * 2, 480 * 2}; |
| 596 | |
| 597 | printf("file (%s) dbg_lvl (%d)\n", file.c_str(), dbg); |
| 598 | |
| 599 | std::string fname_path = file; |
| 600 | NetworkForwardingImageStream strm1( |
| 601 | fmt, dbg, fname_path + "_0.dat", fname_path + "_1.dat"); |
| 602 | fprintf(stderr, "staring main\n"); |
| 603 | strm1.AddTo(&loop); |
| 604 | |
| 605 | fprintf(stderr, "staring main\n"); |
| 606 | loop.RunWithGtkMain(); |
| 607 | } |