SLAM从入门到放弃:SLAM十四讲第五章习题(3-6)
以下均为简单笔记,如有错误,请多多指教。
-
搜索特殊相机(鱼眼或全景相机)的标定方法。它们与普通的针孔模型有何不同?
解: 目前比较常用的鱼眼或全景相机的标定工具有opencv,OcamCalib(https://github.com/urbste/ImprovedOcamCalib),SWARD等等非常多的工具。通常而言其标定思路与常规相机并没有太大区别,首先采集一系列棋盘格的影像,然后使用手动或者自动提取出所有的棋盘角点,并在其基础上进行畸变参数的求解。但是区别在于,鱼眼或全景通常会采用更加复杂的畸变模型,最常用的就是一个多线性畸变公式,如下式所示(OpenCV中的示例):
。
其主要原因是此类相机通常并不符合针孔模型,其成像过程可以用下图展示,可以发现其成像过程是一个球面折射过程。 -
调研全局快门相机和卷帘快门相机的异同。它们在SLAM中有何优缺点?
答: 参考资料:https://www.oxinst.com/learning/view/article/rolling-and-global-shutter。
下图展示了全局相机和卷帘快门相机成像方式的区别,全局相机是一次成像,所有的像素同时停止曝光;而卷帘相机是逐行成像,不同的像素停止曝光的时间不同。
因此当出现高速运动后,卷帘相机会出现明显的“果冻效应”,如左图所示。右图展示的全局相机的拍摄结果,可以发现虽然仍然出现了模糊问题,但是并没有出现果冻问题。
至于他们在SLAM中的优缺点,我感觉目前的大趋势是使用全局快门相机,因为其明显更精确,但是其缺点可能是相对而言比较贵吧~ -
RGB-D相机是如何标定的?以Kinect为例,需要标定那些参数?(参照 https://github.com/code-iai/iai_kinect2)
答: 本人对Kinect不是很熟悉,所以一下答案都是参考iai_kinect2得到,其标定过程与普通相机似乎差异也不是特别大,只是需要同时标定RGB相机和红外相机,需要标定的参数有RGB的内参数,红外相机的内参数,RGB相机和红外相机之间的变化关系,红外相机的深度信息校正。
因此其标定过程通常如下:首先采集一系列RGB影像,然后标定内参数;然后采集一系列红外影像,标定内参数;接下来同时采集RGB影像和红外影像,标定两个相机之间的外参数,并同时对红外相机的深度信息进行校正。
值得注意的是,iai_kinect2标定要求采集数据时标定板和相机都处于静止静止状态,从而避免运动对标定结果的影响,因此相机和标定板都最好放在一个固定架上。另外则是相机最好能够从多个角度、多个深度采集数据数据。 -
除了示例程序演示的遍历图像方式,你还能举出哪些遍历图像的方法?
答:OpenCV中常用的遍历图像的方法主要有三中,包括基于at,ptr和迭代器的方法,本人的实验结果是是ptr的效果最佳。
#include <iostream>
#include <ctime>
#include <opencv2/opencv.hpp>
int main()
{
// Mat
cv::Mat image = cv::Mat::zeros(1000, 1000, CV_8UC3);
// By at
clock_t atBegin = clock();
for (int y = 0; y < image.rows; y++)
{
for (int x = 0; x < image.cols; x++)
{
image.at<cv::Vec3b>(x, y) = cv::Vec3b(100, 100, 100);
}
}
clock_t atFinish = clock();
std::cout << "Time: " << (atFinish - atBegin)*1.0 / CLOCKS_PER_SEC << std::endl;
// By ptr
clock_t ptrBegin = clock();
for (int y = 0; y < image.rows; y++)
{
for (int x = 0; x < image.cols; x++)
{
image.ptr<cv::Vec3b>(y)[x]= cv::Vec3b(100, 100, 100);
}
}
clock_t ptrFinish = clock();
std::cout << "Time: " << (ptrFinish - ptrBegin)*1.0 / CLOCKS_PER_SEC << std::endl;
// By Iterator
clock_t iteratorBegin = clock();
cv::Mat_<cv::Vec3b>::iterator begin = image.begin<cv::Vec3b>();
cv::Mat_<cv::Vec3b>::iterator end = image.end<cv::Vec3b>();
for (; begin != end; begin++)
{
(*begin) = cv::Vec3b(100, 100, 100);
}
clock_t iteratorFinish = clock();
std::cout << "Time: " << (iteratorFinish - iteratorBegin)*1.0 / CLOCKS_PER_SEC << std::endl;
return 0;
}