前言
系统:ubuntu18.04(windows系统也适用),语言:c++
利用opencv(sgbm、bm函数)实现对多组双目图片输出深度估计图(三角视差测距法)。
1.文件结构
本来用的cmake,但是不知什么原因一直出错,链接不到opencv库,无奈只好改用命令行参数编译方法,文件结构因此也较为简单(一般结构需要包含lib、src、include、bin、build、data、CMakeLists.txt等)。
data文件夹;存放双目数据和输出结果
main.cpp:程序源码
parameters.txt:配置文件
data文件夹下:
color:存放深度彩色图(方便查看)
depth:存放输出的深度图
disp:存放sgbm和bm函数输出的水平视差图(单位为像素)
left:存放双目数据左视图
right:存放双目数据右视图
2.配置文件
先来说下配置文件里的一些参数,方便大家对后面源码的理解。
#camera
camera.fx=718.856
camera.fy=718.856
camera.cx=607.1928
camera.cy=185.2157
camera.baseline=537.165719
camera.scale=10
#file
rgb_extension=.png
left_dir=./data/left/
right_dir=./data/right/
depth_dir=./data/depth/
color_dir=./data/color/
disp_dir=./data/disp/
#other
start_index=0
end_index=50
is_color=yes
algorithm=SGBM
#algorithm=BM
#camera:相机内参,其实只需要fx(相机焦距,双目相机一般fx与fy相等)、baseline(双目基线)和scale(深度图缩放因子)。这里要注意下,内参需要毫米为单位。(这里我使用的TUM数据集,因此双目基线比较长,建议大家还是用室内数据集)
#file:输入输出数据的目录名以及文件名后缀。
#other:起始和截止双目数据序列,is_color设置是否需要输出彩色深度图,algorithm设置所用的视差算法。
3.源码
相关部分已经在注释里做了介绍(因为用的单文件结构,所以代码有点冗长,大家可自行优化),有什么问题可以评论区留言。
#include <iostream>
#include <fstream>
#include <map>
#include <vector>
#include <cmath>
#include <opencv2/highgui.hpp>
#include <opencv2/calib3d.hpp>
#include <opencv2/imgproc.hpp>
using namespace std;
//****这里设置三种颜色来让程序运行的更醒目****
#define WHITE "\033[37m"
#define BOLDRED "\033[1m\033[31m"
#define BOLDGREEN "\033[1m\033[32m"
//****相机内参****
struct CAMERA_INTRINSIC_PARAMETERS
{
double cx,cy,fx,fy,baseline,scale;
};
struct FILE_FORM
{
cv::Mat left,right;//存放左右视图数据
string dispname,depthname,colorname;//存放三种输出数据的文件名
};
//****读取配置文件****
class ParameterReader
{
public:
ParameterReader(string filename = "./parameters.txt")//配置文件目录
{
ifstream fin(filename.c_str());
if(!fin)
{
cerr<<BOLDRED"can't find parameters file!"<<endl;
return;
}
while(!fin.eof())
{
string str;
getline(fin,str);
if(str[0] == '#')//遇到’#‘视为注释
{
continue;
}
int pos = str.find("=");//遇到’=‘将其左右值分别赋给key和alue
if (pos == -1)
{
continue;
}
string key = str.substr(0,pos);
string value = str.substr(pos+1,str.length());
data[key] = value;
if (!fin.good())
{
break;
}
}
}
string getData(string key)//获取配置文件参数值
{
map<string,string>::iterator iter = data.find(key);
if (iter == data.end())
{
cerr<<BOLDRED"can't find:"<<key<<" parameters!"<<endl