24 #include <opencv2/features2d.hpp>
41 std::exit(EXIT_FAILURE);
46 size_t num_images = message.
images.size();
47 if (num_images == 1) {
52 parallel_for_(cv::Range(0, (
int)num_images),
LambdaBody([&](
const cv::Range &range) {
53 for (
int i = range.start; i < range.end; i++) {
54 feed_monocular(message, i);
58 PRINT_ERROR(
RED "[ERROR]: invalid number of images passed %zu, we only support mono or stereo tracking", num_images);
59 std::exit(EXIT_FAILURE);
66 rT1 = boost::posix_time::microsec_clock::local_time();
70 std::lock_guard<std::mutex> lck(
mtx_feeds.at(cam_id));
75 cv::equalizeHist(message.
images.at(msg_id), img);
77 double eq_clip_limit = 10.0;
78 cv::Size eq_win_size = cv::Size(8, 8);
79 cv::Ptr<cv::CLAHE> clahe = cv::createCLAHE(eq_clip_limit, eq_win_size);
80 clahe->apply(message.
images.at(msg_id), img);
82 img = message.
images.at(msg_id);
84 mask = message.
masks.at(msg_id);
88 std::vector<cv::KeyPoint> good_left;
89 std::vector<size_t> good_ids_left;
90 cv::Mat good_desc_left;
102 std::vector<cv::KeyPoint> pts_new;
104 std::vector<size_t> ids_new;
108 rT2 = boost::posix_time::microsec_clock::local_time();
111 std::vector<cv::DMatch> matches_ll;
115 rT3 = boost::posix_time::microsec_clock::local_time();
118 std::vector<cv::KeyPoint> good_left;
119 std::vector<size_t> good_ids_left;
120 cv::Mat good_desc_left;
123 int num_tracklast = 0;
128 for (
size_t i = 0; i < pts_new.size(); i++) {
132 for (
size_t j = 0; j < matches_ll.size(); j++) {
133 if (matches_ll[j].trainIdx == (
int)i) {
134 idll = matches_ll[j].queryIdx;
140 good_left.push_back(pts_new[i]);
141 good_desc_left.push_back(desc_new.row((
int)i));
143 good_ids_left.push_back(
ids_last[cam_id][idll]);
146 good_ids_left.push_back(ids_new[i]);
149 rT4 = boost::posix_time::microsec_clock::local_time();
152 for (
size_t i = 0; i < good_left.size(); i++) {
153 cv::Point2f npt_l =
camera_calib.at(cam_id)->undistort_cv(good_left.at(i).pt);
154 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);
169 rT5 = boost::posix_time::microsec_clock::local_time();
172 PRINT_ALL(
"[TIME-DESC]: %.4f seconds for detection\n", (
rT2 -
rT1).total_microseconds() * 1e-6);
173 PRINT_ALL(
"[TIME-DESC]: %.4f seconds for matching\n", (
rT3 -
rT2).total_microseconds() * 1e-6);
174 PRINT_ALL(
"[TIME-DESC]: %.4f seconds for merging\n", (
rT4 -
rT3).total_microseconds() * 1e-6);
175 PRINT_ALL(
"[TIME-DESC]: %.4f seconds for feature DB update (%d features)\n", (
rT5 -
rT4).total_microseconds() * 1e-6,
176 (
int)good_left.size());
177 PRINT_ALL(
"[TIME-DESC]: %.4f seconds for total\n", (
rT5 -
rT1).total_microseconds() * 1e-6);
183 rT1 = boost::posix_time::microsec_clock::local_time();
186 size_t cam_id_left = message.
sensor_ids.at(msg_id_left);
187 size_t cam_id_right = message.
sensor_ids.at(msg_id_right);
188 std::lock_guard<std::mutex> lck1(
mtx_feeds.at(cam_id_left));
189 std::lock_guard<std::mutex> lck2(
mtx_feeds.at(cam_id_right));
192 cv::Mat img_left, img_right, mask_left, mask_right;
194 cv::equalizeHist(message.
images.at(msg_id_left), img_left);
195 cv::equalizeHist(message.
images.at(msg_id_right), img_right);
197 double eq_clip_limit = 10.0;
198 cv::Size eq_win_size = cv::Size(8, 8);
199 cv::Ptr<cv::CLAHE> clahe = cv::createCLAHE(eq_clip_limit, eq_win_size);
200 clahe->apply(message.
images.at(msg_id_left), img_left);
201 clahe->apply(message.
images.at(msg_id_right), img_right);
203 img_left = message.
images.at(msg_id_left);
204 img_right = message.
images.at(msg_id_right);
206 mask_left = message.
masks.at(msg_id_left);
207 mask_right = message.
masks.at(msg_id_right);
211 std::vector<cv::KeyPoint> good_left, good_right;
212 std::vector<size_t> good_ids_left, good_ids_right;
213 cv::Mat good_desc_left, good_desc_right;
214 perform_detection_stereo(img_left, img_right, mask_left, mask_right, good_left, good_right, good_desc_left, good_desc_right,
215 cam_id_left, cam_id_right, good_ids_left, good_ids_right);
222 pts_last[cam_id_right] = good_right;
223 ids_last[cam_id_left] = good_ids_left;
224 ids_last[cam_id_right] = good_ids_right;
226 desc_last[cam_id_right] = good_desc_right;
231 std::vector<cv::KeyPoint> pts_left_new, pts_right_new;
232 cv::Mat desc_left_new, desc_right_new;
233 std::vector<size_t> ids_left_new, ids_right_new;
236 perform_detection_stereo(img_left, img_right, mask_left, mask_right, pts_left_new, pts_right_new, desc_left_new, desc_right_new,
237 cam_id_left, cam_id_right, ids_left_new, ids_right_new);
238 rT2 = boost::posix_time::microsec_clock::local_time();
241 std::vector<cv::DMatch> matches_ll, matches_rr;
242 parallel_for_(cv::Range(0, 2),
LambdaBody([&](
const cv::Range &range) {
243 for (
int i = range.start; i < range.end; i++) {
244 bool is_left = (i == 0);
245 robust_match(pts_last[is_left ? cam_id_left : cam_id_right], is_left ? pts_left_new : pts_right_new,
246 desc_last[is_left ? cam_id_left : cam_id_right], is_left ? desc_left_new : desc_right_new,
247 is_left ? cam_id_left : cam_id_right, is_left ? cam_id_left : cam_id_right,
248 is_left ? matches_ll : matches_rr);
251 rT3 = boost::posix_time::microsec_clock::local_time();
254 std::vector<cv::KeyPoint> good_left, good_right;
255 std::vector<size_t> good_ids_left, good_ids_right;
256 cv::Mat good_desc_left, good_desc_right;
260 assert(pts_left_new.size() == pts_right_new.size());
263 int num_tracklast = 0;
268 for (
size_t i = 0; i < pts_left_new.size(); i++) {
272 for (
size_t j = 0; j < matches_ll.size(); j++) {
273 if (matches_ll[j].trainIdx == (
int)i) {
274 idll = matches_ll[j].queryIdx;
280 for (
size_t j = 0; j < matches_rr.size(); j++) {
281 if (matches_rr[j].trainIdx == (
int)i) {
282 idrr = matches_rr[j].queryIdx;
289 if (idll != -1 && idrr != -1 &&
ids_last[cam_id_left][idll] ==
ids_last[cam_id_right][idrr]) {
290 good_left.push_back(pts_left_new[i]);
291 good_right.push_back(pts_right_new[i]);
292 good_desc_left.push_back(desc_left_new.row((
int)i));
293 good_desc_right.push_back(desc_right_new.row((
int)i));
294 good_ids_left.push_back(
ids_last[cam_id_left][idll]);
295 good_ids_right.push_back(
ids_last[cam_id_right][idrr]);
299 good_left.push_back(pts_left_new[i]);
300 good_right.push_back(pts_right_new[i]);
301 good_desc_left.push_back(desc_left_new.row((
int)i));
302 good_desc_right.push_back(desc_right_new.row((
int)i));
303 good_ids_left.push_back(ids_left_new[i]);
304 good_ids_right.push_back(ids_left_new[i]);
307 rT4 = boost::posix_time::microsec_clock::local_time();
313 for (
size_t i = 0; i < good_left.size(); i++) {
315 assert(good_ids_left.at(i) == good_ids_right.at(i));
317 cv::Point2f npt_l =
camera_calib.at(cam_id_left)->undistort_cv(good_left.at(i).pt);
318 cv::Point2f npt_r =
camera_calib.at(cam_id_right)->undistort_cv(good_right.at(i).pt);
320 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,
322 database->update_feature(good_ids_left.at(i), message.
timestamp, cam_id_right, good_right.at(i).pt.x, good_right.at(i).pt.y, npt_r.x,
338 pts_last[cam_id_right] = good_right;
339 ids_last[cam_id_left] = good_ids_left;
340 ids_last[cam_id_right] = good_ids_right;
342 desc_last[cam_id_right] = good_desc_right;
344 rT5 = boost::posix_time::microsec_clock::local_time();
347 PRINT_ALL(
"[TIME-DESC]: %.4f seconds for detection\n", (
rT2 -
rT1).total_microseconds() * 1e-6);
348 PRINT_ALL(
"[TIME-DESC]: %.4f seconds for matching\n", (
rT3 -
rT2).total_microseconds() * 1e-6);
349 PRINT_ALL(
"[TIME-DESC]: %.4f seconds for merging\n", (
rT4 -
rT3).total_microseconds() * 1e-6);
350 PRINT_ALL(
"[TIME-DESC]: %.4f seconds for feature DB update (%d features)\n", (
rT5 -
rT4).total_microseconds() * 1e-6,
351 (
int)good_left.size());
352 PRINT_ALL(
"[TIME-DESC]: %.4f seconds for total\n", (
rT5 -
rT1).total_microseconds() * 1e-6);
356 cv::Mat &desc0, std::vector<size_t> &ids0) {
359 assert(pts0.empty());
362 std::vector<cv::KeyPoint> pts0_ext;
367 this->
orb0->compute(img0, pts0_ext, desc0_ext);
372 cv::Size size((
int)((
float)img0.cols / (
float)
min_px_dist), (
int)((
float)img0.rows / (
float)
min_px_dist));
373 cv::Mat grid_2d = cv::Mat::zeros(size, CV_8UC1);
380 for (
size_t i = 0; i < pts0_ext.size(); i++) {
382 cv::KeyPoint kpt = pts0_ext.at(i);
383 int x = (int)kpt.pt.x;
384 int y = (
int)kpt.pt.y;
387 if (x_grid < 0 || x_grid >= size.width || y_grid < 0 || y_grid >= size.height || x < 0 || x >= img0.cols || y < 0 || y >= img0.rows) {
391 if (grid_2d.at<uint8_t>(y_grid, x_grid) > 127)
394 pts0.push_back(pts0_ext.at(i));
395 desc0.push_back(desc0_ext.row((
int)i));
398 ids0.push_back(temp);
399 grid_2d.at<uint8_t>(y_grid, x_grid) = 255;
404 std::vector<cv::KeyPoint> &pts0, std::vector<cv::KeyPoint> &pts1, cv::Mat &desc0,
405 cv::Mat &desc1,
size_t cam_id0,
size_t cam_id1, std::vector<size_t> &ids0,
406 std::vector<size_t> &ids1) {
409 assert(pts0.empty());
410 assert(pts1.empty());
413 std::vector<cv::KeyPoint> pts0_ext, pts1_ext;
414 cv::Mat desc0_ext, desc1_ext;
415 parallel_for_(cv::Range(0, 2),
LambdaBody([&](
const cv::Range &range) {
416 for (
int i = range.start; i < range.end; i++) {
417 bool is_left = (i == 0);
418 Grider_FAST::perform_griding(is_left ? img0 : img1, is_left ? mask0 : mask1, is_left ? pts0_ext : pts1_ext,
419 num_features, grid_x, grid_y, threshold, true);
420 (is_left ? orb0 : orb1)->compute(is_left ? img0 : img1, is_left ? pts0_ext : pts1_ext, is_left ? desc0_ext : desc1_ext);
425 std::vector<cv::DMatch> matches;
426 robust_match(pts0_ext, pts1_ext, desc0_ext, desc1_ext, cam_id0, cam_id1, matches);
431 cv::Size size0((
int)((
float)img0.cols / (
float)
min_px_dist), (
int)((
float)img0.rows / (
float)
min_px_dist));
432 cv::Mat grid_2d_0 = cv::Mat::zeros(size0, CV_8UC1);
433 cv::Size size1((
int)((
float)img1.cols / (
float)
min_px_dist), (
int)((
float)img1.rows / (
float)
min_px_dist));
434 cv::Mat grid_2d_1 = cv::Mat::zeros(size1, CV_8UC1);
437 for (
size_t i = 0; i < matches.size(); i++) {
440 int index_pt0 = matches.at(i).queryIdx;
441 int index_pt1 = matches.at(i).trainIdx;
444 cv::KeyPoint kpt0 = pts0_ext.at(index_pt0);
445 cv::KeyPoint kpt1 = pts1_ext.at(index_pt1);
446 int x0 = (int)kpt0.pt.x;
447 int y0 = (
int)kpt0.pt.y;
448 int x0_grid = (int)(kpt0.pt.x / (
float)
min_px_dist);
449 int y0_grid = (int)(kpt0.pt.y / (
float)
min_px_dist);
450 if (x0_grid < 0 || x0_grid >= size0.width || y0_grid < 0 || y0_grid >= size0.height || x0 < 0 || x0 >= img0.cols || y0 < 0 ||
454 int x1 = (int)kpt1.pt.x;
455 int y1 = (
int)kpt1.pt.y;
456 int x1_grid = (int)(kpt1.pt.x / (
float)
min_px_dist);
457 int y1_grid = (int)(kpt1.pt.y / (
float)
min_px_dist);
458 if (x1_grid < 0 || x1_grid >= size1.width || y1_grid < 0 || y1_grid >= size1.height || x1 < 0 || x1 >= img0.cols || y1 < 0 ||
464 if (grid_2d_0.at<uint8_t>(y0_grid, x0_grid) > 127 || grid_2d_1.at<uint8_t>(y1_grid, x1_grid) > 127)
468 pts0.push_back(pts0_ext[index_pt0]);
469 pts1.push_back(pts1_ext[index_pt1]);
470 desc0.push_back(desc0_ext.row(index_pt0));
471 desc1.push_back(desc1_ext.row(index_pt1));
475 ids0.push_back(temp);
476 ids1.push_back(temp);
481 const cv::Mat &desc1,
size_t id0,
size_t id1, std::vector<cv::DMatch> &matches) {
484 std::vector<std::vector<cv::DMatch>> matches0to1, matches1to0;
487 matcher->knnMatch(desc0, desc1, matches0to1, 2);
488 matcher->knnMatch(desc1, desc0, matches1to0, 2);
495 std::vector<cv::DMatch> matches_good;
499 std::vector<cv::Point2f> pts0_rsc, pts1_rsc;
500 for (
size_t i = 0; i < matches_good.size(); i++) {
502 int index_pt0 = matches_good.at(i).queryIdx;
503 int index_pt1 = matches_good.at(i).trainIdx;
505 pts0_rsc.push_back(pts0[index_pt0].pt);
506 pts1_rsc.push_back(pts1[index_pt1].pt);
510 if (pts0_rsc.size() < 10)
515 std::vector<cv::Point2f> pts0_n, pts1_n;
516 for (
size_t i = 0; i < pts0_rsc.size(); i++) {
517 pts0_n.push_back(
camera_calib.at(id0)->undistort_cv(pts0_rsc.at(i)));
518 pts1_n.push_back(
camera_calib.at(id1)->undistort_cv(pts1_rsc.at(i)));
522 std::vector<uchar> mask_rsc;
525 double max_focallength = std::max(max_focallength_img0, max_focallength_img1);
526 cv::findFundamentalMat(pts0_n, pts1_n, cv::FM_RANSAC, 1 / max_focallength, 0.999, mask_rsc);
529 for (
size_t i = 0; i < matches_good.size(); i++) {
531 if (mask_rsc[i] != 1)
534 matches.push_back(matches_good.at(i));
540 for (
auto &match : matches) {
542 if (match.size() > 1) {
544 if (match[0].distance / match[1].distance >
knn_ratio) {
555 std::vector<cv::DMatch> &good_matches) {
557 for (
auto &match1 : matches1) {
559 if (match1.empty() || match1.size() < 2)
562 for (
auto &match2 : matches2) {
564 if (match2.empty() || match2.size() < 2)
567 if (match1[0].queryIdx == match2[0].trainIdx && match2[0].queryIdx == match1[0].trainIdx) {
569 good_matches.emplace_back(cv::DMatch(match1[0].queryIdx, match1[0].trainIdx, match1[0].distance));