// 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 namespace svo { namespace initialization { InitResult KltHomographyInit::addFirstFrame(FramePtr frame_ref) { reset(); detectFeatures(frame_ref, px_ref_, f_ref_); if(px_ref_.size() < 100) { SVO_WARN_STREAM_THROTTLE(2.0, "First image has less than 100 features. Retry in more textured environment."); return FAILURE; } frame_ref_ = frame_ref; px_cur_.insert(px_cur_.begin(), px_ref_.begin(), px_ref_.end()); return SUCCESS; } InitResult KltHomographyInit::addSecondFrame(FramePtr frame_cur) { trackKlt(frame_ref_, frame_cur, px_ref_, px_cur_, f_ref_, f_cur_, disparities_); SVO_INFO_STREAM("Init: KLT tracked "<< disparities_.size() <<" features"); if(disparities_.size() < Config::initMinTracked()) return FAILURE; double disparity = vk::getMedian(disparities_); SVO_INFO_STREAM("Init: KLT "<cam_->errorMultiplier2(), Config::poseOptimThresh(), inliers_, xyz_in_cur_, T_cur_from_ref_); SVO_INFO_STREAM("Init: Homography RANSAC "< depth_vec; for(size_t i=0; iT_f_w_ = T_cur_from_ref_ * frame_ref_->T_f_w_; frame_cur->T_f_w_.translation() = -frame_cur->T_f_w_.rotation_matrix()*(frame_ref_->pos() + scale*(frame_cur->pos() - frame_ref_->pos())); // For each inlier create 3D point and add feature in both frames SE3 T_world_cur = frame_cur->T_f_w_.inverse(); for(vector::iterator it=inliers_.begin(); it!=inliers_.end(); ++it) { Vector2d px_cur(px_cur_[*it].x, px_cur_[*it].y); Vector2d px_ref(px_ref_[*it].x, px_ref_[*it].y); if(frame_ref_->cam_->isInFrame(px_cur.cast(), 10) && frame_ref_->cam_->isInFrame(px_ref.cast(), 10) && xyz_in_cur_[*it].z() > 0) { Vector3d pos = T_world_cur * (xyz_in_cur_[*it]*scale); Point* new_point = new Point(pos); Feature* ftr_cur(new Feature(frame_cur.get(), new_point, px_cur, f_cur_[*it], 0)); frame_cur->addFeature(ftr_cur); new_point->addFrameRef(ftr_cur); Feature* ftr_ref(new Feature(frame_ref_.get(), new_point, px_ref, f_ref_[*it], 0)); frame_ref_->addFeature(ftr_ref); new_point->addFrameRef(ftr_ref); } } return SUCCESS; } void KltHomographyInit::reset() { px_cur_.clear(); frame_ref_.reset(); } void detectFeatures( FramePtr frame, vector& px_vec, vector& f_vec) { Features new_features; feature_detection::FastDetector detector( frame->img().cols, frame->img().rows, Config::gridSize(), Config::nPyrLevels()); detector.detect(frame.get(), frame->img_pyr_, Config::triangMinCornerScore(), new_features); // now for all maximum corners, initialize a new seed px_vec.clear(); px_vec.reserve(new_features.size()); f_vec.clear(); f_vec.reserve(new_features.size()); std::for_each(new_features.begin(), new_features.end(), [&](Feature* ftr){ px_vec.push_back(cv::Point2f(ftr->px[0], ftr->px[1])); f_vec.push_back(ftr->f); delete ftr; }); } void trackKlt( FramePtr frame_ref, FramePtr frame_cur, vector& px_ref, vector& px_cur, vector& f_ref, vector& f_cur, vector& disparities) { const double klt_win_size = 30.0; const int klt_max_iter = 30; const double klt_eps = 0.001; vector status; vector error; vector min_eig_vec; cv::TermCriteria termcrit(cv::TermCriteria::COUNT+cv::TermCriteria::EPS, klt_max_iter, klt_eps); cv::calcOpticalFlowPyrLK(frame_ref->img_pyr_[0], frame_cur->img_pyr_[0], px_ref, px_cur, status, error, cv::Size2i(klt_win_size, klt_win_size), 4, termcrit); vector::iterator px_ref_it = px_ref.begin(); vector::iterator px_cur_it = px_cur.begin(); vector::iterator f_ref_it = f_ref.begin(); f_cur.clear(); f_cur.reserve(px_cur.size()); disparities.clear(); disparities.reserve(px_cur.size()); for(size_t i=0; px_ref_it != px_ref.end(); ++i) { if(!status[i]) { px_ref_it = px_ref.erase(px_ref_it); px_cur_it = px_cur.erase(px_cur_it); f_ref_it = f_ref.erase(f_ref_it); continue; } f_cur.push_back(frame_cur->c2f(px_cur_it->x, px_cur_it->y)); disparities.push_back(Vector2d(px_ref_it->x - px_cur_it->x, px_ref_it->y - px_cur_it->y).norm()); ++px_ref_it; ++px_cur_it; ++f_ref_it; } } void computeHomography( const vector& f_ref, const vector& f_cur, double focal_length, double reprojection_threshold, vector& inliers, vector& xyz_in_cur, SE3& T_cur_from_ref) { vector > uv_ref(f_ref.size()); vector > uv_cur(f_cur.size()); for(size_t i=0, i_max=f_ref.size(); i outliers; vk::computeInliers(f_cur, f_ref, Homography.T_c2_from_c1.rotation_matrix(), Homography.T_c2_from_c1.translation(), reprojection_threshold, focal_length, xyz_in_cur, inliers, outliers); T_cur_from_ref = Homography.T_c2_from_c1; } } // namespace initialization } // namespace svo