1.setMeasurement()
决定了边类中computeError()函数和linearizeOplus()函数中的_measurement的值
2.g2o_types.h
外参*T
3.留意相机内参什么时候传入
backend.cpp中传了外参
if (feat->is_on_left_iamge_)
{
//这里传入了一个外参
edge = new EdgeProjection(K,left_ext);
}
else
{
edge = new EdgeProjection(K,right_ext);
}
内参还不知道
4.new 类和new 类()区别
有小括号时,小括号中可以有若干参数,也可以没有参数。
比如
ptest = new test(); 这样在构造时就会调用无参构造test();
ptest = new test(1); 就会调用构造函数test(int),即一个整型参数的构造函数。
2 没有小括号时,默认调用无参构造。
即
ptest = new test;
和ptest = new test();是一样的。
5.setLevel()
优化完成后,对每一条边都进行检查,剔除误差较大的边(认为是错误的边),并设置setLevel为0(这里应该是原作者写错了,感觉应该是1),即下次不再对该边进行优化
e->setLevel(1);// 不优化
这里每个边都有一个level的概念,默认情况下,g2o只处理level=0的边,在orbslam中,如果确定某个边的重投影误差过大,则把level设置为1,也就是舍弃这个边对于整个优化的影响)
参考:
SLAM-G2O分析
g2o学习笔记
6.外点为什么还计算误差
frontend.cpp
if (features[i]->is_outlier_)
{
e->computeError();
}
7.weak_ptr expired() reset()
feat->map_point_.reset();
将指针置空,据本人理解,释放指针
expired 用于检测所管理的对象是否已经释放, 如果已经释放, 返回 true; 否则返回 false.
// weak_ptr::reset example
#include <iostream>
#include <memory>
int main () {
std::shared_ptr<int> sp (new int(10));
std::weak_ptr<int> wp(sp);
std::cout << "1. wp " << (wp.expired()?"is":"is not") << " expired\n";
wp.reset();
std::cout << "2. wp " << (wp.expired()?"is":"is not") << " expired\n";
return 0;
}
结果:
1. wp is not expired
2. wp is expired
代码出处:
std::weak_ptr::reset
8.g2o::SparseOptimizer::optimize()里面做了什么 optimizer.optimize(10);
参考:G2O使用要点总结
/**
* starts one optimization run given the current configuration of the graph,
* and the current settings stored in the class instance.
* It can be called only after initializeOptimization
*/
int optimize(int iterations, bool online = false);
int SparseOptimizer::optimize(int iterations, bool online)
{
if (_ivMap.size() == 0) {
cerr << __PRETTY_FUNCTION__ << ": 0 vertices to optimize, maybe forgot to call initializeOptimization()" << endl;
return -1;
}
int cjIterations=0;
number_t cumTime=0;
bool ok=true;
ok = _algorithm->init(online);
if (! ok) {
cerr << __PRETTY_FUNCTION__ << " Error while initializing" << endl;
return -1;
}
_batchStatistics.clear();
if (_computeBatchStatistics)
_batchStatistics.resize(iterations);
OptimizationAlgorithm::SolverResult result = OptimizationAlgorithm::OK;
for (int i=0; i<iterations && ! terminate() && ok; i++){
preIteration(i);
if (_computeBatchStatistics) {
G2OBatchStatistics& cstat = _batchStatistics[i];
G2OBatchStatistics::setGlobalStats(&cstat);
cstat.iteration = i;
cstat.numEdges = _activeEdges.size();
cstat.numVertices = _activeVertices.size();
}
number_t ts = get_monotonic_time();
result = _algorithm->solve(i, online);
ok = ( result == OptimizationAlgorithm::OK );
bool errorComputed = false;
if (_computeBatchStatistics) {
computeActiveErrors();
errorComputed = true;
_batchStatistics[i].chi2 = activeRobustChi2();
_batchStatistics[i].timeIteration = get_monotonic_time()-ts;
}
if (verbose()){
number_t dts = get_monotonic_time()-ts;
cumTime += dts;
if (! errorComputed)
computeActiveErrors();
cerr << "iteration= " << i
<< "\t chi2= " << FIXED(activeRobustChi2())
<< "\t time= " << dts
<< "\t cumTime= " << cumTime
<< "\t edges= " << _activeEdges.size();
_algorithm->printVerbose(cerr);
cerr << endl;
}
++cjIterations;
postIteration(i);
}
if (result == OptimizationAlgorithm::Fail) {
return 0;
}
return cjIterations;
}
computeActiveErrors:
void SparseOptimizer::computeActiveErrors()
{
// call the callbacks in case there is something registered
HyperGraphActionSet& actions = _graphActions[AT_COMPUTEACTIVERROR];
if (actions.size() > 0) {
for (HyperGraphActionSet::iterator it = actions.begin(); it != actions.end(); ++it)
(*(*it))(this);
}
# ifdef G2O_OPENMP
# pragma omp parallel for default (shared) if (_activeEdges.size() > 50)
# endif
for (int k = 0; k < static_cast<int>(_activeEdges.size()); ++k) {
OptimizableGraph::Edge* e = _activeEdges[k];
e->computeError();
}
# ifndef NDEBUG
for (int k = 0; k < static_cast<int>(_activeEdges.size()); ++k) {
OptimizableGraph::Edge* e = _activeEdges[k];
bool hasNan = arrayHasNaN(e->errorData(), e->dimension());
if (hasNan) {
cerr << "computeActiveErrors(): found NaN in error for edge " << e << endl;
}
}
# endif
}
9.frontend.cpp:int Frontend::TrackLastFrame()
else
{
/********************kps_last与kps_current这不就一样了么**********************/
kps_last.push_back(kp->position_.pt);
kps_current.push_back(kp->position_.pt);
}
10.cv::KeyPoint构造函数
@param _pt x & y coordinates of the keypoint
@param _size keypoint diameter
@param _angle keypoint orientation
@param _response keypoint detector response on the keypoint (that is, strength of the keypoint)
@param _octave pyramid octave in which the keypoint has been detected
@param _class_id object id
*/
KeyPoint(Point2f _pt, float _size, float _angle=-1, float _response=0, int _octave=0, int _class_id=-1);
11.cv::calcOpticalFlowPyrLK
头文件
cv::TermCriteria类
定义迭代算法终止条件的类。
TermCriteria类定义在 /core/types.hpp 中
成员变量
enum
{
COUNT=1, //计算元素或者迭代次数最小值
MAX_ITER=COUNT, //最大迭代次数
EPS=2 //当满足该精确度时,迭代算法停止
};
构造函数
C++: TermCriteria::TermCriteria()
C++: TermCriteria::TermCriteria(int type, int maxCount, double epsilon)
C++: TermCriteria::TermCriteria(const CvTermCriteria& criteria)
参数:
type – 终止条件类型:
maxCount – 计算的迭代数或者最大元素数
epsilon – 当达到要求的精确度或参数的变化范围时,迭代算法停止
type可选:
TermCriteria::COUNT //达到最大迭代次数
TermCriteria::EPS //达到精度
TermCriteria::COUNT + TermCriteria::EPS //以上两种同时作为判定条件
参考:OpenCV cv::TermCriteria 模板类
12.cv::Mat()构造函数
cv::Mat mask(current_frame_->left_img_.size(),CV_8UC1,255);
/** @overload
@param size 2D array size: Size(cols, rows) . In the Size() constructor, the number of rows and the
number of columns go in the reverse order.
@param type Array type. Use CV_8UC1, ..., CV_64FC4 to create 1-4 channel matrices, or
CV_8UC(n), ..., CV_64FC(n) to create multi-channel (up to CV_CN_MAX channels) matrices.
@param s An optional value to initialize each matrix element with. To set all the matrix elements to
the particular value after the construction, use the assignment operator
Mat::operator=(const Scalar& value) .
*/
Mat(Size size, int type, const Scalar& s);
例子:OpenCV学习笔记(3)——Scalar数据类型理解
Scalar常用的使用场景如下:
Mat M(7,7,CV_32FC2,Scalar(1,3));
上面的代码表示:创建一个2通道,且每个通道的值都为(1,3),深度为32,7行7列的图像矩阵。CV_32F表示每个元素的值的类型为32位浮点数,C2表示通道数为2,Scalar(1,3)表示对矩阵每个元素都赋值为(1,3),第一个通道中的值都是1,第二个通道中的值都是3.
CV_8UC1:
预定义类型的结构如下所示:
CV_<bit_depth>(S|U|F)C<number_of_channels>
1–bit_depth—比特数—代表8bite,16bites,32bites,64bites—举个例子吧–比如说,如
如果你现在创建了一个存储–灰度图片的Mat对象,这个图像的大小为宽100,高100,那么,现在这张
灰度图片中有10000个像素点,它每一个像素点在内存空间所占的空间大小是8bite,8位–所以它对
应的就是CV_8
2–S|U|F–S–代表—signed int—有符号整形
U–代表–unsigned int–无符号整形
F–代表–float---------单精度浮点型
3–C<number_of_channels>----代表—一张图片的通道数,比如:
1–灰度图片–grayImg—是–单通道图像
2–RGB彩色图像---------是–3通道图像
3–带Alph通道的RGB图像–是–4通道图像
参考连接:Opencv 中 CV_8UC1,CV_32FC3等参数的含义
13.rectangle
cv::rectangle(mask,feat->position_.pt-cv::Point2f(10,10),
feat->position_.pt+cv::Point2f(10,10),0,CV_FILLED);
CV_FILLED为负数,绘制实心图形
CV_EXPORTS_W void rectangle(InputOutputArray img, Point pt1, Point pt2,
const Scalar& color, int thickness = 1,
int lineType = LINE_8, int shift = 0);
14.cv::detect()
占个坑
15.int Frontend::DetectFeatures()
mask作用:?
执行这个函数前,就已经有特征点了么?????????????
16.for (auto &landmark: landmarks)和for (auto &obs:observations)的嵌套循环
思考这层嵌套是啥关系??
for (auto &landmark: landmarks)
{
if (landmark.second->is_outlier_) continue;
unsigned long landmark_id = landmark.second->id_;
auto observations = landmark.second->GetObs();
for (auto &obs:observations)
{
if (obs.lock() == nullptr) continue;
auto feat = obs.lock();
if (feat->is_outlier_ || feat->frame_.lock() == nullptr) continue;
...