- 开始
- 完成openMVG的编译之后,在build/software/SfM/SfM_GlobalPipeline.py路径下有对应的编译好的文件,该文件里面包含了对应的sfm整个流程的命令执行的pyton程序。如下内容详细解释内含的每条命令。
-
执行
openMVG_main_SfMInit_ImageListing
-i input_dir
-o matches_dir
-d camera_file_params
-
如上命令的源文件是src/software/SfM/main_SfMInit_ImageListing.cpp
-
通过阅读源文件的代码有如下全部的输入参数 :
-
-i:是输入的图像的文件,要求是里面直接包含图像的文件,例如输入的images, 那么images里面是要求直接包含 *.png 或者 *.JPG 之类的图像的格式的文件,与colmap不同,colmap是可以对输入的文件夹进行递归遍历,然后找到文件夹内的所有的图像。
-
-o: 是输出的内容的路径,执行指令之后会输出一个包含图像信息的文件,文件会对图像进行编号,还有相机内参的信息。
-
-d: 是相机文件sensor_width_camera_database.txt,这个文件是SfM_GlobalPipeline.py文件里面可以找到对应的路径。但是我一般通过如下的方式去设定相机的参数。
-
-f: 输入的是一个相机的焦距,是一个浮点型的数据,也就是不区分fx和fy.
-
-k: 输入内参的矩阵,不过要求这个矩阵是一个字符串的形式输入,如"f;0;ppx;0;f;ppy;0;0;1";
-
-c: 输入的相机的模型,有如下几种相机的类型:
enum EINTRINSIC
{
PINHOLE_CAMERA_START = 0,
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 + 1
};
-
-
-g: 一个bool类型的数据, 用于判断是否是输入的相机组,如果是0那么设定每张图像都有对应的相机内参,如果是1设定所有图像共同一个相机内参。
-
-P:如果使用两这个符号位,那么就是说明使用EXIF中的GPS先验信息
-
-W:使用GPS先验信息的权重,如"x;y;z;", 默认三个方向的权重都是1.
-
-m: 设置GPS转换为xyz的方式,0是默认的ECEF的方式,1是UTM的方式。
- 重要信息
- 这个部分的代码涉及到图像初始化的内容,以及相机的内参,相机内参对于SFM来说很重要,轻则结果异常,重则重建失败。
- 此外,这里面还涉及到比较重要的部分是GPS的使用,以及对应的权重的信息设置
- 所有的重要的信息都保存到两sfm_data的文件中,可以保存为json的格式方便查看
- 代码学习
- sfm_data的数据结构
cpp
namespace openMVG {
namespace sfm {
/// Define a collection of IntrinsicParameter (indexed by View::id_intrinsic)
using Intrinsics = Hash_Map<IndexT, std::shared_ptr<cameras::IntrinsicBase>>;
/// Define a collection of Pose (indexed by View::id_pose)
using Poses = Hash_Map<IndexT, geometry::Pose3>;
/// Define a collection of View (indexed by View::id_view)
using Views = Hash_Map<IndexT, std::shared_ptr<View>>;
/// Generic SfM data container
/// Store structure and camera properties:
struct SfM_Data
{
/// Considered views
Views views;
/// Considered poses (indexed by view.id_pose)
Poses poses;
/// Considered camera intrinsics (indexed by view.id_intrinsic)
Intrinsics intrinsics;
/// Structure (3D points with their 2D observations)
Landmarks structure;
/// Controls points (stored as Landmarks (id_feat has no meaning here))
Landmarks control_points;
/// Root Views path
std::string s_root_path;
//--
// Accessors
//--
const Views & GetViews() const {return views;}
const Poses & GetPoses() const {return poses;}
const Intrinsics & GetIntrinsics() const {return intrinsics;}
const Landmarks & GetLandmarks() const {return structure;}
const Landmarks & GetControl_Points() const {return control_points;}
/// Check if the View have defined intrinsic and pose
bool IsPoseAndIntrinsicDefined(const View * view) const
{
if (!view) return false;
return (
view->id_intrinsic != UndefinedIndexT &&
view->id_pose != UndefinedIndexT &&
intrinsics.find(view->id_intrinsic) != intrinsics.end() &&
poses.find(view->id_pose) != poses.end());
}
/// Get the pose associated to a view
const geometry::Pose3 GetPoseOrDie(const View * view) const
{
return poses.at(view->id_pose);
}
};
} // namespace sfm
} // namespace openMVG
- lla转换为ecef
cpp
Vec3 lla_to_ecef
(
double lat,
double lon,
double alt
)
{
const double clat = cos( D2R(lat) );
const double slat = sin( D2R(lat) );
const double clon = cos( D2R(lon) );
const double slon = sin( D2R(lon) );
const double a2 = Square(WGS84_A);
const double b2 = Square(WGS84_B);
const double L = 1.0 / sqrt(a2 * Square(clat) + b2 * Square(slat));
const double x = (a2 * L + alt) * clat * clon;
const double y = (a2 * L + alt) * clat * slon;
const double z = (b2 * L + alt) * slat;
return Vec3(x, y, z);
}
- lla转换为utm
cpp
/**
** Convert WGS84 lon,lat,alt data to UTM data (Universal Transverse Mercator)
** @param lat Latitude in degree
** @param lon Longitude in degree
** @param alt Altitude relative to the WGS84 ellipsoid
** @return UTM corresponding coordinates
**/
Vec3 lla_to_utm
(
double lat,
double lon,
double alt,
double a = WGS84_A,
double b = WGS84_B
)
{
a /= 1000; // meters to kilometers
b /= 1000; // meters to kilometers
/// CONSTANTS
static const double N0_n = 0;
static const double N0_s = 1e4;
static const double E0 = 5e2;
static const double k0 = 0.9996;
const double f = (a - b) / a;
const double n = f / (2 - f);
const double n_2 = n * n;
const double n_3 = n_2 * n;
const double n_4 = n_3 * n;
const double n_5 = n_4 * n;
const double n_6 = n_5 * n;
const double n_7 = n_6 * n;
const double n_8 = n_7 * n;
const double n_9 = n_8 * n;
const double n_10 = n_9 * n;
const int lon_zone = 1 + floor((lon + 180) / 6);
const double lon_0 = D2R(3 + 6 * (lon_zone - 1) - 180);
lat = D2R(lat);
lon = D2R(lon);
const double A = a / (1 + n) * (1 + n_2/4 + n_4/64 + n_6/256 + n_8*25.0/16384.0 + n_10*49.0/65536.0);
const double a1 = (1.0/2.0)*n - (2.0/3.0)*n_2 + (5.0/16.0)*n_3 + (41.0/180.0)*n_4 - (127.0/288.0)*n_5 + (7891.0/37800.0)*n_6 + (72161.0/387072.0)*n_7 - (18975107.0/50803200.0)*n_8 + (60193001.0/290304000.0)*n_9 + (134592031.0/1026432000.0)*n_10;
const double a2 = (13.0/48.0)*n_2 - (3.0/5.0)*n_3 + (557.0/1440.0)*n_4 + (281.0/630.0)*n_5 - (1983433.0/1935360.0)*n_6 + (13769.0/28800.0)*n_7 + (148003883.0/174182400.0)*n_8 - (705286231.0/465696000.0)*n_9 + (1703267974087.0/3218890752000.0)*n_10;
const double a3 = (61.0/240.0)*n_3 - (103.0/140.0)*n_4 + (15061.0/26880.0)*n_5 + (167603.0/181440.0)*n_6 - (67102379.0/29030400.0)*n_7 + (79682431.0/79833600.0)*n_8 + (6304945039.0/2128896000.0)*n_9 - (6601904925257.0/1307674368000.0)*n_10;
const double a4 = (49561.0/161280.0)*n_4 - (179.0/168.0)*n_5 + (6601661.0/7257600.0)*n_6 + (97445.0/49896.0)*n_7 - (40176129013.0/7664025600.0)*n_8 + (138471097.0/66528000.0)*n_9 + (48087451385201.0/5230697472000.0)*n_10;
const double a5 = (34729.0/80640.0)*n_5 - (3418889.0/1995840.0)*n_6 + (14644087.0/9123840.0)*n_7 + (2605413599.0/622702080.0)*n_8 - (31015475399.0/2583060480.0)*n_9 + (5820486440369.0/1307674368000.0)*n_10;
const double a6 = (212378941.0/319334400.0)*n_6 - (30705481.0/10378368.0)*n_7 + (175214326799.0/58118860800.0)*n_8 + (870492877.0/96096000.0)*n_9 - (1328004581729009.0/47823519744000.0)*n_10;
const double a7 = (1522256789.0/1383782400.0)*n_7 - (16759934899.0/3113510400.0)*n_8 + (1315149374443.0/221405184000.0)*n_9 + (71809987837451.0/3629463552000.0)*n_10;
const double a8 = (1424729850961.0/743921418240.0)*n_8 - (256783708069.0/25204608000.0)*n_9 + (2468749292989891.0/203249958912000.0)*n_10;
const double a9 = (21091646195357.0/6080126976000.0)*n_9 - (67196182138355857.0/3379030566912000.0)*n_10;
const double a10 = (77911515623232821.0/12014330904576000.0)*n_10;
const double t = sinh(atanh(sin(lat)) - 2*sqrt(n)/(1+n) * atanh(2*sqrt(n)/(1+n)*sin(lat)));
const double xi = atan(t/cos(lon-lon_0));
const double eta = atanh(sin(lon-lon_0) / sqrt(1+t*t));
const double N0 = (lat > 0 ? N0_n : N0_s);
const double E = E0 + k0 * A * (eta + a1*cos(2*1*xi)*sinh(2*1*eta) + a2*cos(2*2*xi)*sinh(2*2*eta) + a3*cos(2*3*xi)*sinh(2*3*eta) + a4*cos(2*4*xi)*sinh(2*4*eta) + a5*cos(2*5*xi)*sinh(2*5*eta) + a6*cos(2*6*xi)*sinh(2*6*eta) + a7*cos(2*7*xi)*sinh(2*7*eta) + a8*cos(2*8*xi)*sinh(2*8*eta) + a9*cos(2*9*xi)*sinh(2*9*eta) + a10*cos(2*10*xi)*sinh(2*10*eta));
const double N = N0 + k0 * A * (xi + a1*sin(2*1*xi)*cosh(2*1*eta) + a2*sin(2*2*xi)*cosh(2*2*eta) + a3*sin(2*3*xi)*cosh(2*3*eta) + a4*sin(2*4*xi)*cosh(2*4*eta) + a5*sin(2*5*xi)*cosh(2*5*eta) + a6*sin(2*6*xi)*cosh(2*6*eta) + a7*sin(2*7*xi)*cosh(2*7*eta) + a8*sin(2*8*xi)*cosh(2*8*eta) + a9*sin(2*9*xi)*cosh(2*9*eta) + a10*sin(2*10*xi)*cosh(2*10*eta));
// Scale E,N from kilometers to meters
return Vec3(E * 1000, N * 1000, alt);
}