这个类实现了整个投影过程,对应书上10.2.1里面一直到图10-2
#ifndef PROJECTION_H
#define PROJECTION_H
#include "tools/rotation.h"
/**
* 这个头文件中只有一个内联函数:带畸变的相机投影
* inline bool CamProjectionWithDistortion(const T* camera, const T* point, T* predictions){}
* 整个这个函数就是P246页图10-2的代码实现。
*
* @tparam T 很明显要用模板类,以包含float和double这些类型,主要是这两种,int的还没见过
* @param camera 相机内外参,9维数组。0-2旋转向量、3-5平移向量、6-8相机内参(f,二阶径向畸变系数,四阶径向畸变系数)
* @param point 投影空间点
* @param predictions 投影得到的以图像中心为坐标原点下的像素坐标,取名为预测值,因为性质上这个坐标确是估计值。
* 这里注意一下,这里不是一般意义上像素坐标,一般意义下的像素坐标是以图像左上角为原点。最后面有一些体现~
* @return 整个投影过程成功的话,返回true。
*/
// camera : 9 dims array with
// [0-2] : angle-axis rotation
// [3-5] : translateion
// [6-8] : camera parameter, [6] focal length, [7-8] second and forth order radial distortion
// point : 3D location.
// predictions : 2D predictions with center of the image plane.
template<typename T>
inline bool CamProjectionWithDistortion(const T* camera, const T* point, T* predictions)
{
// Rodrigues' formula
//创建一个中间变量,这个p就是相机坐标系下的空间点的坐标。
T p[3];
//通过tool文件夹中的rotation.h中的AngleAxisRotatePoint()函数计算在相机仅旋转的情况下,新坐标系下的坐标。说白就是p=R*point。
//这里有个小现象点开此函数定义发现,它的第一个参数需要的是个三元素数组,而这里的camera数组是9元素的,也是能用的。对应只取到前三维。
//由数组名的本质可知为什么
AngleAxisRotatePoint(camera, point, p);//p=camrea(前三维)*point
// camera[3,4,5] are the translation
//旋转完之后,平移直接加上就好了。此时的p=R*point+t。即是相机坐标系下空间点的坐标了。也就是式10.36的p`
p[0] += camera[3]; p[1] += camera[4]; p[2] += camera[5];
//得到相机坐标系下空间点的坐标后,下面就是纯粹的相机本身的投影过程了,跟外部没有关系了。
// Compute the center fo distortion
//归一化坐标,也就是在求式10.37的Pc,这里的xp yp就是书上的uc vc。
//问题:这个负号是什么鬼?
T xp = -p[0]/p[2];
T yp = -p[1]/p[2];
// Apply second and fourth order radial distortion
// 这四步将二四阶畸变系数取出来,构造成一个畸变distortion。也就是式10.38中()中的东西
const T& l1 = camera[7];
const T& l2 = camera[8];
T r2 = xp*xp + yp*yp;
T distortion = T(1.0) + l1 * r2 + l2 * r2*r2;
//distortion*xp为式10.39中的Uc’和Vc‘,再乘上焦距f得到式10.39中的fx*Uc’和fx*Vc‘。
//注意,到此为止了,并没有算得整个式10.39中的Us和Vs。
//也就是predictions的坐标是以图像正中心为原点坐标系下的像素坐标。不是一般意义的以图像左上角为原点开始的坐标。
//再回头看整个函数,camera参数压根没有传进来Cx和Cy,所以也就无从算起了。也好搞,根据图像大小直接就能算出来一般意义下的像素坐标
//这里猜测一下为什么只到这里结束了,应该还是为了不同分辨率下图像程序通用性而考虑。
const T& focal = camera[6];
predictions[0] = focal * distortion * xp;//(xp,yp)为归一化坐标
predictions[1] = focal * distortion * yp;
return true;
}
#endif // projection.h
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
这个文件就是定义BA优化中用到的所有参数变量。并利用CommandArgs类进行变量管理。比如赋默认值等。
这里再啰嗦一遍,CommandArgs类只是一个变量(这里就是BA用到的所有参数了)管理类,真正的变量(这里就是参数集了)定义是在这个头文件中,也就是所有参数都定义在BundleParams这个结构体中。
其中有一些参数因为还没看BA的代码,所以没搞清楚,只是大概写了写,但是在这里不是重点,重点是,这个结构体中定义BA所需要的所有参数,不管干啥用的,肯定是个参数而已。
贴代码:
#ifndef BUNDLEPARAMS_H
#define BUNDLEPARAMS_H
#include <string>
#include "flags/command_args.h"
using namespace std;
/**
* 这个结构体定义了Bundle Adjustment使用所有参数。
* 说一下整体的结构和逻辑:
* 结构体名称非常直观,就是BA的参数,当然成员就是一堆参数了
* 那在最后用CommandArgs arg;这么一句,相当于创建了一个参数描述类,
* 结构成员定义完毕,开始构造函数。
* 构造函数中首先调用arg这个类中的.param()函数,这个函数有两个功能:
* 1、给上面定义的每一个参数后面挂一个结构体类型的描述,name、type等等描述
* 2、给这这些参数赋了一些值,也就是默认值了。
* 然后构造函数又调用了arg这个类中的.parseArgs()函数。这个函数功能就是检查一下命令行中有没有用户自定义的参数值,有的话读进来将默认值覆盖。
*/
struct BundleParams{
public:
//构造函数,在后面定义,这里只声明。
BundleParams(int argc, char** argv);
//析构函数
virtual ~BundleParams(){};
public:
//这里的一堆参数才是实打实的BA程序中要用的参数变量!!
//输入,那个文件被处理
string input;
//信赖域策略
string trust_region_strategy;
//线性求解器
string linear_solver;
//稀疏的线性代数求解器
string sparse_linear_algebra_library;
//稠密的线性代数求解器
string dense_linear_algebra_library;
//是否鲁棒??还没整明白
bool robustify; // loss function
// double eta;
//迭代次数
int num_iterations;
// for making noise
//噪声发生器
//随机种子
int random_seed;
//旋转sigma
double rotation_sigma;
//变换sigma
double translation_sigma;
//空间点sigma
double point_sigma;
// for point cloud file...
//原始点云
string initial_ply;
//优化后点云
string final_ply;
//此类在command_args.h中,用于解析用户输入的参数
//创建一个命令行参数类实例,通过下面的构造函数,对这个实例的成员进行赋值。
CommandArgs arg;
};
//构造函数定义,注意看,前面还是要加上类名称空间BundleParams::
//这里看见,直接处理的命令行,也就是main()中的第一句:BundleParams params(argc,argv),用命令行实例化一个BundleParams
BundleParams::BundleParams(int argc, char** argv)
{
/**
* 这一堆瞅着有点蛋疼和复杂。。。
* 慢慢看用法结构:.para()是个函数,下面用法有多种,参数列表也有很多种,明显是一个重载。
* 点开定义去看,.param()在CommandArgs类中。
* 从用法上看出来:(参数名称,参数,参数值,参数描述)
*/
//这个input就是要被BA的数据集。也就是要被处理的文件名。在这个程序里用的就是data文件夹下的problem-16-22106-pre.txt文件。
//发现默认值是空字符串,所以这种就是肯定要通过命令行输入进来值的参数。
arg.param("input", input, "", "file which will be processed");
arg.param("trust_region_strategy", trust_region_strategy, "levenberg_marquardt",
"Options are: levenberg_marquardt, dogleg.");
arg.param("linear_solver", linear_solver, "dense_schur", // iterative schur and cgnr(pcg) leave behind...
"Options are: sparse_schur, dense_schur");
// arg.param("sparse_linear_algebra_library", sparse_linear_algebra_library, "suite_sparse", "Options are: suite_sparse and cx_sparse.");
// arg.param("dense_linear_algebra_library", dense_linear_algebra_library, "eigen", "Options are: eigen and lapack.");
// arg.param("ordering",ordering,"automatic","Options are: automatic, user.");
arg.param("robustify", robustify, false, "Use a robust loss function");
// arg.param("num_threads",num_threads,1, "Number of threads.");
arg.param("num_iterations", num_iterations,20, "Number of iterations.");
arg.param("rotation_sigma", rotation_sigma, 0.0, "Standard deviation of camera rotation "
"perturbation.");
arg.param("translation_sigma", translation_sigma,0.0, "translation perturbation.");
arg.param("point_sigma",point_sigma,0.0,"Standard deviation of the point "
"perturbation.");
arg.param("random_seed", random_seed, 38401,"Random seed used to set the state ");
arg.param("initial_ply", initial_ply,"initial.ply","Export the BAL file data as a PLY file.");
arg.param("final_ply", final_ply, "final.ply", "Export the refined BAL file data as a PLY");
//解析命令行中的参数,看看有没有新值过来,有的话就覆盖。
arg.parseArgs(argc, argv);
}
#endif
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113