OpenMVG (open Multiple View Geometry):开源多视角立体几何库,这是一个cv届处理多视角立体几何的著名开源库,信奉“简单,可维护”,提供了一套强大的接口,每一个模块都被测试过,尽力提供一致可靠的体验。git
openMVG可以:数据结构
解决多视角立体几何的精准匹配问题;框架
提供一系列SfM须要用到的特征提取和匹配方法;iview
完整的SfM工具链(校订,参估,重建,表面处理等);ide
openMVG尽力提供可读性性强的代码,方便开发者二次开发,核心功能是尽可能精简的,因此你可能须要其它库来完善你的系统。openMVG分红了几个大的模块:函数
核心库:各个功能的核心算法实现;工具
样例:教你怎么用;post
工具链:也就是连起来用咯(乱序图像集的特征匹配,SfM,处理色彩和纹理);
第一步固然是从github clone代码,而后按照 BUILD 说明操做,须要注意的是:
建议和opencv一块儿编译,方法是在CMakeLists.txt
文件中修改相应选项为 ON,而后在cmake的GUI中添加一个叫OpenCV_DIR
的入口,值就是你已经安装好的opencv的路径。
openMVG写的很是不错,对Windows也提供了良好的支持,因此cmake以后用VS打开生成的openMVG.sln
解决方案就能够进行编译了,编译的时间稍久。我用的VS2013不支持C++新特性:constexpr
,因此建议你使用VS2015或更新版本,若是必定要用VS2013,能够这样作:在src/openMVG/cameras/Camera_Common.hpp
文件中将有constexpr
的地方直接去掉,或者改为模板函数也是能够的:
template <class T> inline T operator|(T x, T y){ return static_cast<T>(static_cast<int>(x) | static_cast<int>(y)); };
运行样例,这里遇到一个坑:DenseStoraage.h line 86
报错:R6010 Assertion failed
,这是一个断言错误,在release模式下不会出现,但在debug模式下几乎是必现。缘由嘛,打开Eigen给出的网址能够明确:数据结构未对齐(unaligned arrays)。这个问题对于刚接触openMVG的人来讲仍是很烦人的,openMVG代码很优雅,不少数据类型都是从模板类或函数延伸,经过虚函数扩展各项具体方法,并且很是强烈的依赖Eigen这个库,因此给定位问题带来了阻碍。通过一天的攻坚,最后大概确认了缘由:
regions.h
这个文件中定义的Regions
类包含了fixed-size vectorizable Eigen types的stl容器vector,按照Eigen提供的解决方法,须要作的是:
//原来 typedef std::vector<FeatureT> FeatsT; //改为 typedef std::vector<FeatureT, Eigen::aligned_allocator<FeatureT>> FeatsT; //其它相似的地方都要改,包括返回vector的函数,最好也加上 EIGEN_MAKE_ALIGNED_OPERATOR_NEW
openMVG提供一个基本的类用做图像容器:Image<T>
,T表明像素类型,这个类能够处理灰度,RGB,RGBA或者自定义类型的图像。用法很简单:
// A 8-bit gray image: Image<unsigned char> grayscale_image_8bit; // Multichannel image: (use pre-defined pixel type) // A 8-bit RGB image: Image<RGBColor> rgb_image_8bit; // 8-bit RGBA image Image<RGBAColor> rgba_image_8bit; Image<Rgba<unsigned char> > rgba_image2_8bit;
这里的 RGBColor
,RGBAColor
等是openMVG基于Eigen定义好的类型,具体是定义在pixel_types.hpp
中。
openMVG支持ppm/pgm
,jpeg
,png
,tiff
格式的图片文件,例子:
Image<RGBColor> rgb_image_gray; bool bRet = ReadImage("Foo.imgExtension", &rgb_image);
用于在图像上画圆,椭圆,直线等。
openMVG从新包装了Eigen的基本类型和算法,以便更简单的调用。好比 Vec2
表明一个二维点(char型)。
这个模块主要是提供特征容器的封装,包括特征,特征描述,关键点集等,基本都是模板类,好比顶一个sift特征描述子能够这样作:
// SIFT like descriptor typedef Descriptor<float, 128> siftDescriptorData;
此模块提供不一样的相机模型的抽象类,包括:
最简单的相机模型,如图:
相机模型包括内参和外参,关键词也就是你们熟悉的几样:投影矩阵,旋转、平移矩阵,焦距、主点等,具体参见说明。
看一个例子:openMVG提供的PinholeCamera
类:
/// Pinhole camera P = K[R|t], t = -RC struct PinholeCamera { //构造函数 PinholeCamera( const Mat3 & K = Mat3::Identity(), const Mat3 & R = Mat3::Identity(), const Vec3 & t = Vec3::Zero()) : _K(K), _R(R), _t(t) { _C = -R.transpose() * t; P_From_KRt(_K, _R, _t, &_P); } PinholeCamera(const Mat34 & P) { _P = P; KRt_From_P(_P, &_K, &_R, &_t); _C = -_R.transpose() * _t; } /// Projection matrix P = K[R|t] Mat34 _P; /// Intrinsic parameter (Focal, principal point) Mat3 _K; /// Extrinsic Rotation Mat3 _R; /// Extrinsic translation Vec3 _t; /// Camera center Vec3 _C; };
这部分是比较基础和重要的模块之一,包括了:
多视角集几何中n(>=2)视角的求解算法;
将这些求解算法综合起来以便进行鲁棒估计的通用框架——Kernel;
文档中讲解了单应矩阵,本征矩阵,本质矩阵,位置矩阵等的概念,讲得很是好,建议仔细阅读文档。
简单的解释一下:
单应矩阵:描述两个投影平面之间的关系;
本征矩阵:同一个场景在两个相机成像下的关系,也就是物体上的点A在两个视角下成像位置的关系;
本质矩阵:基于本征矩阵和内参矩阵创建,描述相机和本征矩阵位置之间的相对关系;
位置矩阵:估计相机的绝对位置(被转化为一个最小化问题求解);
Kernel:一个将求解器、数据、度量方案等结合起来的类,这个类将用于鲁棒的估计以上的参数和矩阵;
一个用于求解多视角几何中线性优化(参数估计)的工具集,文档。
提供一些列鲁棒估计方法,好比:Max-Consensus,Max-Consensus,AC-Ransac A Contrario Ransac等。
提供的接口包括:NNS,K-NN,FLANN,KVLD,Cascade hashing Nearest Neighbor等。这些接口可用于在二维或三维点集,以及更高维的特征描述集中。
多视几何里的追踪是指在一系列的图片中找到对应的特征点(同一点在不一样视角下的位置)。
openMVG提供的sfm模块包含了处理SfM问题的一系列方法个数据存储接口,例如相机位置估计,结构测量,BA等。SfM_Data
类包含了SfM全部的输入:
struct SfM_Data { /// Considered views Views views; // 包含图像文件名,id_view,id_pose,id_intrinsic,image size。 /// Considered poses (indexed by view.id_pose) Poses poses; // 相机的三维位置 /// Considered camera intrinsics (indexed by view.id_cam) Intrinsics intrinsics; // 相机内参 /// Structure (3D points with their 2D observations) Landmarks structure; // 二维视图特征关联的3D点 }
个人codepen连接:codepen