openmvg中cmd模块解析
---恢复内容开始---
在openmvg库中,定义了一个CmdLine类来定义例程的输入参数格式。源文件为.\openMVG\src\third_party\cmdLine\cmdLine.h。
先举个例子来说明一般输入参数格式,选用.\openMVG\src\software\SfM\main_SfMInit_ImageListing.cpp作为例程,对应的可执行文件为openMVG_main_SfMInit_ImageListing,在官网上(https://openmvg.readthedocs.io/en/latest/software/SfM/SfM/#)有该例程用法的介绍:

// Example(3种参数输入方式)
$openMVG_main_SfMInit_ImageListing --imageDirectory images --sensorWidthDatabase images/sensor_width_camera_database.txt --outputDirectory matches $openMVG_main_SfMInit_ImageListing -i images -d images/sensor_width_camera_database.txt -o matches $openMVG_main_SfMInit_ImageListing --imageDirectory=images --sensorWidthDatabase=images/sensor_width_camera_database.txt --outputDirectory=matches
其中第一种“--”后面接着的是长名标识符(longName如imageDirectory),images为对应参数
第二种“-”后面是短标识符(c如i,d,o等)
下面来分析与这3种输入参数格式相关的源代码。
我们先来看其中的一个类Option,它用于存储参数标识符(上面的-d,-i,-o等)与对应的长标识名(imageDirectory等),比如某个Option类种存储着-d和sensorWidthDatabase ,另一个Option类存储着-i和imageDirectory 。类的定义如下:
/// 类中包含3个数据成员,该类为父类,有两个子类(后面介绍)
class Option {
public:
char c; ///短标识符:i,d,o等
bool used; ///用于说明该参数是否已经被检测到,在解析输入参数时使用
std::string longName; /// 长名标识符:imageDirectory等 Option(char d, std::string name) //构造函数
: c(d), used(false), longName(name) {}
virtual ~Option() = default;
virtual bool check(int& argc, char* argv[]) = ; ///检查是否存在有对应的符合格式的参数存在,并解析,具体解析见子类
virtual Option* clone() const = ; ///< Copy
};
OptionField类,是Option的一个子类
template <class T>
class OptionField : public Option {
public:
//构造函数c,name分别对应父类Option种的c,longName;field对应参数比如例子中的输入参数images/sensor_width_camera_database.txt等
//因为输入参数类型不固定,可能是字符串也可能是数字,所以采用模板类
OptionField(char c, T& field, std::string name = "")
: Option(c, name), _field(field) {}
/// 查找正确的输入参数
bool check(int& argc, char* argv[]) override { //这里的argc,argv形参,并不与主程序中的argc,argv等同
std::string param; int arg = ;
if (std::string("-") + c == argv[] ||
(!longName.empty() && std::string("--") + longName == argv[])) { //对应输入参数格式为:-i ImageDataset_SceauxCastle/images
if (argc <= ) // 或:--imageDirectory ImageDataset_SceauxCastle/images
throw std::string("Option ")
+ argv[] + " requires argument";
param = argv[]; arg = ; //将ImageDataset_SceauxCastle/images赋值給param
}
else if (std::string(argv[]).find(std::string("-") + c) == ) { //对应输入参数格式为:-iImageDataset_SceauxCastle/images
param = argv[] + ; arg = ; //将ImageDataset_SceauxCastle/images赋值給param
}
else if (!longName.empty() && //对应输入参数格式为:--imageDirectory=ImageDataset_SceauxCastle/images
std::string(argv[]).find(std::string("--") + longName + '=') == ) {
size_t size = (std::string("--") + longName + '=').size();
param = std::string(argv[]).substr(size); arg = ; //将ImageDataset_SceauxCastle/images赋值給param
}
if (arg>) { //arg>0代表检查到了符合格式的输入参数
if (!read_param(param)) //读入检测到的参数,如果不成功,抛出异常
throw std::string("Unable to interpret ")
+ param + " as argument of " + argv[];
used = true; //该option对象对应的参数已经检测到
std::rotate(argv, argv + arg, argv + argc); //把从参数argv到argv + argc之间的参数序列看成一个圆,对他们进行旋转,旋转后的圆的第一个元素为argv + arg
//作用就是将检测到的参数放在输入参数序列后面
//rotate函数的用法详细介绍见:http://c.biancheng.net/view/609.html
/*
比如原始序列为:openMVG_main_SfMInit_ImageListing -i images -d images/sensor_width_camera_database.txt -o matches
假如argv对应-i argv + argc对应images/sensor_width_camera_database.txt arg=2
-i images -d images/sensor_width_camera_database.txt构成待旋转的圆,argv + arg对应的-d为旋转后圆的第一个元素
那么rotate后的新序列为openMVG_main_SfMInit_ImageListing -d images/sensor_width_camera_database.txt -i images -o matches
*/
argc -= arg;
return true;
}
return false;
}
/// 将读到的参数param赋值给_field;param为string型,_field类型在OptionField对象中预先定义了,见于make_option函数,也在cmdLine.h文件中
bool read_param(const std::string& param) {
std::stringstream str(param); char unused;
return !((str >> _field).fail() || !(str >> unused).fail());
}
/// Copy
Option* clone() const override {
return new OptionField<T>(c, _field, longName);
}
private:
T& _field;
};
另一个类OptionSwitch用的少,用于是否选用某种方法或者模式,比如:输入参数中如果有-u或者--use_sift参数,就使用sift方法,如果没有就不适用,只有是否两种情况;具体类定义就不做介绍了
Option类check用于匹配单个输入参数,CmdLine类实现所有的输入参数与所有的Option对象进行匹配
/// Command line parsing
class CmdLine {
std::vector<Option*> opts; //opts中包含所有的必须的或者可选的参数对应的标识符;即该程序需要输入哪些参数
public:
/// Destructor
~CmdLine() {
std::vector<Option*>::iterator it = opts.begin();
for (; it != opts.end(); ++it)
delete *it;
}
/// Add an option
void add(const Option& opt) { //在Option对象向量中添加Option对象
opts.push_back(opt.clone());
}
/// ************主要的成员函数************
/// 实现输入参数与程序需求的参数进行匹配
void process(int& argc, char* argv[]) {
std::vector<Option*>::iterator it = opts.begin();
for (; it != opts.end(); ++it)
(*it)->used = false;
for (int i = ; i<argc;) {
if (std::string("--") == argv[i]) { // "--" 为参数结尾标志,不知道这个有什么用
std::rotate(argv + i, argv + i + , argv + argc); //旋转,使"--"为序列结尾
--argc;
break;
}
bool found = false; // Find option
for (it = opts.begin(); it != opts.end(); ++it) { //将预先定义的Option类的各个对象分别与输入参数进行匹配
int n = argc - i;
found = (*it)->check(n, argv + i); //argv + i(argv[1])对应的参数与当前Option对象匹配
if (found) {
argc = n + i; //这行也不知道有什么用
break;
}
}
if (!found) { //如果没找到合适的匹配,但是输入的参数开头为"_",则抛出异常未识别标识符
if (std::string(argv[i]).size()> && argv[i][] == '-') {
std::istringstream str(argv[i]);
float v;
if (!(str >> v).eof())
throw std::string("Unrecognized option ") + argv[i];
}
++i;
}
}
}
/// Was the option used in last parsing?
bool used(char c) const {
std::vector<Option*>::const_iterator it = opts.begin();
for (; it != opts.end(); ++it)
if ((*it)->c == c)
return (*it)->used;
assert(false); // Called with non-existent option, probably a bug
return false;
}
};
在openmvg库中例程读入参数的主要流程如下:
#include"cmdLine.h"
#include <Eigen/Core>
//#include <Eigen/Dense>
//#include <Eigen/SparseCore>
//#include <Eigen/StdVector>
using namespace std;
using namespace Eigen; enum EINTRINSIC
{
PINHOLE_CAMERA_START = ,
PINHOLE_CAMERA, // No distortion
PINHOLE_CAMERA_RADIAL1, // radial distortion K1
PINHOLE_CAMERA_RADIAL3, // radial distortion K1,K2,K3
PINHOLE_CAMERA_BROWN, // radial distortion K1,K2,K3, tangential distortion T1,T2
PINHOLE_CAMERA_FISHEYE, // a simple Fish-eye distortion model with 4 distortion coefficients
PINHOLE_CAMERA_END,
CAMERA_SPHERICAL = PINHOLE_CAMERA_END +
}; using Vec3 = Eigen::Vector3d; inline bool split
(
const std::string & rhs,
const char delim,
std::vector<std::string> & items
)
{
items.clear();
std::stringstream ss(rhs);
std::string item;
while (std::getline(ss, item, delim))
{
items.emplace_back(item);
} // return true if the delimiter is present in the input string
return rhs.find(delim) != std::string::npos;
} /// Check that Kmatrix is a string like "f;0;ppx;0;f;ppy;0;0;1"
/// With f,ppx,ppy as valid numerical value
bool checkIntrinsicStringValidity(const std::string & Kmatrix, double & focal, double & ppx, double & ppy)
{
std::vector<std::string> vec_str;
split(Kmatrix, ';', vec_str);
if (vec_str.size() != ) {
std::cerr << "\n Missing ';' character" << std::endl;
return false;
}
// Check that all K matrix value are valid numbers
for (size_t i = ; i < vec_str.size(); ++i) {
double readvalue = 0.0;
std::stringstream ss;
ss.str(vec_str[i]);
if (!(ss >> readvalue)) {
std::cerr << "\n Used an invalid not a number character" << std::endl;
return false;
}
if (i == ) focal = readvalue;
if (i == ) ppx = readvalue;
if (i == ) ppy = readvalue;
}
return true;
} int main()
{
int argc = ;
char* argv[] = { "cmdline_study","-iimages", "-dsensor_width_camera_database.txt", "-ocmdline_study_outputdir", "-k2905.88; 0; 1416; \
; 2905.88; ; \
; ; " };
//1.定义一个CmdLine类
CmdLine cmd; std::string sImageDir, //2.定义输入参数对应数据类型,有的为string,有的为double等
sfileDatabase,
sOutputDir,
sKmatrix;
std::string sPriorWeights;
std::pair<bool, Vec3> prior_w_info(false, Vec3(1.0, 1.0, 1.0));
int i_User_camera_model = PINHOLE_CAMERA_RADIAL3;
bool b_Group_camera_model = true;
int i_GPS_XYZ_method = ;
double focal_pixels = -1.0;
//3.在CmdLine类中添加option对象(即需要输入的参数标识符)
cmd.add(make_option('i', sImageDir, "imageDirectory"));
cmd.add(make_option('d', sfileDatabase, "sensorWidthDatabase"));
cmd.add(make_option('o', sOutputDir, "outputDirectory"));
cmd.add(make_option('f', focal_pixels, "focal"));
cmd.add(make_option('k', sKmatrix, "intrinsics"));
cmd.add(make_option('c', i_User_camera_model, "camera_model"));
cmd.add(make_option('g', b_Group_camera_model, "group_camera_model"));
cmd.add(make_switch('P', "use_pose_prior"));
cmd.add(make_option('W', sPriorWeights, "prior_weights"));
cmd.add(make_option('m', i_GPS_XYZ_method, "gps_to_xyz_method"));
//4.进行输入参数与标识符匹配(CmdLine::process())
try {
if (argc == ) throw std::string("Invalid command line parameter.");
cmd.process(argc, argv);
}
catch (const std::string& s) {
std::cerr << "Usage: " << argv[] << '\n'
<< "[-i|--imageDirectory]\n"
<< "[-d|--sensorWidthDatabase]\n"
<< "[-o|--outputDirectory]\n"
<< "[-f|--focal] (pixels)\n"
<< "[-k|--intrinsics] Kmatrix: \"f;0;ppx;0;f;ppy;0;0;1\"\n"
<< "[-c|--camera_model] Camera model type:\n"
<< "\t" << static_cast<int>(PINHOLE_CAMERA) << ": Pinhole\n"
<< "\t" << static_cast<int>(PINHOLE_CAMERA_RADIAL1) << ": Pinhole radial 1\n"
<< "\t" << static_cast<int>(PINHOLE_CAMERA_RADIAL3) << ": Pinhole radial 3 (default)\n"
<< "\t" << static_cast<int>(PINHOLE_CAMERA_BROWN) << ": Pinhole brown 2\n"
<< "\t" << static_cast<int>(PINHOLE_CAMERA_FISHEYE) << ": Pinhole with a simple Fish-eye distortion\n"
<< "\t" << static_cast<int>(CAMERA_SPHERICAL) << ": Spherical camera\n"
<< "[-g|--group_camera_model]\n"
<< "\t 0-> each view have it's own camera intrinsic parameters,\n"
<< "\t 1-> (default) view can share some camera intrinsic parameters\n"
<< "\n"
<< "[-P|--use_pose_prior] Use pose prior if GPS EXIF pose is available"
<< "[-W|--prior_weights] \"x;y;z;\" of weights for each dimension of the prior (default: 1.0)\n"
<< "[-m|--gps_to_xyz_method] XZY Coordinate system:\n"
<< "\t 0: ECEF (default)\n"
<< "\t 1: UTM\n"
<< std::endl; std::cerr << s << std::endl;
return EXIT_FAILURE;
} system("pause");
return ;
}
openmvg中cmd模块解析的更多相关文章
- Python中pandas模块解析
Pandas基于两种数据类型: series 与 dataframe . 1.Series 一个series是一个一维的数据类型,其中每一个元素都有一个标签.类似于Numpy中元素带标签的数组.其中, ...
- Python中matplotlib模块解析
用Matplotlib绘制二维图像的最简单方法是: 1. 导入模块 导入matplotlib的子模块 import matplotlib.pyplot as plt import numpy as ...
- Python3 中 configparser 模块解析配置的用法详解
configparser 简介 configparser 是 Pyhton 标准库中用来解析配置文件的模块,并且内置方法和字典非常接近.Python2.x 中名为 ConfigParser,3.x 已 ...
- CCS中CMD文件解析
http://blog.csdn.net/u011392772/article/details/49760897 gel文件中主要包含了PLL.DDR等的初始化工作,具体可以看一下gel源码就明白了: ...
- Python中xlrd模块解析
xlrd 导入模块 import xlrd 2.打开指定的excel文件,返回一个data对象 data = xlrd.open_workbook(file) ...
- Python中csv模块解析
导入模块 import csv 2.读取csv文件 file1 = open('test1.csv', 'rb') reader = csv.reader(file1) rows = [row for ...
- TypeScript和Node模块解析策略
一般我们在模块化编码时,总会导入其它模块,通常我们使用如下语法: import { A } from './a'; // ES6语法 import { A } from 'a'; var A = re ...
- 浅析JS中的模块规范(CommonJS,AMD,CMD)////////////////////////zzzzzz
浅析JS中的模块规范(CommonJS,AMD,CMD) 如果你听过js模块化这个东西,那么你就应该听过或CommonJS或AMD甚至是CMD这些规范咯,我也听过,但之前也真的是听听而已. ...
- JS中的模块规范(CommonJS,AMD,CMD)
JS中的模块规范(CommonJS,AMD,CMD) 如果你听过js模块化这个东西,那么你就应该听过或CommonJS或AMD甚至是CMD这些规范咯,我也听过,但之前也真的是听听而已. 现在就看看吧, ...
随机推荐
- 【NOIP2014模拟8.25】设备塔
题目 为了封印辉之环,古代塞姆利亚大陆的人民在异空间中建造了一座设备塔. 简单的说,这座设备塔是一个漂浮在异空间中的圆柱体,圆柱体两头的圆是计算核心,而侧面则是 传输信息所用的数据通道,划分成N *m ...
- .NET面试题系列(二十)XX
遍历树.实现造成锁的代码.在线音乐网站 抽象工厂和工厂的区别 简单工厂 : 用来生产同一等级结构中的任意产品.(对于增加新的产品,无能为力) 工厂方法 :用来生产同一等级结构中的固定产品.(支持增加任 ...
- Markers
immune pdf(file = paste0(outdir,"T_B_NK_feature.pdf")) VlnPlot(expr_1_4,features = c(" ...
- vue 使用 axios 时 post 请求方法传参无法发送至后台
axios 时 post 请求方法传参无法发送至后台报错如下 Response to preflight request doesn't pass access control check: No ' ...
- Sql Server2008中自定义函数调用存储过程解决方案
1.开启sql server 2008远程连接 打开sql server配置管理器 配置SSCM,选中左侧的“SQL Server服务”,确保右侧的“SQL Server”以及“SQL Server ...
- [BZOJ3622]已经没有什么好害怕的了:DP+容斥原理
分析 说白了就是一道先DP再二项式反演的水题,然后被脑残博主把"多\(k\)组"看成了"糖果比药片能量大的组数恰好为\(k\)组",还改了各种奇怪的地方,最后看 ...
- 关于判断StringBuffer是否为空
对于String和StringBuffer来说,都是通过创建新的char value[]数组来达到字符串改变的操作的,只不过String是通过新创建String对象来达到目的, 而StringBuff ...
- python正则之特殊表达式 .*?{}
. 能匹配所有字符--单个字符,除了\n >>> re.match(r".","1") <_sre.SRE_Match object a ...
- DAY 1模拟赛
DAY1 杨溢鑫小姐姐出题 好毒瘤啊 T1 低仿机器人 (robo,1s,64M) 题目描述 自从 Dji 推出 robomaster S1 机器人过后,小文就一直缠着爸爸想要一个机器人.没想到爸爸最 ...
- JQuery插件 aos.js
简介: aos.js是一款效果超赞的页面滚动元素动画jQuery动画库插件.该动画库可以在页面滚动时提供28种不同的元素动画效果,以及多种easing效果.在页面往回滚动时,元素会恢复到原来的状态. ...