从运动中恢复结构以便能更好的通过摄像机移动来提取图像几何结构。在书中为了使用单目相机,一个离散且稀疏的视频帧集合,而不是连续的视频流。这在后面两两循环组合配对提供了方便性。
主要内容:
1:从两幅图像估计摄像机的运动姿态。
2:重构场景
3:从视图中重构
4:重构细化
5:可视化三维点云
I:假定使用一个标定过的摄像机——一个先前标定过的摄像机。前面的博客也提到如何进行相机标定。因此,我们假定摄像机内参数存在,并且具体化到K矩阵中,K矩阵为摄像机标定过程的一个结果输出。
在程序中初始化相机标定内参数:
//load calibration matrix
cv::FileStorage fs;
if(fs.open(imgs_path_+ "\\out_camera_data.yml",cv::FileStorage::READ)) //打开校正参数文件
{
fs["camera_matrix"]>>cam_matrix;
fs["distortion_coefficients"]>>distortion_coeff;
} else {
//若没有标定文件,就组合一个标定内参数
cv::Size imgs_size = imgs_[0].size();
double max_w_h = MAX(imgs_size.height,imgs_size.width);
cam_matrix = (cv::Mat_<double>(3,3) << max_w_h , 0 , imgs_size.width/2.0,
0, max_w_h, imgs_size.height/2.0,
0, 0, 1);
distortion_coeff = cv::Mat_<double>::zeros(1,4);
}
K = cam_matrix;
cv::invert(K, Kinv); //对内参数进行取反
distortion_coeff.convertTo(distcoeff_32f,CV_32FC1);
K.convertTo(K_32f,CV_32FC1);
若有标定文件,就从文件中导入,若没有标定文件,就组合一个相机内参K,根据图像大小就可以组合,畸变参数设为0,对相机内参取反得Kinv,转换成32FC1精度。
II:获取图像
书中在获取图像时,采用给定目录,逐个读取目录中的图像,保存在一个std::vector& imgs中。我们也可以挨个读取,或者截取视频帧。
我觉得这是一个常规代码片,放在下面供以后随便调用。
//给定目录的路径,读取目录下图像文件,保存图片名,设置图像缩放比率
void open_imgs_dir(char* dir_name, std::vector<cv::Mat>& images, std::vector<std::string>& images_names, double downscale_factor) {
if (dir_name == NULL) {
return;
}
string dir_name_ = string(dir_name);
vector<string> files_;
#ifndef WIN32
//open a directory the POSIX way
//linux或者macos下面读取图片,需要包含#include <dirent.h>
DIR *dp;
struct dirent *ep;
dp = opendir (dir_name);
if (dp != NULL)
{
while (ep = readdir (dp)) {
if (ep->d_name[0] != '.')
files_.push_back(ep->d_name);
}
(void) closedir (dp);
}
else {
cerr << ("Couldn't open the directory");
return;
}
#else
//open a directory the WIN32 way
HANDLE hFind = INVALID_HANDLE_VALUE;
WIN32_FIND_DATA fdata;
if(dir_name_[dir_name_.size()-1] == '\\' || dir_name_[dir_name_.size()-1] == '/') {
dir_name_ = dir_name_.substr(0,dir_name_.size()-1);
}
hFind = FindFirstFile(string(dir_name_).append("\\*").c_str(), &fdata);
if (hFind != INVALID_HANDLE_VALUE)
{
do
{
if (strcmp(fdata.cFileName, ".") != 0 &&
strcmp(fdata.cFileName, "..") != 0)
{
if (fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
continue; // a diretory
}
else
{
files_.push_back(fdata.cFileName);
}
}
}
while (FindNextFile(hFind, &fdata) != 0);
} else {
cerr << "can't open directory\n";
return;
}
if (GetLastError() != ERROR_NO_MORE_FILES)
{
FindClose(hFind);
cerr << "some other error with opening directory: " << GetLastError() << endl;
return;
}
FindClose(hFind);
hFind = INVALID_HANDLE_VALUE;
#endif
for (unsigned int i=0; i<files_.size(); i++) {
if (files_[i][0] == '.' || !(hasEndingLower(files_[i],"jpg")||hasEndingLower(files_[i],"png"))) {
continue;
}
cv::Mat m_ = cv::imread(string(dir_name_).append("/