DSO数据读取

一、程序运行

不考虑gamma校正,不考虑像素衰减,没有进行光度校正。可以使用下列方式运行dso。

./bin/dso_dataset \
files=~/cam0/data/  \
calib=~/cam0/camera.txt \
mode=1

二、读取图像

2.1 ImageFolderReader

从main函数开始,系统首先定义ImageFolderReader类的对象reader。在构造函数中完成文件路径读取操作。

ImageFolderReader* reader = new ImageFolderReader(source,calib, gammaCalib, vignette);

ImageFolderReader类的构造函数在DatasetReader.h文件,程序通过getdir()函数获取输入文件夹下的所有文件,也就是files下的所有文件。

inline int getdir (std::string dir, std::vector<std::string> &files){
    DIR *dp;
    struct dirent *dirp;
    if((dp  = opendir(dir.c_str())) == NULL)    {
        return -1;
    }
    while ((dirp = readdir(dp)) != NULL) {
    	std::string name = std::string(dirp->d_name);
    	if(name != "." && name != "..")
    		files.push_back(name);
    }
    closedir(dp);
    std::sort(files.begin(), files.end());
    if(dir.at( dir.length() - 1 ) != '/') dir = dir+"/";
	for(unsigned int i=0;i<files.size();i++)	{
		if(files[i].at(0) != '/')
			files[i] = dir + files[i];
	}
    return files.size();
}

getdir()是非常常用的从文件夹读取文件的函数,输入文件夹路径到dir,输出文件夹下所有文件路径到files。
函数先将文件夹的所有文件排序,std::sort()默认按升序排序,也可以用lambda表达式自定义排序方式。

std::sort(files.begin(), files.end(), [](int a, int b) { 
	return a < b; //降序排列写法,升序用>
	});

然后把每个文件的路径按顺序存入reader对象的成员变量中的vector容器,方便读取。
loadTimestamps()函数会读取图像文件夹父文件夹下(cam0)的时间戳time.txt文件,建议相机内参camera.txt文件也放到这个文件夹下。

2.2 getImage

在main函数中,新建一个线程,把lambda表达式放到线程中运行

std::thread runthread([&](){......})//[&]表示用引用传递的方式表示lambda表达式以外的变量

在线程中执行getImage函数,ImageFolderReader中的成员函数

for(int ii=0;ii<(int)idsToPlay.size(); ii++){
	if(!fullSystem->initialized){
		gettimeofday(&tv_start, NULL);
		started = clock();
		sInitializerOffset = timesToPlayAt[ii];
    }
	......
	img = reader->getImage(i);
	......
	if(ii < 250 || setting_fullResetRequested){
	}
}

在这里要控制系统从某一帧开始往后读取图像,相当于完成rosbag play -s ii0 xxx.bag的操作。可以在运行程序的命令里加上
start=a,end=b。

在DatasetReader.h文件中,getImage函数调用成员函数getImage_internal(),然后函数里调用getImageRaw_internal(),最终调用IOWrap/ImageRW_OpenCV.cpp中的IOWrap::readImageBW_8U(files[id])函数。
在这时程序才开始执行图像读取操作。

MinimalImageB* readImageBW_8U(std::string filename){
	cv::Mat m = cv::imread(filename, CV_LOAD_IMAGE_GRAYSCALE);
	/**
	*在这里可以对图像进行各种操作
	*/
	if(m.rows*m.cols==0)	{
		printf("cv::imread could not read image %s! this may segfault. \n", filename.c_str());
		return 0;
	}
	if(m.type() != CV_8U)	{
		printf("cv::imread did something strange! this may segfault. \n");
		return 0;
	}
	MinimalImageB* img = new MinimalImageB(m.cols, m.rows);
	memcpy(img->data, m.data, m.rows*m.cols);
	return img;
}

了解到这里之后,就可以对图像进行各种预处理操作。
比如说要进行直方图均衡化,就只需要添加头文件#include <opencv2/opencv.hpp>和

cv::Ptr<cv::CLAHE> clahe = cv::createCLAHE(3.0, cv::Size(8, 8));
clahe->apply(m, m);

需要注意的是,这里不能直接用rect剪切图像区域,图像可能错位。

m = m(cv::Rect(x,y, col, row));

一定要修剪图像,需要添加

cv::resize(m, m, cv::Size(col0, row0));

恢复图像原尺寸。

三、读取参数

这一步是紧跟在getdir之后,也就是在定义reader对象时ImageFolderReader的构造函数里。

undistort = Undistort::getUndistorterForFile(calibFile, gammaFile, vignetteFile);

函数首先读取calibFile里第一行,判断相机模型。
当参数文件image.txt中没有给定相机模型时,可能有几种情况

(Pinhole )fx fy cx cy 0
(FOV )		fx fy cx cy omega
(RadTan )fx fy cx cy k1 k2 r1 r2

对应不同的类,这些相机模型类继承自同一个类Undistort。然后函数利用calibFile开辟对应的相机模型空间。
在定义相机模型同时,调用对应的构造函数,然后程序会调用readFromFile。

void Undistort::readFromFile(const char* configFileName, int nPars, std::string prefix){
	//这里是tadtan对应的参数读取过程
	snprintf(buf, 1000, "%s%%lf %%lf %%lf %%lf %%lf %%lf %%lf %%lf %%lf %%lf", prefix.c_str());
	if(std::sscanf(l1.c_str(), buf,
				&parsOrg[0], &parsOrg[1], &parsOrg[2], &parsOrg[3], &parsOrg[4],
				&parsOrg[5], &parsOrg[6], &parsOrg[7]) == 8 &&
				std::sscanf(l2.c_str(), "%d %d", &wOrg, &hOrg) == 2){
		}
}
int snprintf(char *str, size_t size, const char *format, ...);

这里的snprintf是将format复制到str中,并给其后添加一个字符串结束符(‘\0’),和strcpy很类似,或许可以替代。

char* strcpy(char* strDestination, const char* strSource);

std::sscanf的解析可以参考资料std::sscanf

int sscanf( const char* buffer, const char* format, ... );
//Reads the data from null-terminated character string buffer
//从以空结束的字符串缓冲区读取数据

sscanf是从字符串读取数据,C++可以使用字符串流来实现数据读取。

void Undistort::readFromFile(string configFileName, int nPars, std::string prefix){
	std::ifstream paramK;
	paramK.open(configFileName.c_str(), std::ios::in);//只读
	if(!paramK.is_open()){
		cout << "open file failed" << endl;
		return;
	}
	//while(!paramK.eof()){
		paramK>>parsOrg[0]>>parsOrg[1]>>parsOrg[2]>>parsOrg[3]>>parsOrg[4]
			>>parsOrg[5]>>parsOrg[6]>>parsOrg[7];
	//}
	paramK.close();
}

此时,程序将相机内参读入,保存到parsOrg,经过畸变等操作后存到Undistort类中的成员变量K。
在运行ImageFolderReader的构造函数之后,也就是程序获取所有图像路径,并且读入了内参之后,程序调用

reader->setGlobalCalibration();

在函数中调用globalCalib.cpp中的setGlobalCalib()函数,将Undistort类中的内参保存到全局变量KG。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值