42 std::exit(EXIT_FAILURE);
48 rT1 = boost::posix_time::microsec_clock::local_time();
49 size_t num_images = message.
images.size();
50 for (
size_t msg_id = 0; msg_id < num_images; msg_id++) {
54 std::lock_guard<std::mutex> lck(
mtx_feeds.at(cam_id));
59 cv::equalizeHist(message.
images.at(msg_id), img);
61 double eq_clip_limit = 10.0;
62 cv::Size eq_win_size = cv::Size(8, 8);
63 cv::Ptr<cv::CLAHE> clahe = cv::createCLAHE(eq_clip_limit, eq_win_size);
64 clahe->apply(message.
images.at(msg_id), img);
66 img = message.
images.at(msg_id);
70 std::vector<cv::Mat> imgpyr;
80 if (num_images == 1) {
85 parallel_for_(cv::Range(0, (
int)num_images),
LambdaBody([&](
const cv::Range &range) {
86 for (
int i = range.start; i < range.end; i++) {
87 feed_monocular(message, i);
91 PRINT_ERROR(
RED "[ERROR]: invalid number of images passed %zu, we only support mono or stereo tracking", num_images);
92 std::exit(EXIT_FAILURE);
100 std::lock_guard<std::mutex> lck(
mtx_feeds.at(cam_id));
105 cv::Mat mask = message.
masks.at(msg_id);
106 rT2 = boost::posix_time::microsec_clock::local_time();
112 std::vector<cv::KeyPoint> good_left;
113 std::vector<size_t> good_ids_left;
127 int pts_before_detect = (int)
pts_last[cam_id].size();
128 auto pts_left_old =
pts_last[cam_id];
129 auto ids_left_old =
ids_last[cam_id];
131 rT3 = boost::posix_time::microsec_clock::local_time();
134 std::vector<uchar> mask_ll;
135 std::vector<cv::KeyPoint> pts_left_new = pts_left_old;
139 assert(pts_left_new.size() == ids_left_old.size());
140 rT4 = boost::posix_time::microsec_clock::local_time();
143 if (mask_ll.empty()) {
150 PRINT_ERROR(
RED "[KLT-EXTRACTOR]: Failed to get enough points to do RANSAC, resetting.....\n" RESET);
155 std::vector<cv::KeyPoint> good_left;
156 std::vector<size_t> good_ids_left;
159 for (
size_t i = 0; i < pts_left_new.size(); i++) {
161 if (pts_left_new.at(i).pt.x < 0 || pts_left_new.at(i).pt.y < 0 || (
int)pts_left_new.at(i).pt.x >= img.cols ||
162 (
int)pts_left_new.at(i).pt.y >= img.rows)
166 if ((
int)message.
masks.at(msg_id).at<uint8_t>((
int)pts_left_new.at(i).pt.y, (
int)pts_left_new.at(i).pt.x) > 127)
170 good_left.push_back(pts_left_new[i]);
171 good_ids_left.push_back(ids_left_old[i]);
176 for (
size_t i = 0; i < good_left.size(); i++) {
177 cv::Point2f npt_l =
camera_calib.at(cam_id)->undistort_cv(good_left.at(i).pt);
178 database->update_feature(good_ids_left.at(i), message.
timestamp, cam_id, good_left.at(i).pt.x, good_left.at(i).pt.y, npt_l.x, npt_l.y);
190 rT5 = boost::posix_time::microsec_clock::local_time();
193 PRINT_ALL(
"[TIME-KLT]: %.4f seconds for pyramid\n", (
rT2 -
rT1).total_microseconds() * 1e-6);
194 PRINT_ALL(
"[TIME-KLT]: %.4f seconds for detection (%zu detected)\n", (
rT3 -
rT2).total_microseconds() * 1e-6,
195 (
int)
pts_last[cam_id].size() - pts_before_detect);
196 PRINT_ALL(
"[TIME-KLT]: %.4f seconds for temporal klt\n", (
rT4 -
rT3).total_microseconds() * 1e-6);
197 PRINT_ALL(
"[TIME-KLT]: %.4f seconds for feature DB update (%d features)\n", (
rT5 -
rT4).total_microseconds() * 1e-6,
198 (
int)good_left.size());
199 PRINT_ALL(
"[TIME-KLT]: %.4f seconds for total\n", (
rT5 -
rT1).total_microseconds() * 1e-6);
205 size_t cam_id_left = message.
sensor_ids.at(msg_id_left);
206 size_t cam_id_right = message.
sensor_ids.at(msg_id_right);
207 std::lock_guard<std::mutex> lck1(
mtx_feeds.at(cam_id_left));
208 std::lock_guard<std::mutex> lck2(
mtx_feeds.at(cam_id_right));
211 cv::Mat img_left =
img_curr.at(cam_id_left);
212 cv::Mat img_right =
img_curr.at(cam_id_right);
215 cv::Mat mask_left = message.
masks.at(msg_id_left);
216 cv::Mat mask_right = message.
masks.at(msg_id_right);
217 rT2 = boost::posix_time::microsec_clock::local_time();
223 std::vector<cv::KeyPoint> good_left, good_right;
224 std::vector<size_t> good_ids_left, good_ids_right;
225 perform_detection_stereo(imgpyr_left, imgpyr_right, mask_left, mask_right, cam_id_left, cam_id_right, good_left, good_right,
226 good_ids_left, good_ids_right);
236 pts_last[cam_id_right] = good_right;
237 ids_last[cam_id_left] = good_ids_left;
238 ids_last[cam_id_right] = good_ids_right;
244 int pts_before_detect = (int)
pts_last[cam_id_left].size();
245 auto pts_left_old =
pts_last[cam_id_left];
246 auto pts_right_old =
pts_last[cam_id_right];
247 auto ids_left_old =
ids_last[cam_id_left];
248 auto ids_right_old =
ids_last[cam_id_right];
250 img_mask_last[cam_id_right], cam_id_left, cam_id_right, pts_left_old, pts_right_old, ids_left_old,
252 rT3 = boost::posix_time::microsec_clock::local_time();
255 std::vector<uchar> mask_ll, mask_rr;
256 std::vector<cv::KeyPoint> pts_left_new = pts_left_old;
257 std::vector<cv::KeyPoint> pts_right_new = pts_right_old;
260 parallel_for_(cv::Range(0, 2),
LambdaBody([&](
const cv::Range &range) {
261 for (
int i = range.start; i < range.end; i++) {
262 bool is_left = (i == 0);
263 perform_matching(img_pyramid_last[is_left ? cam_id_left : cam_id_right], is_left ? imgpyr_left : imgpyr_right,
264 is_left ? pts_left_old : pts_right_old, is_left ? pts_left_new : pts_right_new,
265 is_left ? cam_id_left : cam_id_right, is_left ? cam_id_left : cam_id_right,
266 is_left ? mask_ll : mask_rr);
269 rT4 = boost::posix_time::microsec_clock::local_time();
279 rT5 = boost::posix_time::microsec_clock::local_time();
285 if (mask_ll.empty() && mask_rr.empty()) {
297 PRINT_ERROR(
RED "[KLT-EXTRACTOR]: Failed to get enough points to do RANSAC, resetting.....\n" RESET);
302 std::vector<cv::KeyPoint> good_left, good_right;
303 std::vector<size_t> good_ids_left, good_ids_right;
306 for (
size_t i = 0; i < pts_left_new.size(); i++) {
308 if (pts_left_new.at(i).pt.x < 0 || pts_left_new.at(i).pt.y < 0 || (
int)pts_left_new.at(i).pt.x > img_left.cols ||
309 (
int)pts_left_new.at(i).pt.y > img_left.rows)
312 bool found_right =
false;
313 size_t index_right = 0;
314 for (
size_t n = 0; n < ids_right_old.size(); n++) {
315 if (ids_left_old.at(i) == ids_right_old.at(n)) {
323 if (mask_ll[i] && found_right && mask_rr[index_right]) {
325 if (pts_right_new.at(index_right).pt.x < 0 || pts_right_new.at(index_right).pt.y < 0 ||
326 (
int)pts_right_new.at(index_right).pt.x >= img_right.cols || (
int)pts_right_new.at(index_right).pt.y >= img_right.rows)
328 good_left.push_back(pts_left_new.at(i));
329 good_right.push_back(pts_right_new.at(index_right));
330 good_ids_left.push_back(ids_left_old.at(i));
331 good_ids_right.push_back(ids_right_old.at(index_right));
333 }
else if (mask_ll[i]) {
334 good_left.push_back(pts_left_new.at(i));
335 good_ids_left.push_back(ids_left_old.at(i));
341 for (
size_t i = 0; i < pts_right_new.size(); i++) {
343 if (pts_right_new.at(i).pt.x < 0 || pts_right_new.at(i).pt.y < 0 || (
int)pts_right_new.at(i).pt.x >= img_right.cols ||
344 (
int)pts_right_new.at(i).pt.y >= img_right.rows)
347 bool added_already = (std::find(good_ids_right.begin(), good_ids_right.end(), ids_right_old.at(i)) != good_ids_right.end());
349 if (mask_rr[i] && !added_already) {
350 good_right.push_back(pts_right_new.at(i));
351 good_ids_right.push_back(ids_right_old.at(i));
357 for (
size_t i = 0; i < good_left.size(); i++) {
358 cv::Point2f npt_l =
camera_calib.at(cam_id_left)->undistort_cv(good_left.at(i).pt);
359 database->update_feature(good_ids_left.at(i), message.
timestamp, cam_id_left, good_left.at(i).pt.x, good_left.at(i).pt.y, npt_l.x,
362 for (
size_t i = 0; i < good_right.size(); i++) {
363 cv::Point2f npt_r =
camera_calib.at(cam_id_right)->undistort_cv(good_right.at(i).pt);
364 database->update_feature(good_ids_right.at(i), message.
timestamp, cam_id_right, good_right.at(i).pt.x, good_right.at(i).pt.y, npt_r.x,
378 pts_last[cam_id_right] = good_right;
379 ids_last[cam_id_left] = good_ids_left;
380 ids_last[cam_id_right] = good_ids_right;
382 rT6 = boost::posix_time::microsec_clock::local_time();
385 PRINT_ALL(
"[TIME-KLT]: %.4f seconds for pyramid\n", (
rT2 -
rT1).total_microseconds() * 1e-6);
386 PRINT_ALL(
"[TIME-KLT]: %.4f seconds for detection (%d detected)\n", (
rT3 -
rT2).total_microseconds() * 1e-6,
387 (
int)
pts_last[cam_id_left].size() - pts_before_detect);
388 PRINT_ALL(
"[TIME-KLT]: %.4f seconds for temporal klt\n", (
rT4 -
rT3).total_microseconds() * 1e-6);
389 PRINT_ALL(
"[TIME-KLT]: %.4f seconds for stereo klt\n", (
rT5 -
rT4).total_microseconds() * 1e-6);
390 PRINT_ALL(
"[TIME-KLT]: %.4f seconds for feature DB update (%d features)\n", (
rT6 -
rT5).total_microseconds() * 1e-6,
391 (
int)good_left.size());
392 PRINT_ALL(
"[TIME-KLT]: %.4f seconds for total\n", (
rT6 -
rT1).total_microseconds() * 1e-6);
396 std::vector<size_t> &ids0) {
401 cv::Size size_close((
int)((
float)img0pyr.at(0).cols / (
float)
min_px_dist),
402 (
int)((
float)img0pyr.at(0).rows / (
float)
min_px_dist));
403 cv::Mat grid_2d_close = cv::Mat::zeros(size_close, CV_8UC1);
404 float size_x = (float)img0pyr.at(0).cols / (float)
grid_x;
405 float size_y = (float)img0pyr.at(0).rows / (float)
grid_y;
407 cv::Mat grid_2d_grid = cv::Mat::zeros(size_grid, CV_8UC1);
408 cv::Mat mask0_updated = mask0.clone();
409 auto it0 = pts0.begin();
410 auto it1 = ids0.begin();
411 while (it0 != pts0.end()) {
413 cv::KeyPoint kpt = *it0;
414 int x = (int)kpt.pt.x;
415 int y = (
int)kpt.pt.y;
417 if (x < edge || x >= img0pyr.at(0).cols - edge || y < edge || y >= img0pyr.at(0).rows - edge) {
418 it0 = pts0.erase(it0);
419 it1 = ids0.erase(it1);
423 int x_close = (int)(kpt.pt.x / (
float)
min_px_dist);
424 int y_close = (int)(kpt.pt.y / (
float)
min_px_dist);
425 if (x_close < 0 || x_close >= size_close.width || y_close < 0 || y_close >= size_close.height) {
426 it0 = pts0.erase(it0);
427 it1 = ids0.erase(it1);
431 int x_grid = std::floor(kpt.pt.x / size_x);
432 int y_grid = std::floor(kpt.pt.y / size_y);
433 if (x_grid < 0 || x_grid >= size_grid.width || y_grid < 0 || y_grid >= size_grid.height) {
434 it0 = pts0.erase(it0);
435 it1 = ids0.erase(it1);
439 if (grid_2d_close.at<uint8_t>(y_close, x_close) > 127) {
440 it0 = pts0.erase(it0);
441 it1 = ids0.erase(it1);
446 if (mask0.at<uint8_t>(y, x) > 127) {
447 it0 = pts0.erase(it0);
448 it1 = ids0.erase(it1);
452 grid_2d_close.at<uint8_t>(y_close, x_close) = 255;
453 if (grid_2d_grid.at<uint8_t>(y_grid, x_grid) < 255) {
454 grid_2d_grid.at<uint8_t>(y_grid, x_grid) += 1;
460 cv::rectangle(mask0_updated, pt1, pt2, cv::Scalar(255), -1);
468 double min_feat_percent = 0.50;
470 if (num_featsneeded < std::min(20, (
int)(min_feat_percent *
num_features)))
480 cv::resize(mask0, mask0_grid, size_grid, 0.0, 0.0, cv::INTER_NEAREST);
484 int num_features_grid_req = std::max(1, (
int)(min_feat_percent * num_features_grid));
485 std::vector<std::pair<int, int>> valid_locs;
486 for (
int x = 0; x < grid_2d_grid.cols; x++) {
487 for (
int y = 0; y < grid_2d_grid.rows; y++) {
488 if ((
int)grid_2d_grid.at<uint8_t>(y, x) < num_features_grid_req && (
int)mask0_grid.at<uint8_t>(y, x) != 255) {
489 valid_locs.emplace_back(x, y);
493 std::vector<cv::KeyPoint> pts0_ext;
497 std::vector<cv::KeyPoint> kpts0_new;
498 std::vector<cv::Point2f> pts0_new;
499 for (
auto &kpt : pts0_ext) {
503 if (x_grid < 0 || x_grid >= size_close.width || y_grid < 0 || y_grid >= size_close.height)
506 if (grid_2d_close.at<uint8_t>(y_grid, x_grid) > 127)
509 kpts0_new.push_back(kpt);
510 pts0_new.push_back(kpt.pt);
511 grid_2d_close.at<uint8_t>(y_grid, x_grid) = 255;
519 for (
size_t i = 0; i < pts0_new.size(); i++) {
521 kpts0_new.at(i).pt = pts0_new.at(i);
523 pts0.push_back(kpts0_new.at(i));
526 ids0.push_back(temp);
531 const cv::Mat &mask1,
size_t cam_id_left,
size_t cam_id_right, std::vector<cv::KeyPoint> &pts0,
532 std::vector<cv::KeyPoint> &pts1, std::vector<size_t> &ids0, std::vector<size_t> &ids1) {
537 cv::Size size_close0((
int)((
float)img0pyr.at(0).cols / (
float)
min_px_dist),
538 (
int)((
float)img0pyr.at(0).rows / (
float)
min_px_dist));
539 cv::Mat grid_2d_close0 = cv::Mat::zeros(size_close0, CV_8UC1);
540 float size_x0 = (float)img0pyr.at(0).cols / (float)
grid_x;
541 float size_y0 = (float)img0pyr.at(0).rows / (float)
grid_y;
543 cv::Mat grid_2d_grid0 = cv::Mat::zeros(size_grid0, CV_8UC1);
544 cv::Mat mask0_updated = mask0.clone();
545 auto it0 = pts0.begin();
546 auto it1 = ids0.begin();
547 while (it0 != pts0.end()) {
549 cv::KeyPoint kpt = *it0;
550 int x = (int)kpt.pt.x;
551 int y = (
int)kpt.pt.y;
553 if (x < edge || x >= img0pyr.at(0).cols - edge || y < edge || y >= img0pyr.at(0).rows - edge) {
554 it0 = pts0.erase(it0);
555 it1 = ids0.erase(it1);
559 int x_close = (int)(kpt.pt.x / (
float)
min_px_dist);
560 int y_close = (int)(kpt.pt.y / (
float)
min_px_dist);
561 if (x_close < 0 || x_close >= size_close0.width || y_close < 0 || y_close >= size_close0.height) {
562 it0 = pts0.erase(it0);
563 it1 = ids0.erase(it1);
567 int x_grid = std::floor(kpt.pt.x / size_x0);
568 int y_grid = std::floor(kpt.pt.y / size_y0);
569 if (x_grid < 0 || x_grid >= size_grid0.width || y_grid < 0 || y_grid >= size_grid0.height) {
570 it0 = pts0.erase(it0);
571 it1 = ids0.erase(it1);
575 if (grid_2d_close0.at<uint8_t>(y_close, x_close) > 127) {
576 it0 = pts0.erase(it0);
577 it1 = ids0.erase(it1);
582 if (mask0.at<uint8_t>(y, x) > 127) {
583 it0 = pts0.erase(it0);
584 it1 = ids0.erase(it1);
588 grid_2d_close0.at<uint8_t>(y_close, x_close) = 255;
589 if (grid_2d_grid0.at<uint8_t>(y_grid, x_grid) < 255) {
590 grid_2d_grid0.at<uint8_t>(y_grid, x_grid) += 1;
596 cv::rectangle(mask0_updated, pt1, pt2, cv::Scalar(255), -1);
603 double min_feat_percent = 0.50;
604 int num_featsneeded_0 =
num_features - (int)pts0.size();
609 if (num_featsneeded_0 > std::min(20, (
int)(min_feat_percent *
num_features))) {
618 cv::resize(mask0, mask0_grid, size_grid0, 0.0, 0.0, cv::INTER_NEAREST);
622 int num_features_grid_req = std::max(1, (
int)(min_feat_percent * num_features_grid));
623 std::vector<std::pair<int, int>> valid_locs;
624 for (
int x = 0; x < grid_2d_grid0.cols; x++) {
625 for (
int y = 0; y < grid_2d_grid0.rows; y++) {
626 if ((
int)grid_2d_grid0.at<uint8_t>(y, x) < num_features_grid_req && (
int)mask0_grid.at<uint8_t>(y, x) != 255) {
627 valid_locs.emplace_back(x, y);
631 std::vector<cv::KeyPoint> pts0_ext;
635 std::vector<cv::KeyPoint> kpts0_new;
636 std::vector<cv::Point2f> pts0_new;
637 for (
auto &kpt : pts0_ext) {
641 if (x_grid < 0 || x_grid >= size_close0.width || y_grid < 0 || y_grid >= size_close0.height)
644 if (grid_2d_close0.at<uint8_t>(y_grid, x_grid) > 127)
647 grid_2d_close0.at<uint8_t>(y_grid, x_grid) = 255;
648 kpts0_new.push_back(kpt);
649 pts0_new.push_back(kpt.pt);
656 std::vector<cv::KeyPoint> kpts1_new;
657 std::vector<cv::Point2f> pts1_new;
658 kpts1_new = kpts0_new;
662 if (!pts0_new.empty()) {
667 std::vector<uchar> mask;
669 std::vector<float> error;
670 cv::TermCriteria term_crit = cv::TermCriteria(cv::TermCriteria::COUNT | cv::TermCriteria::EPS, 30, 0.01);
671 cv::calcOpticalFlowPyrLK(img0pyr, img1pyr, pts0_new, pts1_new, mask, error,
win_size,
pyr_levels, term_crit,
672 cv::OPTFLOW_USE_INITIAL_FLOW);
675 for (
size_t i = 0; i < pts0_new.size(); i++) {
678 bool oob_left = ((int)pts0_new.at(i).x < 0 || (int)pts0_new.at(i).x >= img0pyr.at(0).cols || (int)pts0_new.at(i).y < 0 ||
679 (int)pts0_new.at(i).y >= img0pyr.at(0).rows);
680 bool oob_right = ((int)pts1_new.at(i).x < 0 || (int)pts1_new.at(i).x >= img1pyr.at(0).cols || (int)pts1_new.at(i).y < 0 ||
681 (int)pts1_new.at(i).y >= img1pyr.at(0).rows);
688 if (!oob_left && !oob_right && mask[i] == 1) {
690 kpts0_new.at(i).pt = pts0_new.at(i);
691 kpts1_new.at(i).pt = pts1_new.at(i);
693 pts0.push_back(kpts0_new.at(i));
694 pts1.push_back(kpts1_new.at(i));
697 ids0.push_back(temp);
698 ids1.push_back(temp);
699 }
else if (!oob_left) {
701 kpts0_new.at(i).pt = pts0_new.at(i);
703 pts0.push_back(kpts0_new.at(i));
706 ids0.push_back(temp);
715 cv::Size size_close1((
int)((
float)img1pyr.at(0).cols / (
float)
min_px_dist), (
int)((
float)img1pyr.at(0).rows / (
float)
min_px_dist));
716 cv::Mat grid_2d_close1 = cv::Mat::zeros(size_close1, CV_8UC1);
717 float size_x1 = (float)img1pyr.at(0).cols / (float)
grid_x;
718 float size_y1 = (float)img1pyr.at(0).rows / (float)
grid_y;
720 cv::Mat grid_2d_grid1 = cv::Mat::zeros(size_grid1, CV_8UC1);
721 cv::Mat mask1_updated = mask0.clone();
724 while (it0 != pts1.end()) {
726 cv::KeyPoint kpt = *it0;
727 int x = (int)kpt.pt.x;
728 int y = (
int)kpt.pt.y;
730 if (x < edge || x >= img1pyr.at(0).cols - edge || y < edge || y >= img1pyr.at(0).rows - edge) {
731 it0 = pts1.erase(it0);
732 it1 = ids1.erase(it1);
736 int x_close = (int)(kpt.pt.x / (
float)
min_px_dist);
737 int y_close = (int)(kpt.pt.y / (
float)
min_px_dist);
738 if (x_close < 0 || x_close >= size_close1.width || y_close < 0 || y_close >= size_close1.height) {
739 it0 = pts1.erase(it0);
740 it1 = ids1.erase(it1);
744 int x_grid = std::floor(kpt.pt.x / size_x1);
745 int y_grid = std::floor(kpt.pt.y / size_y1);
746 if (x_grid < 0 || x_grid >= size_grid1.width || y_grid < 0 || y_grid >= size_grid1.height) {
747 it0 = pts1.erase(it0);
748 it1 = ids1.erase(it1);
754 bool is_stereo = (std::find(ids0.begin(), ids0.end(), *it1) != ids0.end());
755 if (grid_2d_close1.at<uint8_t>(y_close, x_close) > 127 && !is_stereo) {
756 it0 = pts1.erase(it0);
757 it1 = ids1.erase(it1);
762 if (mask1.at<uint8_t>(y, x) > 127) {
763 it0 = pts1.erase(it0);
764 it1 = ids1.erase(it1);
768 grid_2d_close1.at<uint8_t>(y_close, x_close) = 255;
769 if (grid_2d_grid1.at<uint8_t>(y_grid, x_grid) < 255) {
770 grid_2d_grid1.at<uint8_t>(y_grid, x_grid) += 1;
776 cv::rectangle(mask1_updated, pt1, pt2, cv::Scalar(255), -1);
784 int num_featsneeded_1 =
num_features - (int)pts1.size();
785 if (num_featsneeded_1 > std::min(20, (
int)(min_feat_percent *
num_features))) {
794 cv::resize(mask1, mask1_grid, size_grid1, 0.0, 0.0, cv::INTER_NEAREST);
798 int num_features_grid_req = std::max(1, (
int)(min_feat_percent * num_features_grid));
799 std::vector<std::pair<int, int>> valid_locs;
800 for (
int x = 0; x < grid_2d_grid1.cols; x++) {
801 for (
int y = 0; y < grid_2d_grid1.rows; y++) {
802 if ((
int)grid_2d_grid1.at<uint8_t>(y, x) < num_features_grid_req && (
int)mask1_grid.at<uint8_t>(y, x) != 255) {
803 valid_locs.emplace_back(x, y);
807 std::vector<cv::KeyPoint> pts1_ext;
811 for (
auto &kpt : pts1_ext) {
815 if (x_grid < 0 || x_grid >= size_close1.width || y_grid < 0 || y_grid >= size_close1.height)
818 if (grid_2d_close1.at<uint8_t>(y_grid, x_grid) > 127)
823 ids1.push_back(temp);
824 grid_2d_close1.at<uint8_t>(y_grid, x_grid) = 255;
830 std::vector<cv::KeyPoint> &kpts1,
size_t id0,
size_t id1, std::vector<uchar> &mask_out) {
833 assert(kpts0.size() == kpts1.size());
836 if (kpts0.empty() || kpts1.empty())
840 std::vector<cv::Point2f> pts0, pts1;
841 for (
size_t i = 0; i < kpts0.size(); i++) {
842 pts0.push_back(kpts0.at(i).pt);
843 pts1.push_back(kpts1.at(i).pt);
848 if (pts0.size() < 10) {
849 for (
size_t i = 0; i < pts0.size(); i++)
850 mask_out.push_back((uchar)0);
855 std::vector<uchar> mask_klt;
856 std::vector<float> error;
857 cv::TermCriteria term_crit = cv::TermCriteria(cv::TermCriteria::COUNT | cv::TermCriteria::EPS, 30, 0.01);
858 cv::calcOpticalFlowPyrLK(img0pyr, img1pyr, pts0, pts1, mask_klt, error,
win_size,
pyr_levels, term_crit, cv::OPTFLOW_USE_INITIAL_FLOW);
862 std::vector<cv::Point2f> pts0_n, pts1_n;
863 for (
size_t i = 0; i < pts0.size(); i++) {
864 pts0_n.push_back(
camera_calib.at(id0)->undistort_cv(pts0.at(i)));
865 pts1_n.push_back(
camera_calib.at(id1)->undistort_cv(pts1.at(i)));
869 std::vector<uchar> mask_rsc;
872 double max_focallength = std::max(max_focallength_img0, max_focallength_img1);
873 cv::findFundamentalMat(pts0_n, pts1_n, cv::FM_RANSAC, 2.0 / max_focallength, 0.999, mask_rsc);
876 for (
size_t i = 0; i < mask_klt.size(); i++) {
877 auto mask = (uchar)((i < mask_klt.size() && mask_klt[i] && i < mask_rsc.size() && mask_rsc[i]) ? 1 : 0);
878 mask_out.push_back(mask);
882 for (
size_t i = 0; i < pts0.size(); i++) {
883 kpts0.at(i).pt = pts0.at(i);
884 kpts1.at(i).pt = pts1.at(i);