// This file is part of SVO - Semi-direct Visual Odometry. // // Copyright (C) 2014 Christian Forster // (Robotics and Perception Group, University of Zurich, Switzerland). // // SVO is free software: you can redistribute it and/or modify it under the // terms of the GNU General Public License as published by the Free Software // Foundation, either version 3 of the License, or any later version. // // SVO is distributed in the hope that it will be useful, but WITHOUT ANY // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS // FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . #include #include #include #include #include #include #include #include #include #include #ifdef USE_BUNDLE_ADJUSTMENT #include #endif namespace svo { FrameHandlerMono::FrameHandlerMono(vk::AbstractCamera* cam,Sophus::SE3& SE_init) : FrameHandlerBase(), cam_(cam), reprojector_(cam_, map_), depth_filter_(NULL) { gpu_fast_= new opencl(); gpu_fast_->make_kernel("fast_gray"); cv::Mat img=cv::Mat(cv::Size(700, 500),CV_8UC1); gpu_fast_->write_buf(0,0,img); cl_int2 corners_[350000]; gpu_fast_->write_buf(0,1,350000,corners_); int icorner[1]={0}; gpu_fast_->write_buf(0,2,1,icorner); gpu_fast_->write_buf(0,3,(1 << 18)); klt_homography_init_=new initialization::KltHomographyInit(gpu_fast_); initialize(); imu_integPtr_=std::make_shared(SE_init); } void FrameHandlerMono::initialize() { feature_detection::DetectorPtr feature_detector( new feature_detection::FastDetector( cam_->width(), cam_->height(), Config::gridSize(),gpu_fast_, Config::nPyrLevels())); DepthFilter::callback_t depth_filter_cb = boost::bind( &MapPointCandidates::newCandidatePoint, &map_.point_candidates_, _1, _2); depth_filter_ = new DepthFilter(feature_detector, depth_filter_cb); depth_filter_->startThread(); } FrameHandlerMono::~FrameHandlerMono() { delete depth_filter_; } void FrameHandlerMono::addImage(const cv::Mat& img, const double timestamp) { if(!startFrameProcessingCommon(timestamp)) return; // some cleanup from last iteration, can't do before because of visualization core_kfs_.clear(); overlap_kfs_.clear(); // create new frame new_frame_.reset(new Frame(cam_, img.clone(), timestamp)); // process frame UpdateResult res = RESULT_FAILURE; if(stage_ == STAGE_DEFAULT_FRAME) res = processFrame(); else if(stage_ == STAGE_SECOND_FRAME) res = processSecondFrame(); else if(stage_ == STAGE_FIRST_FRAME) res = processFirstFrame(); else if(stage_ == STAGE_RELOCALIZING) res = relocalizeFrame(SE3(Matrix3d::Identity(), Vector3d::Zero()), map_.getClosestKeyframe(last_frame_)); // set last frame last_frame_ = new_frame_; new_frame_.reset(); // finish processing finishFrameProcessingCommon(last_frame_->id_, res, last_frame_->nObs()); } FrameHandlerMono::UpdateResult FrameHandlerMono::processFirstFrame() { new_frame_->T_f_w_ = SE2_5(0.0,0.0,0.0); if(klt_homography_init_->addFirstFrame(new_frame_) == initialization::FAILURE) return RESULT_NO_KEYFRAME; new_frame_->setKeyframe(); map_.addKeyframe(new_frame_); stage_ = STAGE_SECOND_FRAME; SVO_INFO_STREAM("Init: Selected first frame."); return RESULT_IS_KEYFRAME; } FrameHandlerBase::UpdateResult FrameHandlerMono::processSecondFrame() { new_frame_->T_f_w_ = last_frame_->T_f_w_; initialization::InitResult res = klt_homography_init_->addSecondFrame(new_frame_); if(res == initialization::NO_KEYFRAME) return RESULT_NO_KEYFRAME; new_frame_->setKeyframe(); double depth_mean, depth_min; frame_utils::getSceneDepth(*new_frame_, depth_mean, depth_min); depth_filter_->addKeyframe(new_frame_, depth_mean, 0.5*depth_min); if(!imu_integPtr_->init(new_frame_)){ return RESULT_FAILURE; } // add frame to map map_.addKeyframe(new_frame_); stage_ = STAGE_DEFAULT_FRAME; klt_homography_init_->reset(); SVO_INFO_STREAM("Init: Selected second frame, triangulated initial map."); return RESULT_IS_KEYFRAME; } FrameHandlerBase::UpdateResult FrameHandlerMono::processFrame() { bool IMU=false; SE2_5 tem(0.0,0.0,0.0); if(imu_integPtr_->preintegrate_predict(tem))if((last_frame_->T_f_w_.T->translation()-tem.T->translation()).norm()>0.5){ new_frame_->T_f_w_ = tem; IMU=true; }else{ imu_integPtr_->reset(); new_frame_->T_f_w_ = last_frame_->T_f_w_; } // sparse image align SparseImgAlign img_align(Config::kltMaxLevel(), Config::kltMinLevel(), 30, SparseImgAlign::LevenbergMarquardt, false, false); img_align.run(last_frame_, new_frame_); new_frame_->T_f_w_.set(); // map reprojection & feature alignment reprojector_.reprojectMap(new_frame_, overlap_kfs_); new_frame_->T_f_w_.set(); if(IMU)if(!imu_integPtr_->predict(new_frame_,last_frame_,reprojector_.n_matches_)){ return RESULT_FAILURE; } size_t sfba_n_edges_final=0; double sfba_thresh, sfba_error_init, sfba_error_final; new_frame_->T_f_w_.set(); pose_optimizer::optimizeGaussNewton( Config::poseOptimThresh(), Config::poseOptimNumIter(), false, new_frame_, sfba_thresh, sfba_error_init, sfba_error_final, sfba_n_edges_final); new_frame_->T_f_w_.set(); std::cout<<"Reprojection Map: "<<"\t nPoint:"<T_f_w_.T->translation()-new_frame_->T_f_w_.T->translation()).norm()>1.0){ new_frame_->T_f_w_ = last_frame_->T_f_w_; return RESULT_NO_KEYFRAME; } if(sfba_n_edges_final < Config::qualityMinFts() || reprojector_.n_matches_ < Config::qualityMinFts()){ return RESULT_NO_KEYFRAME; } optimizeStructure(new_frame_, Config::structureOptimMaxPts(), Config::structureOptimNumIter()); new_frame_->T_f_w_.set(); // select keyframe core_kfs_.insert(new_frame_); setTrackingQuality(sfba_n_edges_final); if(tracking_quality_ == TRACKING_INSUFFICIENT) { return RESULT_FAILURE; } double depth_mean, depth_min; new_frame_->T_f_w_.set(); frame_utils::getSceneDepth(*new_frame_, depth_mean, depth_min); if(depth_mean > 50 || depth_mean < 0.0) { return RESULT_NO_KEYFRAME; } if(!needNewKf(depth_mean) || tracking_quality_ == TRACKING_BAD)//edited { depth_filter_->addFrame(new_frame_); return RESULT_NO_KEYFRAME; } new_frame_->setKeyframe(); new_frame_->T_f_w_.set(); // new keyframe selected for(auto&& it:new_frame_->fts_){ if(it->point != NULL)it->point->addFrameRef(it); } map_.point_candidates_.addCandidatePointToFrame(new_frame_); // init new depth-filters depth_filter_->addKeyframe(new_frame_, depth_mean, 0.5*depth_min); // if limited number of keyframes, remove the one furthest apart if(Config::maxNKfs() > 2 && map_.size() >= Config::maxNKfs()) { FramePtr furthest_frame = map_.getFurthestKeyframe(new_frame_->pos()); depth_filter_->removeKeyframe(furthest_frame); // TODO this interrupts the mapper thread, maybe we can solve this better map_.safeDeleteFrame(furthest_frame); } new_frame_->T_f_w_.set(); // add keyframe to map map_.addKeyframe(new_frame_); std::cout<<"Svo pipline was finished\n"; return RESULT_IS_KEYFRAME; } FrameHandlerMono::UpdateResult FrameHandlerMono::relocalizeFrame( const SE3& T_cur_ref, FramePtr ref_keyframe) { if(ref_keyframe == nullptr) { return RESULT_FAILURE; } SparseImgAlign img_align(Config::kltMaxLevel(), Config::kltMinLevel(), 30, SparseImgAlign::GaussNewton, false, false); size_t img_align_n_tracked = img_align.run(ref_keyframe, new_frame_); usleep(2000); if(img_align_n_tracked > Config::qualityMinFts()) { SE2_5 T_f_w_last = last_frame_->T_f_w_; last_frame_ = ref_keyframe; FrameHandlerMono::UpdateResult res = processFrame(); if(res != RESULT_FAILURE) { stage_ = STAGE_DEFAULT_FRAME; } else new_frame_->T_f_w_ = T_f_w_last; // reset to last well localized pose return res; } return RESULT_FAILURE; } bool FrameHandlerMono::relocalizeFrameAtPose( const int keyframe_id, const SE3& T_f_kf, const cv::Mat& img, const double timestamp) { FramePtr ref_keyframe; if(!map_.getKeyframeById(keyframe_id, ref_keyframe)) return false; new_frame_.reset(new Frame(cam_, img.clone(), timestamp)); UpdateResult res = relocalizeFrame(T_f_kf, ref_keyframe); if(res != RESULT_FAILURE) { last_frame_ = new_frame_; return true; } return false; } void FrameHandlerMono::resetAll() { resetCommon(); last_frame_.reset(); new_frame_.reset(); core_kfs_.clear(); overlap_kfs_.clear(); depth_filter_->reset(); } void FrameHandlerMono::setFirstFrame(const FramePtr& first_frame) { resetAll(); last_frame_ = first_frame; last_frame_->setKeyframe(); map_.addKeyframe(last_frame_); stage_ = STAGE_DEFAULT_FRAME; } bool FrameHandlerMono::needNewKf(double scene_depth_mean) { if(scene_depth_mean >10.0)return true; for(auto&& it:overlap_kfs_) { Vector3d relpos = new_frame_->w2f(it.first->pos()); if(fabs(relpos.norm())/scene_depth_mean < Config::kfSelectMinDist()){ return false; } } return true; } void FrameHandlerMono::setCoreKfs(size_t n_closest) { size_t n = min(n_closest, overlap_kfs_.size()-1); std::partial_sort(overlap_kfs_.begin(), overlap_kfs_.begin()+n, overlap_kfs_.end(), boost::bind(&pair::second, _1) > boost::bind(&pair::second, _2)); std::for_each(overlap_kfs_.begin(), overlap_kfs_.end(), [&](pair& i){ core_kfs_.insert(i.first); }); } } // namespace svo