高博十四讲VO调试日志
-
- 2.1.
Eigen
字节对齐 - 2.2. 命名空间
- 2.3. Google glog
- 2.4. auto类型
- 2.5. 重新认识for循环
- 2.6. cv::calcOpticalFlowPyrLK()
- 2.7. cv::KeyPoint
- 2.8. #pragma once
- 2.1.
1. frame.h
1.1. 智能指针
智能指针是C++11
标准模板库里面提供的模板类
。普通指针指向的内存无法自动清除(人为用new
delete
),为了防止内存泄露,智能指针在生存期结束时可以自动析构释放内存。
shared_ptr<T> sp;
unique_ptr<T> up;
weak_ptr<T> make_shared<T>();
shared_ptr<int> ptr1(new int(100));//ptr1指向一个值为100的int型数据
我们可以认为每个shared_ptr都有一个关联的计数器,通常称其为引用计数,无论何时我们拷贝一个shared_ptr,计数器都会递增。当我们给shared_ptr赋予一个新值或是shared_ptr被销毁(例如一个局部的shared_ptr离开其作用域)时,计数器就会递减,一旦一个shared_ptr的计数器变为0,它就会自动释放自己所管理的对象。
shared_ptr允许多个指针指向同一个对象,unique_ptr则“独占”所指向的对象。标准库还定义了一种名为weak_ptr的伴随类,它是一种弱引用,指向shared_ptr所管理的对象,用来防止互相引用无法析构。这三种智能指针都定义在memory头文件中。
- .lock()会检查weak_ptr指向的对象是否存在。如果存在,返回一个指向共享对象的shared_ptr,如果不存在,lock将返回一个空指针。frontend.cpp line 234
1.2. 线程锁
std::mutex
2. frontend.cpp frontend.h
2.1. Eigen
字节对齐
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
Eigen
库为了使用SSE
加速,在内存上分配了128位的指针,涉及字节对齐问题,出问题时在编译时不会报错,只在运行时报错。写下这一句能够让编译器自动将数据对齐。
SSE
指令集是英特尔提供的基于SIMD(单指令多数据,也就是说同一时间内,对多个不同的数据执行同一条命令)的硬件加速指令,通过使用寄存器来进行并行加速。
2.2. 命名空间
namespace myslam{
void Foo();
}
using declaration 访问特定的成员
using myslam::Foo();
using directive 访问整个namespace
using namespace myslam;
Foo();
一般来说,using declaration比using directive 安全。因为
- using declaration明确的告诉我们可以用哪个成员。
- using diclaration如果名字冲突了,编译器会报错;而using directive会覆盖了namespace的版本,而不做任何提示。
可以嵌套和设置别名。
2.3. Google glog
Google glog是一个基于程序级记录日志信息的c++库,编程使用方式与c++的stream操作类似,例:
LOG(INFO) << "Found " << num_cookies << " cookies";
“LOG”宏为日志输出关键字,“INFO”为严重性程度。
官方文档见
http://google-glog.googlecode.com/svn/trunk/doc/glog.html
有好哥哥翻译了该文档
https://blog.youkuaiyun.com/junmuzi/article/details/79670351
2.4. auto类型
auto的原理就是根据后面的值,来自己推测前面的类型是什么。
auto的作用就是为了简化变量初始化,如果这个变量有一个很长很长的初始化类型,就可以用auto代替。
注意点:
1.用auto声明的变量必须初始化(auto是根据后面的值来推测这个变量的类型,如果后面没有值,自然会报错)
2.函数和模板参数不能被声明为auto(原因同上)
3.因为auto是一个占位符,并不是一个他自己的类型,因此不能用于类型转换或其他一些操作,如sizeof和typeid
4.定义在一个auto序列的变量必须始终推导成同一类型
2.5. 重新认识for循环
frontend.cpp line 233
基于范围的for循环,循环从头到尾的每一个元素
for (auto &kp : last_frame_->features_left_)
符号 & 表示 kp 是一个引用变量,将使用并改变 last_frame_->features_left 的原始数据。
若不带 & 则不会改变原始数据 , 循环时使用的是一个副本。
2.6. cv::calcOpticalFlowPyrLK()
frontend.cpp line 249
void cv::calcOpticalFlowPyrLK(
InputArray prevImg,
InputArray nextImg,
InputArray prevPts,
InputOutputArray nextPts,
OutputArray status,
OutputArray err,
Size winSize = Size(21, 21),
int maxLevel = 3,
TermCriteria criteria = TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, 30, 0.01),
int flags = 0,
double minEigThreshold = 1e-4
)
使用具有金字塔的迭代Lucas-Kanade方法计算稀疏特征集的光流。
参数:
prevImg :buildOpticalFlowPyramid构造的第一个8位输入图像或金字塔。
nextImg :与prevImg相同大小和相同类型的第二个输入图像或金字塔
prevPts :需要找到流的2D点的矢量(vector of 2D points for which the flow needs to be found;);点坐标必须是单精度浮点数。
nextPts :输出二维点的矢量(具有单精度浮点坐标),包含第二图像中输入特征的计算新位置;当传递OPTFLOW_USE_INITIAL_FLOW标志时,向量必须与输入中的大小相同。
status :输出状态向量(无符号字符);如果找到相应特征的流,则向量的每个元素设置为1,否则设置为0。
err :输出错误的矢量; 向量的每个元素都设置为相应特征的错误,错误度量的类型可以在flags参数中设置; 如果未找到流,则未定义错误(使用status参数查找此类情况)。
winSize :每个金字塔等级的搜索窗口的winSize大小。
maxLevel :基于0的最大金字塔等级数;如果设置为0,则不使用金字塔(单级),如果设置为1,则使用两个级别,依此类推;如果将金字塔传递给输入,那么算法将使用与金字塔一样多的级别,但不超过maxLevel。
criteria :参数,指定迭代搜索算法的终止条件(在指定的最大迭代次数criteria.maxCount之后或当搜索窗口移动小于criteria.epsilon时)。
flags :操作标志:
OPTFLOW_USE_INITIAL_FLOW使用初始估计,存储在nextPts中;如果未设置标志,则将prevPts复制到nextPts并将其视为初始估计。
OPTFLOW_LK_GET_MIN_EIGENVALS使用最小特征值作为误差测量(参见minEigThreshold描述);如果没有设置标志,则将原稿周围的色块和移动点之间的L1距离除以窗口中的像素数,用作误差测量。
minEigThreshold :算法计算光流方程的2x2正常矩阵的最小特征值,除以窗口中的像素数;如果此值小于minEigThreshold,则过滤掉相应的功能并且不处理其流程,因此它允许删除坏点并获得性能提升。
该函数实现了金字塔中Lucas-Kanade光流的稀疏迭代版本。
2.7. cv::KeyPoint
frontend.cpp line 260
Opencv中KeyPoint类中的默认构造函数如下:
CV_WRAP KeyPoint() : pt(0,0), size(0), angle(-1), response(0), octave(0), class_id(-1) {}
现分析各项属性
pt(x,y):关键点的点坐标;
size():该关键点邻域直径大小;
angle:角度,表示关键点的方向,值为[零,三百六十),负值表示不使用。
response:响应强度,网络上有如下解释:
1)”The response, by which the strongest keypoints have been selected.”
2)”Responseis indeed an indicator of “how good” (roughly speaking, in terms of corner-ness) a point is. The higher, the better. The strongest keypoints means the ones that are the best.“
octacv:从哪一层金字塔得到的此关键点。
class_id:当要对图片进行分类时,用class_id对每个关键点进行区分,默认为-1。
2.8. #pragma once
为了避免同一个头文件被包含(include)多次,C/C++中有两种宏实现方式:一种是#ifndef方式;另一种是#pragma once方式。
在能够支持这两种方式的编译器上,二者并没有太大的区别。
3. 跑代码报错
3.1. eigen
cmake时报错
tian@tian-legion:~/slambook2-master/ch13/build$ cmake ..
-- Configuring done
CMake Error in src/CMakeLists.txt:
Imported target "pangolin" includes non-existent path
"/usr/include/eigen3"
in its INTERFACE_INCLUDE_DIRECTORIES. Possible reasons include:
* The path was deleted, renamed, or moved to another location.
* An install or uninstall procedure did not complete successfully.
* The installation package was faulty and references files it does not
provide.
CMake Error in src/CMakeLists.txt:
Imported target "pangolin" includes non-existent path
"/usr/include/eigen3"
in its INTERFACE_INCLUDE_DIRECTORIES. Possible reasons include:
* The path was deleted, renamed, or moved to another location.
* An install or uninstall procedure did not complete successfully.
* The installation package was faulty and references files it does not
provide.
CMake Error in test/CMakeLists.txt:
Imported target "pangolin" includes non-existent path
"/usr/include/eigen3"
in its INTERFACE_INCLUDE_DIRECTORIES. Possible reasons include:
* The path was deleted, renamed, or moved to another location.
* An install or uninstall procedure did not complete successfully.
* The installation package was faulty and references files it does not
provide.
CMake Error in test/CMakeLists.txt:
Imported target "pangolin" includes non-existent path
"/usr/include/eigen3"
in its INTERFACE_INCLUDE_DIRECTORIES. Possible reasons include:
* The path was deleted, renamed, or moved to another location.
* An install or uninstall procedure did not complete successfully.
* The installation package was faulty and references files it does not
provide.
-- Generating done
CMake Generate step failed. Build files cannot be regenerated correctly.
错误信息提示pangolin找不到eigen3,这是因为它默认搜索"/usr/include/eigen3"这个路径,但笔者在安装eigen3时手动编译,eigen被安装在"/usr/local/include/eigen3"这个目录下。
解决方法
sudo ln -s /usr/local/include/eigen3 /usr/include/eigen3
这样相当于创建了一个快捷方式,让其他程序在"/usr/include/eigen3"中也能找到eigen3.
3.2. fmt
报错
/usr/bin/ld: ../../lib/libmyslam.so: undefined reference to `fmt::v8::detail::assert_fail(char const*, int, char const*)'
解决,在
set(THIRD_PARTY_LIBS
${OpenCV_LIBS}
显式加上fmt
set(THIRD_PARTY_LIBS
${OpenCV_LIBS} fmt
3.3. 还是fmt
报错
/usr/bin/ld: /usr/local/lib/libfmt.a(format.cc.o): relocation R_X86_64_PC32 against symbol `stderr@@GLIBC_2.2.5' can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: final link failed: bad value
collect2: error: ld returned 1 exit status
make[2]: *** [src/CMakeFiles/myslam.dir/build.make:262: ../lib/libmyslam.so] Error 1
make[1]: *** [CMakeFiles/Makefile2:136: src/CMakeFiles/myslam.dir/all] Error 2
make: *** [Makefile:95: all] Error 2
查看报错信息,编译器提示我们重新把fmt这个库带着参数-fPIC编译一遍。具体操作是在fmt库的CMakeLists.txt里加上一句
add_compile_options(-fPIC)
再编译一遍这个库,问题解决。
4. 学习计划
计划在高博VO基础上加全局地图和轨迹的显示和回环检测。