/**
* This file is part of ORB-SLAM3
*
* Copyright (C) 2017-2021 Carlos Campos, Richard Elvira, Juan J. Gómez Rodríguez, José M.M. Montiel and Juan D. Tardós, University of Zaragoza.
* Copyright (C) 2014-2016 Raúl Mur-Artal, José M.M. Montiel and Juan D. Tardós, University of Zaragoza.
*
* ORB-SLAM3 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
* (at your option) any later version.
*
* ORB-SLAM3 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 ORB-SLAM3.
* If not, see .
*/
#include "Frame.h"
#include "G2oTypes.h"
#include "MapPoint.h"
#include "KeyFrame.h"
#include "ORBextractor.h"
#include "Converter.h"
#include "ORBmatcher.h"
#include "GeometricCamera.h"
#include
#include
#include
namespace ORB_SLAM3
{
long unsigned int Frame::nNextId=0;
bool Frame::mbInitialComputations=true;
float Frame::cx, Frame::cy, Frame::fx, Frame::fy, Frame::invfx, Frame::invfy;
float Frame::mnMinX, Frame::mnMinY, Frame::mnMaxX, Frame::mnMaxY;
float Frame::mfGridElementWidthInv, Frame::mfGridElementHeightInv;
//For stereo fisheye matching
cv::BFMatcher Frame::BFmatcher = cv::BFMatcher(cv::NORM_HAMMING);
Frame::Frame(): mpcpi(NULL), mpImuPreintegrated(NULL), mpPrevFrame(NULL), mpImuPreintegratedFrame(NULL), mpReferenceKF(static_cast(NULL)), mbIsSet(false), mbImuPreintegrated(false), mbHasPose(false), mbHasVelocity(false)
{
#ifdef REGISTER_TIMES
mTimeStereoMatch = 0;
mTimeORB_Ext = 0;
#endif
}
//Copy Constructor
Frame::Frame(const Frame &frame)
:mpcpi(frame.mpcpi),mpORBvocabulary(frame.mpORBvocabulary), mpORBextractorLeft(frame.mpORBextractorLeft), mpORBextractorRight(frame.mpORBextractorRight),
mTimeStamp(frame.mTimeStamp), mK(frame.mK.clone()), mK_(Converter::toMatrix3f(frame.mK)), mDistCoef(frame.mDistCoef.clone()),
mbf(frame.mbf), mb(frame.mb), mThDepth(frame.mThDepth), N(frame.N), mvKeys(frame.mvKeys),
mvKeysRight(frame.mvKeysRight), mvKeysUn(frame.mvKeysUn), mvuRight(frame.mvuRight),
mvDepth(frame.mvDepth), mBowVec(frame.mBowVec), mFeatVec(frame.mFeatVec),
mDescriptors(frame.mDescriptors.clone()), mDescriptorsRight(frame.mDescriptorsRight.clone()),
mvpMapPoints(frame.mvpMapPoints), mvbOutlier(frame.mvbOutlier), mImuCalib(frame.mImuCalib), mnCloseMPs(frame.mnCloseMPs),
mpImuPreintegrated(frame.mpImuPreintegrated), mpImuPreintegratedFrame(frame.mpImuPreintegratedFrame), mImuBias(frame.mImuBias),
mnId(frame.mnId), mpReferenceKF(frame.mpReferenceKF), mnScaleLevels(frame.mnScaleLevels),
mfScaleFactor(frame.mfScaleFactor), mfLogScaleFactor(frame.mfLogScaleFactor),
mvScaleFactors(frame.mvScaleFactors), mvInvScaleFactors(frame.mvInvScaleFactors), mNameFile(frame.mNameFile), mnDataset(frame.mnDataset),
mvLevelSigma2(frame.mvLevelSigma2), mvInvLevelSigma2(frame.mvInvLevelSigma2), mpPrevFrame(frame.mpPrevFrame), mpLastKeyFrame(frame.mpLastKeyFrame),
mbIsSet(frame.mbIsSet), mbImuPreintegrated(frame.mbImuPreintegrated), mpMutexImu(frame.mpMutexImu),
mpCamera(frame.mpCamera), mpCamera2(frame.mpCamera2), Nleft(frame.Nleft), Nright(frame.Nright),
monoLeft(frame.monoLeft), monoRight(frame.monoRight), mvLeftToRightMatch(frame.mvLeftToRightMatch),
mvRightToLeftMatch(frame.mvRightToLeftMatch), mvStereo3Dpoints(frame.mvStereo3Dpoints),
mTlr(frame.mTlr), mRlr(frame.mRlr), mtlr(frame.mtlr), mTrl(frame.mTrl),
mTcw(frame.mTcw), mbHasPose(false), mbHasVelocity(false)
{
for(int i=0;i 0){
mGridRight[i][j] = frame.mGridRight[i][j];
}
}
if(frame.mbHasPose)
SetPose(frame.GetPose());
if(frame.HasVelocity())
{
SetVelocity(frame.GetVelocity());
}
mmProjectPoints = frame.mmProjectPoints;
mmMatchedInImage = frame.mmMatchedInImage;
#ifdef REGISTER_TIMES
mTimeStereoMatch = frame.mTimeStereoMatch;
mTimeORB_Ext = frame.mTimeORB_Ext;
#endif
}
Frame::Frame(const cv::Mat &imLeft, const cv::Mat &imRight, const double &timeStamp, ORBextractor* extractorLeft, ORBextractor* extractorRight, ORBVocabulary* voc, cv::Mat &K, cv::Mat &distCoef, const float &bf, const float &thDepth, GeometricCamera* pCamera, Frame* pPrevF, const IMU::Calib &ImuCalib)
:mpcpi(NULL), mpORBvocabulary(voc),mpORBextractorLeft(extractorLeft),mpORBextractorRight(extractorRight), mTimeStamp(timeStamp), mK(K.clone()), mK_(Converter::toMatrix3f(K)), mDistCoef(distCoef.clone()), mbf(bf), mThDepth(thDepth),
mImuCalib(ImuCalib), mpImuPreintegrated(NULL), mpPrevFrame(pPrevF),mpImuPreintegratedFrame(NULL), mpReferenceKF(static_cast(NULL)), mbIsSet(false), mbImuPreintegrated(false),
mpCamera(pCamera) ,mpCamera2(nullptr), mbHasPose(false), mbHasVelocity(false)
{
// Frame ID
mnId=nNextId++;
// Scale Level Info
mnScaleLevels = mpORBextractorLeft->GetLevels();
mfScaleFactor = mpORBextractorLeft->GetScaleFactor();
mfLogScaleFactor = log(mfScaleFactor);
mvScaleFactors = mpORBextractorLeft->GetScaleFactors();
mvInvScaleFactors = mpORBextractorLeft->GetInverseScaleFactors();
mvLevelSigma2 = mpORBextractorLeft->GetScaleSigmaSquares();
mvInvLevelSigma2 = mpORBextractorLeft->GetInverseScaleSigmaSquares();
// ORB extraction
#ifdef REGISTER_TIMES
std::chrono::steady_clock::time_point time_StartExtORB = std::chrono::steady_clock::now();
#endif
thread threadLeft(&Frame::ExtractORB,this,0,imLeft,0,0);
thread threadRight(&Frame::ExtractORB,this,1,imRight,0,0);
threadLeft.join();
threadRight.join();
#ifdef REGISTER_TIMES
std::chrono::steady_clock::time_point time_EndExtORB = std::chrono::steady_clock::now();
mTimeORB_Ext = std::chrono::duration_cast >(time_EndExtORB - time_StartExtORB).count();
#endif
N = mvKeys.size();
if(mvKeys.empty())
return;
UndistortKeyPoints();
#ifdef REGISTER_TIMES
std::chrono::steady_clock::time_point time_StartStereoMatches = std::chrono::steady_clock::now();
#endif
ComputeStereoMatches();
#ifdef REGISTER_TIMES
std::chrono::steady_clock::time_point time_EndStereoMatches = std::chrono::steady_clock::now();
mTimeStereoMatch = std::chrono::duration_cast >(time_EndStereoMatches - time_StartStereoMatches).count();
#endif
mvpMapPoints = vector(N,static_cast(NULL));
mvbOutlier = vector(N,false);
mmProjectPoints.clear();
mmMatchedInImage.clear();
// This is done only for the first Frame (or after a change in the calibration)
if(mbInitialComputations)
{
ComputeImageBounds(imLeft);
mfGridElementWidthInv=static_cast(FRAME_GRID_COLS)/(mnMaxX-mnMinX);
mfGridElementHeightInv=static_cast(FRAME_GRID_ROWS)/(mnMaxY-mnMinY);
fx = K.at(0,0);
fy = K.at(1,1);
cx = K.at(0,2);
cy = K.at(1,2);
invfx = 1.0f/fx;
invfy = 1.0f/fy;
mbInitialComputations=false;
}
mb = mbf/fx;
if(pPrevF)
{
if(pPrevF->HasVelocity())
SetVelocity(pPrevF->GetVelocity());
}
else
{
mVw.setZero();
}
mpMutexImu = new std::mutex();
//Set no stereo fisheye information
Nleft = -1;
Nright = -1;
mvLeftToRightMatch = vector(0);
mvRightToLeftMatch = vector(0);
mvStereo3Dpoints = vector(0);
monoLeft = -1;
monoRight = -1;
AssignFeaturesToGrid();
}
Frame::Frame(const cv::Mat &imGray, const cv::Mat &imDepth, const double &timeStamp, ORBextractor* extractor,ORBVocabulary* voc, cv::Mat &K, cv::Mat &distCoef, const float &bf, const float &thDepth, GeometricCamera* pCamera,Frame* pPrevF, const IMU::Calib &ImuCalib)
:mpcpi(NULL),mpORBvocabulary(voc),mpORBextractorLeft(extractor),mpORBextractorRight(static_cast(NULL)),
mTimeStamp(timeStamp), mK(K.clone()), mK_(Converter::toMatrix3f(K)),mDistCoef(distCoef.clone()), mbf(bf), mThDepth(thDepth),
mImuCalib(ImuCalib), mpImuPreintegrated(NULL), mpPrevFrame(pPrevF), mpImuPreintegratedFrame(NULL), mpReferenceKF(static_cast(NULL)), mbIsSet(false), mbImuPreintegrated(false),
mpCamera(pCamera),mpCamera2(nullptr), mbHasPose(false), mbHasVelocity(false)
{
// Frame ID
mnId=nNextId++;
// Scale Level Info
mnScaleLevels = mpORBextractorLeft->GetLevels();
mfScaleFactor = mpORBextractorLeft->GetScaleFactor();
mfLogScaleFactor = log(mfScaleFactor);
mvScaleFactors = mpORBextractorLeft->GetScaleFactors();
mvInvScaleFactors = mpORBextractorLeft->GetInverseScaleFactors();
mvLevelSigma2 = mpORBextractorLeft->GetScaleSigmaSquares();
mvInvLevelSigma2 = mpORBextractorLeft->GetInverseScaleSigmaSquares();
// ORB extraction
#ifdef REGISTER_TIMES
std::chrono::steady_clock::time_point time_StartExtORB = std::chrono::steady_clock::now();
#endif
ExtractORB(0,imGray,0,0);
#ifdef REGISTER_TIMES
std::chrono::steady_clock::time_point time_EndExtORB = std::chrono::steady_clock::now();
mTimeORB_Ext = std::chrono::duration_cast >(time_EndExtORB - time_StartExtORB).count();
#endif
N = mvKeys.size();
if(mvKeys.empty())
return;
UndistortKeyPoints();
ComputeStereoFromRGBD(imDepth);
mvpMapPoints = vector(N,static_cast(NULL));
mmProjectPoints.clear();
mmMatchedInImage.clear();
mvbOutlier = vector(N,false);
// This is done only for the first Frame (or after a change in the calibration)
if(mbInitialComputations)
{
ComputeImageBounds(imGray);
mfGridElementWidthInv=static_cast(FRAME_GRID_COLS)/static_cast(mnMaxX-mnMinX);
mfGridElementHeightInv=static_cast(FRAME_GRID_ROWS)/static_cast(mnMaxY-mnMinY);
fx = K.at(0,0);
fy = K.at(1,1);
cx = K.at(0,2);
cy = K.at(1,2);
invfx = 1.0f/fx;
invfy = 1.0f/fy;
mbInitialComputations=false;
}
mb = mbf/fx;
if(pPrevF){
if(pPrevF->HasVelocity())
SetVelocity(pPrevF->GetVelocity());
}
else{
mVw.setZero();
}
mpMutexImu = new std::mutex();
//Set no stereo fisheye information
Nleft = -1;
Nright = -1;
mvLeftToRightMatch = vector(0);
mvRightToLeftMatch = vector(0);
mvStereo3Dpoints = vector(0);
monoLeft = -1;
monoRight = -1;
AssignFeaturesToGrid();
}
Frame::Frame(const cv::Mat &imGray, const double &timeStamp, ORBextractor* extractor,ORBVocabulary* voc, GeometricCamera* pCamera, cv::Mat &distCoef, const float &bf, const float &thDepth, Frame* pPrevF, const IMU::Calib &ImuCalib)
:mpcpi(NULL),mpORBvocabulary(voc),mpORBextractorLeft(extractor),mpORBextractorRight(static_cast(NULL)),
mTimeStamp(timeStamp), mK(static_cast(pCamera)->toK()), mK_(static_cast(pCamera)->toK_()), mDistCoef(distCoef.clone()), mbf(bf), mThDepth(thDepth),
mImuCalib(ImuCalib), mpImuPreintegrated(NULL),mpPrevFrame(pPrevF),mpImuPreintegratedFrame(NULL), mpReferenceKF(static_cast(NULL)), mbIsSet(false), mbImuPreintegrated(false), mpCamera(pCamera),
mpCamera2(nullptr), mbHasPose(false), mbHasVelocity(false)
{
// Frame ID
mnId=nNextId++;
// Scale Level Info
mnScaleLevels = mpORBextractorLeft->GetLevels();
mfScaleFactor = mpORBextractorLeft->GetScaleFactor();
mfLogScaleFactor = log(mfScaleFactor);
mvScaleFactors = mpORBextractorLeft->GetScaleFactors();
mvInvScaleFactors = mpORBextractorLeft->GetInverseScaleFactors();
mvLevelSigma2 = mpORBextractorLeft->GetScaleSigmaSquares();
mvInvLevelSigma2 = mpORBextractorLeft->GetInverseScaleSigmaSquares();
// ORB extraction
#ifdef REGISTER_TIMES
std::chrono::steady_clock::time_point time_StartExtORB = std::chrono::steady_clock::now();
#endif
ExtractORB(0,imGray,0,1000);
#ifdef REGISTER_TIMES
std::chrono::steady_clock::time_point time_EndExtORB = std::chrono::steady_clock::now();
mTimeORB_Ext = std::chrono::duration_cast >(time_EndExtORB - time_StartExtORB).count();
#endif
N = mvKeys.size();
if(mvKeys.empty())
return;
UndistortKeyPoints();
// Set no stereo information
mvuRight = vector(N,-1);
mvDepth = vector(N,-1);
mnCloseMPs = 0;
mvpMapPoints = vector(N,static_cast(NULL));
mmProjectPoints.clear();// = map(N, static_cast(NULL));
mmMatchedInImage.clear();
mvbOutlier = vector(N,false);
// This is done only for the first Frame (or after a change in the calibration)
if(mbInitialComputations)
{
ComputeImageBounds(imGray);
mfGridElementWidthInv=static_cast(FRAME_GRID_COLS)/static_cast(mnMaxX-mnMinX);
mfGridElementHeightInv=static_cast(FRAME_GRID_ROWS)/static_cast(mnMaxY-mnMinY);
fx = static_cast(mpCamera)->toK().at(0,0);
fy = static_cast(mpCamera)->toK().at(1,1);
cx = static_cast(mpCamera)->toK().at(0,2);
cy = static_cast(mpCamera)->toK().at(1,2);
invfx = 1.0f/fx;
invfy = 1.0f/fy;
mbInitialComputations=false;
}
mb = mbf/fx;
//Set no stereo fisheye information
Nleft = -1;
Nright = -1;
mvLeftToRightMatch = vector(0);
mvRightToLeftMatch = vector(0);
mvStereo3Dpoints = vector(0);
monoLeft = -1;
monoRight = -1;
AssignFeaturesToGrid();
if(pPrevF)
{
if(pPrevF->HasVelocity())
{
SetVelocity(pPrevF->GetVelocity());
}
}
else
{
mVw.setZero();
}
mpMutexImu = new std::mutex();
}
void Frame::AssignFeaturesToGrid()
{
// Fill matrix with points
const int nCells = FRAME_GRID_COLS*FRAME_GRID_ROWS;
int nReserve = 0.5f*N/(nCells);
for(unsigned int i=0; i vLapping = {x0,x1};
if(flag==0)
monoLeft = (*mpORBextractorLeft)(im,cv::Mat(),mvKeys,mDescriptors,vLapping);
else
monoRight = (*mpORBextractorRight)(im,cv::Mat(),mvKeysRight,mDescriptorsRight,vLapping);
}
bool Frame::isSet() const {
return mbIsSet;
}
void Frame::SetPose(const Sophus::SE3 &Tcw) {
mTcw = Tcw;
UpdatePoseMatrices();
mbIsSet = true;
mbHasPose = true;
}
void Frame::SetNewBias(const IMU::Bias &b)
{
mImuBias = b;
if(mpImuPreintegrated)
mpImuPreintegrated->SetNewBias(b);
}
void Frame::SetVelocity(Eigen::Vector3f Vwb)
{
mVw = Vwb;
mbHasVelocity = true;
}
Eigen::Vector3f Frame::GetVelocity() const
{
return mVw;
}
void Frame::SetImuPoseVelocity(const Eigen::Matrix3f &Rwb, const Eigen::Vector3f &twb, const Eigen::Vector3f &Vwb)
{
mVw = Vwb;
mbHasVelocity = true;
Sophus::SE3f Twb(Rwb, twb);
Sophus::SE3f Tbw = Twb.inverse();
mTcw = mImuCalib.mTcb * Tbw;
UpdatePoseMatrices();
mbIsSet = true;
mbHasPose = true;
}
void Frame::UpdatePoseMatrices()
{
Sophus::SE3 Twc = mTcw.inverse();
mRwc = Twc.rotationMatrix();
mOw = Twc.translation();
mRcw = mTcw.rotationMatrix();
mtcw = mTcw.translation();
}
Eigen::Matrix Frame::GetImuPosition() const {
return mRwc * mImuCalib.mTcb.translation() + mOw;
}
Eigen::Matrix Frame::GetImuRotation() {
return mRwc * mImuCalib.mTcb.rotationMatrix();
}
Sophus::SE3 Frame::GetImuPose() {
return mTcw.inverse() * mImuCalib.mTcb;
}
Sophus::SE3f Frame::GetRelativePoseTrl()
{
return mTrl;
}
Sophus::SE3f Frame::GetRelativePoseTlr()
{
return mTlr;
}
Eigen::Matrix3f Frame::GetRelativePoseTlr_rotation(){
return mTlr.rotationMatrix();
}
Eigen::Vector3f Frame::GetRelativePoseTlr_translation() {
return mTlr.translation();
}
bool Frame::isInFrustum(MapPoint *pMP, float viewingCosLimit)
{
if(Nleft == -1){
pMP->mbTrackInView = false;
pMP->mTrackProjX = -1;
pMP->mTrackProjY = -1;
// 3D in absolute coordinates
Eigen::Matrix P = pMP->GetWorldPos();
// 3D in camera coordinates
const Eigen::Matrix Pc = mRcw * P + mtcw;
const float Pc_dist = Pc.norm();
// Check positive depth
const float &PcZ = Pc(2);
const float invz = 1.0f/PcZ;
if(PcZ<0.0f)
return false;
const Eigen::Vector2f uv = mpCamera->project(Pc);
if(uv(0)mnMaxX)
return false;
if(uv(1)mnMaxY)
return false;
pMP->mTrackProjX = uv(0);
pMP->mTrackProjY = uv(1);
// Check distance is in the scale invariance region of the MapPoint
const float maxDistance = pMP->GetMaxDistanceInvariance();
const float minDistance = pMP->GetMinDistanceInvariance();
const Eigen::Vector3f PO = P - mOw;
const float dist = PO.norm();
if(distmaxDistance)
return false;
// Check viewing angle
Eigen::Vector3f Pn = pMP->GetNormal();
const float viewCos = PO.dot(Pn)/dist;
if(viewCosPredictScale(dist,this);
// Data used by the tracking
pMP->mbTrackInView = true;
pMP->mTrackProjX = uv(0);
pMP->mTrackProjXR = uv(0) - mbf*invz;
pMP->mTrackDepth = Pc_dist;
pMP->mTrackProjY = uv(1);
pMP->mnTrackScaleLevel= nPredictedLevel;
pMP->mTrackViewCos = viewCos;
return true;
}
else{
pMP->mbTrackInView = false;
pMP->mbTrackInViewR = false;
pMP -> mnTrackScaleLevel = -1;
pMP -> mnTrackScaleLevelR = -1;
pMP->mbTrackInView = isInFrustumChecks(pMP,viewingCosLimit);
pMP->mbTrackInViewR = isInFrustumChecks(pMP,viewingCosLimit,true);
return pMP->mbTrackInView || pMP->mbTrackInViewR;
}
}
bool Frame::ProjectPointDistort(MapPoint* pMP, cv::Point2f &kp, float &u, float &v)
{
// 3D in absolute coordinates
Eigen::Vector3f P = pMP->GetWorldPos();
// 3D in camera coordinates
const Eigen::Vector3f Pc = mRcw * P + mtcw;
const float &PcX = Pc(0);
const float &PcY= Pc(1);
const float &PcZ = Pc(2);
// Check positive depth
if(PcZ<0.0f)
{
cout << "Negative depth: " << PcZ << endl;
return false;
}
// Project in image and check it is not outside
const float invz = 1.0f/PcZ;
u=fx*PcX*invz+cx;
v=fy*PcY*invz+cy;
if(umnMaxX)
return false;
if(vmnMaxY)
return false;
float u_distort, v_distort;
float x = (u - cx) * invfx;
float y = (v - cy) * invfy;
float r2 = x * x + y * y;
float k1 = mDistCoef.at(0);
float k2 = mDistCoef.at(1);
float p1 = mDistCoef.at(2);
float p2 = mDistCoef.at(3);
float k3 = 0;
if(mDistCoef.total() == 5)
{
k3 = mDistCoef.at(4);
}
// Radial distorsion
float x_distort = x * (1 + k1 * r2 + k2 * r2 * r2 + k3 * r2 * r2 * r2);
float y_distort = y * (1 + k1 * r2 + k2 * r2 * r2 + k3 * r2 * r2 * r2);
// Tangential distorsion
x_distort = x_distort + (2 * p1 * x * y + p2 * (r2 + 2 * x * x));
y_distort = y_distort + (p1 * (r2 + 2 * y * y) + 2 * p2 * x * y);
u_distort = x_distort * fx + cx;
v_distort = y_distort * fy + cy;
u = u_distort;
v = v_distort;
kp = cv::Point2f(u, v);
return true;
}
Eigen::Vector3f Frame::inRefCoordinates(Eigen::Vector3f pCw)
{
return mRcw * pCw + mtcw;
}
vector Frame::GetFeaturesInArea(const float &x, const float &y, const float &r, const int minLevel, const int maxLevel, const bool bRight) const
{
vector vIndices;
vIndices.reserve(N);
float factorX = r;
float factorY = r;
const int nMinCellX = max(0,(int)floor((x-mnMinX-factorX)*mfGridElementWidthInv));
if(nMinCellX>=FRAME_GRID_COLS)
{
return vIndices;
}
const int nMaxCellX = min((int)FRAME_GRID_COLS-1,(int)ceil((x-mnMinX+factorX)*mfGridElementWidthInv));
if(nMaxCellX<0)
{
return vIndices;
}
const int nMinCellY = max(0,(int)floor((y-mnMinY-factorY)*mfGridElementHeightInv));
if(nMinCellY>=FRAME_GRID_ROWS)
{
return vIndices;
}
const int nMaxCellY = min((int)FRAME_GRID_ROWS-1,(int)ceil((y-mnMinY+factorY)*mfGridElementHeightInv));
if(nMaxCellY<0)
{
return vIndices;
}
const bool bCheckLevels = (minLevel>0) || (maxLevel>=0);
for(int ix = nMinCellX; ix<=nMaxCellX; ix++)
{
for(int iy = nMinCellY; iy<=nMaxCellY; iy++)
{
const vector vCell = (!bRight) ? mGrid[ix][iy] : mGridRight[ix][iy];
if(vCell.empty())
continue;
for(size_t j=0, jend=vCell.size(); j=0)
if(kpUn.octave>maxLevel)
continue;
}
const float distx = kpUn.pt.x-x;
const float disty = kpUn.pt.y-y;
if(fabs(distx)=FRAME_GRID_COLS || posY<0 || posY>=FRAME_GRID_ROWS)
return false;
return true;
}
void Frame::ComputeBoW()
{
if(mBowVec.empty())
{
vector vCurrentDesc = Converter::toDescriptorVector(mDescriptors);
mpORBvocabulary->transform(vCurrentDesc,mBowVec,mFeatVec,4);
}
}
void Frame::UndistortKeyPoints()
{
if(mDistCoef.at(0)==0.0)
{
mvKeysUn=mvKeys;
return;
}
// Fill matrix with points
cv::Mat mat(N,2,CV_32F);
for(int i=0; i(i,0)=mvKeys[i].pt.x;
mat.at(i,1)=mvKeys[i].pt.y;
}
// Undistort points
mat=mat.reshape(2);
cv::undistortPoints(mat,mat, static_cast(mpCamera)->toK(),mDistCoef,cv::Mat(),mK);
mat=mat.reshape(1);
// Fill undistorted keypoint vector
mvKeysUn.resize(N);
for(int i=0; i(i,0);
kp.pt.y=mat.at(i,1);
mvKeysUn[i]=kp;
}
}
void Frame::ComputeImageBounds(const cv::Mat &imLeft)
{
if(mDistCoef.at(0)!=0.0)
{
cv::Mat mat(4,2,CV_32F);
mat.at(0,0)=0.0; mat.at(0,1)=0.0;
mat.at(1,0)=imLeft.cols; mat.at(1,1)=0.0;
mat.at(2,0)=0.0; mat.at(2,1)=imLeft.rows;
mat.at(3,0)=imLeft.cols; mat.at(3,1)=imLeft.rows;
mat=mat.reshape(2);
cv::undistortPoints(mat,mat,static_cast(mpCamera)->toK(),mDistCoef,cv::Mat(),mK);
mat=mat.reshape(1);
// Undistort corners
mnMinX = min(mat.at(0,0),mat.at(2,0));
mnMaxX = max(mat.at(1,0),mat.at(3,0));
mnMinY = min(mat.at(0,1),mat.at(1,1));
mnMaxY = max(mat.at(2,1),mat.at(3,1));
}
else
{
mnMinX = 0.0f;
mnMaxX = imLeft.cols;
mnMinY = 0.0f;
mnMaxY = imLeft.rows;
}
}
void Frame::ComputeStereoMatches()
{
mvuRight = vector(N,-1.0f);
mvDepth = vector(N,-1.0f);
const int thOrbDist = (ORBmatcher::TH_HIGH+ORBmatcher::TH_LOW)/2;
const int nRows = mpORBextractorLeft->mvImagePyramid[0].rows;
//Assign keypoints to row table
vector > vRowIndices(nRows,vector());
for(int i=0; i > vDistIdx;
vDistIdx.reserve(N);
for(int iL=0; iL &vCandidates = vRowIndices[vL];
if(vCandidates.empty())
continue;
const float minU = uL-maxD;
const float maxU = uL-minD;
if(maxU<0)
continue;
int bestDist = ORBmatcher::TH_HIGH;
size_t bestIdxR = 0;
const cv::Mat &dL = mDescriptors.row(iL);
// Compare descriptor to right keypoints
for(size_t iC=0; iClevelL+1)
continue;
const float &uR = kpR.pt.x;
if(uR>=minU && uR<=maxU)
{
const cv::Mat &dR = mDescriptorsRight.row(iR);
const int dist = ORBmatcher::DescriptorDistance(dL,dR);
if(distmvImagePyramid[kpL.octave].rowRange(scaledvL-w,scaledvL+w+1).colRange(scaleduL-w,scaleduL+w+1);
int bestDist = INT_MAX;
int bestincR = 0;
const int L = 5;
vector vDists;
vDists.resize(2*L+1);
const float iniu = scaleduR0+L-w;
const float endu = scaleduR0+L+w+1;
if(iniu<0 || endu >= mpORBextractorRight->mvImagePyramid[kpL.octave].cols)
continue;
for(int incR=-L; incR<=+L; incR++)
{
cv::Mat IR = mpORBextractorRight->mvImagePyramid[kpL.octave].rowRange(scaledvL-w,scaledvL+w+1).colRange(scaleduR0+incR-w,scaleduR0+incR+w+1);
float dist = cv::norm(IL,IR,cv::NORM_L1);
if(dist1)
continue;
// Re-scaled coordinate
float bestuR = mvScaleFactors[kpL.octave]*((float)scaleduR0+(float)bestincR+deltaR);
float disparity = (uL-bestuR);
if(disparity>=minD && disparity(bestDist,iL));
}
}
}
sort(vDistIdx.begin(),vDistIdx.end());
const float median = vDistIdx[vDistIdx.size()/2].first;
const float thDist = 1.5f*1.4f*median;
for(int i=vDistIdx.size()-1;i>=0;i--)
{
if(vDistIdx[i].first(N,-1);
mvDepth = vector(N,-1);
for(int i=0; i(v,u);
if(d>0)
{
mvDepth[i] = d;
mvuRight[i] = kpU.pt.x-mbf/d;
}
}
}
bool Frame::UnprojectStereo(const int &i, Eigen::Vector3f &x3D)
{
const float z = mvDepth[i];
if(z>0) {
const float u = mvKeysUn[i].pt.x;
const float v = mvKeysUn[i].pt.y;
const float x = (u-cx)*z*invfx;
const float y = (v-cy)*z*invfy;
Eigen::Vector3f x3Dc(x, y, z);
x3D = mRwc * x3Dc + mOw;
return true;
} else
return false;
}
bool Frame::imuIsPreintegrated()
{
unique_lock lock(*mpMutexImu);
return mbImuPreintegrated;
}
void Frame::setIntegrated()
{
unique_lock lock(*mpMutexImu);
mbImuPreintegrated = true;
}
Frame::Frame(const cv::Mat &imLeft, const cv::Mat &imRight, const double &timeStamp, ORBextractor* extractorLeft, ORBextractor* extractorRight, ORBVocabulary* voc, cv::Mat &K, cv::Mat &distCoef, const float &bf, const float &thDepth, GeometricCamera* pCamera, GeometricCamera* pCamera2, Sophus::SE3f& Tlr,Frame* pPrevF, const IMU::Calib &ImuCalib)
:mpcpi(NULL), mpORBvocabulary(voc),mpORBextractorLeft(extractorLeft),mpORBextractorRight(extractorRight), mTimeStamp(timeStamp), mK(K.clone()), mK_(Converter::toMatrix3f(K)), mDistCoef(distCoef.clone()), mbf(bf), mThDepth(thDepth),
mImuCalib(ImuCalib), mpImuPreintegrated(NULL), mpPrevFrame(pPrevF),mpImuPreintegratedFrame(NULL), mpReferenceKF(static_cast(NULL)), mbImuPreintegrated(false), mpCamera(pCamera), mpCamera2(pCamera2),
mbHasPose(false), mbHasVelocity(false)
{
imgLeft = imLeft.clone();
imgRight = imRight.clone();
// Frame ID
mnId=nNextId++;
// Scale Level Info
mnScaleLevels = mpORBextractorLeft->GetLevels();
mfScaleFactor = mpORBextractorLeft->GetScaleFactor();
mfLogScaleFactor = log(mfScaleFactor);
mvScaleFactors = mpORBextractorLeft->GetScaleFactors();
mvInvScaleFactors = mpORBextractorLeft->GetInverseScaleFactors();
mvLevelSigma2 = mpORBextractorLeft->GetScaleSigmaSquares();
mvInvLevelSigma2 = mpORBextractorLeft->GetInverseScaleSigmaSquares();
// ORB extraction
#ifdef REGISTER_TIMES
std::chrono::steady_clock::time_point time_StartExtORB = std::chrono::steady_clock::now();
#endif
thread threadLeft(&Frame::ExtractORB,this,0,imLeft,static_cast(mpCamera)->mvLappingArea[0],static_cast(mpCamera)->mvLappingArea[1]);
thread threadRight(&Frame::ExtractORB,this,1,imRight,static_cast(mpCamera2)->mvLappingArea[0],static_cast(mpCamera2)->mvLappingArea[1]);
threadLeft.join();
threadRight.join();
#ifdef REGISTER_TIMES
std::chrono::steady_clock::time_point time_EndExtORB = std::chrono::steady_clock::now();
mTimeORB_Ext = std::chrono::duration_cast >(time_EndExtORB - time_StartExtORB).count();
#endif
Nleft = mvKeys.size();
Nright = mvKeysRight.size();
N = Nleft + Nright;
if(N == 0)
return;
// This is done only for the first Frame (or after a change in the calibration)
if(mbInitialComputations)
{
ComputeImageBounds(imLeft);
mfGridElementWidthInv=static_cast(FRAME_GRID_COLS)/(mnMaxX-mnMinX);
mfGridElementHeightInv=static_cast(FRAME_GRID_ROWS)/(mnMaxY-mnMinY);
fx = K.at(0,0);
fy = K.at(1,1);
cx = K.at(0,2);
cy = K.at(1,2);
invfx = 1.0f/fx;
invfy = 1.0f/fy;
mbInitialComputations=false;
}
mb = mbf / fx;
// Sophus/Eigen
mTlr = Tlr;
mTrl = mTlr.inverse();
mRlr = mTlr.rotationMatrix();
mtlr = mTlr.translation();
#ifdef REGISTER_TIMES
std::chrono::steady_clock::time_point time_StartStereoMatches = std::chrono::steady_clock::now();
#endif
ComputeStereoFishEyeMatches();
#ifdef REGISTER_TIMES
std::chrono::steady_clock::time_point time_EndStereoMatches = std::chrono::steady_clock::now();
mTimeStereoMatch = std::chrono::duration_cast >(time_EndStereoMatches - time_StartStereoMatches).count();
#endif
//Put all descriptors in the same matrix
cv::vconcat(mDescriptors,mDescriptorsRight,mDescriptors);
mvpMapPoints = vector(N,static_cast(nullptr));
mvbOutlier = vector(N,false);
AssignFeaturesToGrid();
mpMutexImu = new std::mutex();
UndistortKeyPoints();
}
void Frame::ComputeStereoFishEyeMatches() {
//Speed it up by matching keypoints in the lapping area
vector stereoLeft(mvKeys.begin() + monoLeft, mvKeys.end());
vector stereoRight(mvKeysRight.begin() + monoRight, mvKeysRight.end());
cv::Mat stereoDescLeft = mDescriptors.rowRange(monoLeft, mDescriptors.rows);
cv::Mat stereoDescRight = mDescriptorsRight.rowRange(monoRight, mDescriptorsRight.rows);
mvLeftToRightMatch = vector(Nleft,-1);
mvRightToLeftMatch = vector(Nright,-1);
mvDepth = vector(Nleft,-1.0f);
mvuRight = vector(Nleft,-1);
mvStereo3Dpoints = vector(Nleft);
mnCloseMPs = 0;
//Perform a brute force between Keypoint in the left and right image
vector> matches;
BFmatcher.knnMatch(stereoDescLeft,stereoDescRight,matches,2);
int nMatches = 0;
int descMatches = 0;
//Check matches using Lowe's ratio
for(vector>::iterator it = matches.begin(); it != matches.end(); ++it){
if((*it).size() >= 2 && (*it)[0].distance < (*it)[1].distance * 0.7){
//For every good match, check parallax and reprojection error to discard spurious matches
Eigen::Vector3f p3D;
descMatches++;
float sigma1 = mvLevelSigma2[mvKeys[(*it)[0].queryIdx + monoLeft].octave], sigma2 = mvLevelSigma2[mvKeysRight[(*it)[0].trainIdx + monoRight].octave];
float depth = static_cast(mpCamera)->TriangulateMatches(mpCamera2,mvKeys[(*it)[0].queryIdx + monoLeft],mvKeysRight[(*it)[0].trainIdx + monoRight],mRlr,mtlr,sigma1,sigma2,p3D);
if(depth > 0.0001f){
mvLeftToRightMatch[(*it)[0].queryIdx + monoLeft] = (*it)[0].trainIdx + monoRight;
mvRightToLeftMatch[(*it)[0].trainIdx + monoRight] = (*it)[0].queryIdx + monoLeft;
mvStereo3Dpoints[(*it)[0].queryIdx + monoLeft] = p3D;
mvDepth[(*it)[0].queryIdx + monoLeft] = depth;
nMatches++;
}
}
}
}
bool Frame::isInFrustumChecks(MapPoint *pMP, float viewingCosLimit, bool bRight) {
// 3D in absolute coordinates
Eigen::Vector3f P = pMP->GetWorldPos();
Eigen::Matrix3f mR;
Eigen::Vector3f mt, twc;
if(bRight){
Eigen::Matrix3f Rrl = mTrl.rotationMatrix();
Eigen::Vector3f trl = mTrl.translation();
mR = Rrl * mRcw;
mt = Rrl * mtcw + trl;
twc = mRwc * mTlr.translation() + mOw;
}
else{
mR = mRcw;
mt = mtcw;
twc = mOw;
}
// 3D in camera coordinates
Eigen::Vector3f Pc = mR * P + mt;
const float Pc_dist = Pc.norm();
const float &PcZ = Pc(2);
// Check positive depth
if(PcZ<0.0f)
return false;
// Project in image and check it is not outside
Eigen::Vector2f uv;
if(bRight) uv = mpCamera2->project(Pc);
else uv = mpCamera->project(Pc);
if(uv(0)mnMaxX)
return false;
if(uv(1)mnMaxY)
return false;
// Check distance is in the scale invariance region of the MapPoint
const float maxDistance = pMP->GetMaxDistanceInvariance();
const float minDistance = pMP->GetMinDistanceInvariance();
const Eigen::Vector3f PO = P - twc;
const float dist = PO.norm();
if(distmaxDistance)
return false;
// Check viewing angle
Eigen::Vector3f Pn = pMP->GetNormal();
const float viewCos = PO.dot(Pn) / dist;
if(viewCosPredictScale(dist,this);
if(bRight){
pMP->mTrackProjXR = uv(0);
pMP->mTrackProjYR = uv(1);
pMP->mnTrackScaleLevelR= nPredictedLevel;
pMP->mTrackViewCosR = viewCos;
pMP->mTrackDepthR = Pc_dist;
}
else{
pMP->mTrackProjX = uv(0);
pMP->mTrackProjY = uv(1);
pMP->mnTrackScaleLevel= nPredictedLevel;
pMP->mTrackViewCos = viewCos;
pMP->mTrackDepth = Pc_dist;
}
return true;
}
Eigen::Vector3f Frame::UnprojectStereoFishEye(const int &i){
return mRwc * mvStereo3Dpoints[i] + mOw;
}
} //namespace ORB_SLAM