opencv 图像旋转后的匹配怎么做

代码: //OpenCV 图像任意角度旋转 //需要inter公司OpenCV支持. //OpenCV图像任意角度旋转 //待旋转图像IplImage Img_old /regions.h这个文件中定义的Regions类包含了fixed-size vectorizable Eigen types的stl容器vector,按照Eigen提供的解决方法,需要做的是:/返旋转图像 IplImage Img_tmp. //旋转角度,单位度. //三种同.其二没完全测试,满足部需要 //Vastsky - Nercita 二005 陆 一二 //vastsky_sun#一二陆 IplImage CCropMeasureView::FitRotate (IplImage Img_old, double angle,int mod) { IplImage Img_tmp = NULL; double anglerad = (CV_PI (angle/一吧0)) ; int newheight =int (fabs(( sin(anglerad)Img_old->width )) + fabs(( cos(anglerad)Img_old->height )) ); int newwidth =int (fabs(( sin(anglerad)Img_old->height)) + fabs(( cos(anglerad)Img_old->width)) ); Img_tmp = cvCreateImage(cvSize(newwidth,newheight), IPL_DEPTH_吧U, 三); cvFillImage(Img_tmp,0);//目图像 使用扩展 IplImage dst = cvCloneImage( Img_old );//目图像 与原图像等 float m[陆]; CvMat M = cvMat( 二, 三, CV_三二F, m ); if(一==mod) { // 提取象素四边形使用象素精度 int w = Img_old->width; int h = Img_old->height; m[0] = (float)(cos(angleCV_PI/一吧0.)); m[一] = (float)(sin(angleCV_PI/一吧0.)); m[二] = w0.5f; m[三] = -m[一]; m[四] = m[0]; m[5] = h0.5f; cvGetQuadrangleSubPix( Img_old, dst, &M, 一, cvScalarAll(0)); cvGetQuadrangleSubPix( Img_old, Img_tmp, &M, CV_INTER_LINEAR, cvScalarAll(0));//+CV_WARP_FILL_OUTLIERS // 提取象素四边形使用象素精度 } if(二==mod) { //二 使用 二维旋转仿射变换矩阵 存问题 要求输入输图像 旋转 CvPoint二D三二f center; center.x=float (Img_old->width/二.0+0.5);//float (Img_tmp->width/二.0+0.5); center.y=float (Img_old->height/二.0+0.5);//float (Img_tmp->height/二.0+0.5); cv二DRotationMatrix( center, angle,一, &M); cvWarpAffine( Img_old, dst, &M,CV_INTER_LINEAR,cvScalarAll(0) );//图 //目标图像 //图像进Mat34 _P;行扩展 // 能定角度内 同象限同待 int dx=int((newwidth -Img_old->width )/二+0.5); int dy=int((newheight-Img_old->height)/二+0.5); uchar old_ptr,temp_ptr; for( int y=0 ; yheight; y++) //越界 { for (int x=0 ; x Img_old->width; x++) { old_ptr = &((uchar)(Img_old->imageData + Img_old->widthStepy))[(x)三]; temp_ptr = &((uchar)(Img_tmp->imageData + Img_tmp->widthStep(y+dy)))[(x+dx)三]; temp_ptr[0]=old_ptr[0]; //green temp_ptr[一]=old_ptr[一]; //blue temp_ptr[二]=old_ptr[二]; //Red } } center.x=float (Img_tmp->width/二.0+0.5); center.y=float (Img_tmp->height/二.0+0.5); cv二DRotationMatrix( center, angle,一, &M); IplImage temp = cvCloneImage( Img_tmp );//输图像 cvWarpAffine( Img_tmp, temp , &M,CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS,cvScalarAll(0) );//图 Img_tmp=cvCloneImage( temp ); //问题 //cvWarpAffine( Img_tmp, Img_tmp, &M,CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS,cvScalarAll(0) );//

opencv 仿射变换_opencv仿射变换函数opencv 仿射变换_opencv仿射变换函数


opencv 仿射变换_opencv仿射变换函数


OpenCV library中的cvWarpAffine参数详解是什么?

WarpAffinex0dx0a对图像做仿射变换x0dx0oid cvWarpAffine( const CvArr src, CvArr dst, const CvMat map_matrix,x0dx0a int flags=CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS,x0dx0a CvScalar fillval=cvScalarAll(0) );x0dx0asrcx0dx0a输入图像.x0dx0adstx0dx0a输出图像.x0dx0amap_matrixx0dx0a2×3 #1.7 鲁棒估计变换矩阵x0dx0aflagsx0dx0a插值方法和以下开关选项的组合:x0dx0aCV_WARP_FILL_OUTLIERS - 填充所有输出图像的象素。如果部分象素落在输入图像的边界外,那么它们的值设定为 fillval.x0dx0aCV_WARP_INVERSE_MAP - 指定 map_matrix 是输出图像到输入图像的反变换,因此可以直接用来做象素插值。否则, 函数从 map_matrix 得到反变换。x0dx0afillvalx0dx0a用来填充边界外面的值x0dx0ax0dx0a函数与 cvGetQuadrangleSubPix 类似,但是不完全相同。 cvWarpAffine 要求输入和输出图像具有同样的数据类型,有更大的资源开销(因此对小图像不太合适)而且输出图像的部分可以保留不变。而 cvGetQuadrangleSubPix 可以地从8位图像中提取四边形到浮点数缓存区中,具有比较小的系统开销,而且总是全部改变输出图像的内容。x0dx0a要变换稀疏矩阵,使用 cxcore 中的函数 cvTransform 。

openmVG库怎么用?

#2. features_affine_demo

OpenMVG (open Multiple View Geometry):开源多视角立体几何库,这是一个cv届处理多视角立体几何的开源库,信奉逗简单,可维护地,提供了一套强大的接口,每个模块都被测试过,尽力提供一致可靠的体验。

地址:github

文档:documents

openMVG能够:

解决多视角立体几何的精准匹配问题;

完整的SfM工具链(校正,参估,重建,表面处理等);

openMVG尽力提供可读性性强的代码,方便开发者二次开发,核心功能是尽量精简的,所以你可能需要其它库来完善你的系统。openMVG分成了几个大的模块:

核心库:各个功能的核心算法实现;

样例:教你怎么用;

工具链:也就是连起来用咯(乱序图像集的特征匹配,SfM,处理色彩和纹理);

#0. 安装(win10+VS2013)

步当然是从github clone代码,然后按照 BUILD 说明作,需要注意的是:

template inline T operator|(T x, T y){

return static_cast(static_cast(x) | static_cast(y));

};

建议和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的地方直接去掉,或者改成模板函数也是可以的:

运行样例,这里遇到一个坑:DenseStoraage.h line 86报错:R6010 Assertion failed,这是一个断言错误,在release模式下不会出现,但在debug模式下几乎是必现。原因嘛,打开Eigen给出的网址可以明确:数据结构未对齐(unaligned arrays)。这个问题对于刚接触openMVG的人来说还是很烦人的,openMVG代码很优雅,很多数据类型都是从模板类或函数延伸,通过虚函数扩展各项具体方法,而且非常强烈的依赖Eigen这个库,所以给定位问题带来了阻碍。经过一天的攻坚,大概确认了原因:

//原来

typedef std::vector FeatsT;

//改成

typedef std::vector> FeatsT;

//其它类似的地方都要改,包括返回vector的函数,也加上 EIGEN_MAKE_ALIGNED_OPERATOR_NEW

#1. 核心库

#1.1 图像

#Image Container

openMVG提供一个基本的类用作图像容器:Image,T代表像素类型,这个类可以处理灰度,RGB,RGBA或者自定义类型的图像。用法很简单:

// A 8-bit gray image:

Image grayscale_image_8bit;

// Multichannel image: (use pre-defined pixel type)

Image rgb_image_8bit;

// 8-bit RGBA image

Image rgba_image_8bit;

Image > rgba_image2_8bit;

这里的 RGBColor,RGBAColor等是openMVG基于Eigen定义好的类型,具体是定义在pixel_types.hpp中。

#Image I/O

openMVG支持ppm/pgm,jpeg,png,tiff格式的文件,例子:

Image rgb_image_gray;

bool bRet = ReadImage("Foo.imgExtension", &rgb_image);

#Drawing operations

用于在图像上画圆,椭圆,直线等。

#1.2 数值

openMVG重新包装了Eigen的基本类型和算法,以便更简单的调用。比如 Vec2代表一个二维点(char型)。

#1.3 特征

这个模块主要是提供特征容器的封装,包括特征,特征描述,关键点集等,基本都是模板类,比如顶一个sift特征描述子可以这样做:

// SIFT like descriptor

typedef Descriptor siftDescriptorData;

#1.4 相机

此模块提供不同的相机模型的抽象类,包括:

#小孔相机模型

/// 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.transe() t;

P_From_KRt(_K, _R, _t, &_P);

}PinholeCamera(const Mat34 & P)

{_P = P;

KRt_From_P(_P, &_K, &_R, &_t);

_C = -_R.transe() _t;

}/// Projection matrix P = K[R|t]

/// Intrinsic parameter (Focal, principal point)

Mat3 _K;

/// Extrinsic Rotation

/// Extrinsic translation

Vec3 _t;

/// Camera center

Vec3 _C;

};

这部分是比较基础和重要的模块之一,包括了:

多视角集几何中n(>=2)视角的求解算法;

将这些求解算法综合起来以便进行鲁棒估计的通用框架——Kernel;

文档中讲解了单应矩阵,本征矩阵,本质矩阵,位置矩阵等的概念,讲得非常好,建议仔细阅读文档。 简单的解释一下:

本征矩阵:同一个场景在两个相机成像下的关系,也就是物体上的点A在两个视角下成像位置的关系;

位置矩阵:估计相机的位置(被转化为一个最小化问题求解);

Kernel:一个将求解器、数据、度量方案等结合起来的类,这个类将用于鲁棒的估计以上的参数和矩阵;

#1.6 线性规划

一个用于求解多视角几何中线性优化(参数估计)的工具集,文档。

提供一些列鲁棒估计方法,比如:Max-Consensus,Max-Consensus,AC-Ransac A Contrario Ransac等。

#1.7 匹配

提供的接口包括:NNS,K-NN,FLANN,KVLD,Cascade hashing Nearest Neighbor等。这些接口可用于在二维或三维点集,以及更高维的特征描述集中。

#1.8

多视几何里的是指在一系列的中找到对应的特征点(同一点在不同视角下的位置)。

#1.9 sfm

openMVG提供的sfm模块包含了处理SfM问题的一系列方法个数据存储接口,例如相机位置估计,结构测量,BA等。 SfM_Data类包含了SfM所有的输入:

struct SfM_Data

{/// Considered views

Views views; // 包含图像文件名,id_// A 8-bit RGB image:view,id_e,id_intrinsic,image size。

Poses es; // 相机的三维位置

/// Considered camera intrinsics (indexed by view.id_cam)

Intrinsics intrinsics; // 相机内参

/// Structure (3D points with their 2D observations)

Landmarks structure; // 二维视图特征关联的3D点

}下面是例子:

#1. features_siftPutativeMatches

这个样例做了这么几件事(直接翻译):

分别提取两张图像的SIFT特征(使用非免费的vlsift)并形成特征描述;

根据特征描述子匹配两张图像上的特征点(BRUTE_FORCE_L2方法);

刚开始的时候会遇到Assertion failed断言错误,处理办法见上一篇文章。运行成功项目目录下会生成三个文件:00_images.jpg,01_features.jpg,02_siftMatches.svg。

这个例子是图像MSER(参考)和TBMR特征提取的样例,MSER(Maximally Stable Extremal Regions)极值稳定区域是一种对图像灰度具有仿射变换不变性,也许也是这个样例起名的原因。TBMR(tree-based Morse regions)这个算法不是特别了解,具体可以在google学术中搜索。

#3. features_image_matching

这个样例给出了利用Image_describer接口提取特征描述子,并匹配和显示结果的样例。示例中可以选择SIFT,AKAZE_MLDB或者AKAZE算法,AKAZE介绍可看这里,是一种比SIFT更稳定的特征检测算法。程序中关于解析输入参数的部分可以注释掉(如果你是用过VS2013 debug),直接修改sImage_describer_type这个值以测试。

#4. features_kvld_filter 和 features_repeatability

这两个也是关于特征提取和匹配的,kvld这个例子中由于之前更改了regions.h中的内容,所以有些函数接口也要做相应改变,具体也是在vector中增加对齐函数选项。

#5. multiview_robust_homography_guided 和 multiview_robust_fundamental_guided

这两个样例是估计单应矩阵和本征矩阵的,并且能够根据这些信息反过来确定匹配点。两个样例运行时间都很长(分辨率教大时),个在用另外的照片时还遇到报错,大概是在DoG时出错,具体也没有细究了·····

提取EXIF信息,编译后通过命令行执行,给出的参数格式:--imafile 你的照片路径,路径中使用/斜杠。

#7. multiview_robust_essential

估计本质矩阵并计算3D结构。这个例子可以直接运行,生成的点云十分稀疏且不带颜色信息。

怎么学习机器视觉

#6. exif_Parsing

可以从图像处理入手,先了解下图像处理最基本的作,比如的读取、显示,仿射变换,平滑、锐化、腐蚀膨胀等。看理论的同时多动手,可以用Matlab编程,也可以用C++搭配OpenCV。个人后者。当然两者都了解更好。这方面的书和网上很多人的博客都是不错的参考。有了一定基础之后后面该如何学习相信你就会有自己的想法了。而且有了这些基础之后就可以做很多有意思的事情了,如人脸识别,行人检测,字符识别等等。

展示匹配结果;

openMVG是用来做什么的?

Mat3 _R;

OpenMVG (open Multiple View Geometry):开源多视角立体几何库,这是一个cv届处理多视角立体几何的开源库,信奉逗简单,可维护地,提供了一套强大的接口,每个模块都被测试过,尽力提供一致可靠的体验。

地址:github

文档:documents

openMVG能够:

解决多视角立体几何的精准匹配问题;

完整的SfM工具链(校正,参估,重建,表面处理等);

openMVG尽力提供可读性性强的代码,方便开发者二次开发,核心功能是尽量精简的,所以你可能需要其它库来完善你的系统。openMVG分成了几个大的模块:

核心库:各个功能的核心算法实现;

样例:教你怎么用;

工具链:也就是连起来用咯(乱序图像集的特征匹配,SfM,处理色彩和纹理);

#0. 安装(win10+VS2013)

步当然是从github clone代码,然后按照 BUILD 说明作,需要注意的是:

template inline T operator|(T x, T y){

return static_cast(static_cast(x) | static_cast(y));

};

建议和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的地方直接去掉,或者改成模板函数也是可以的:

运行样例,这里遇到一个坑:DenseStoraage.h line 86报错:R6010 Assertion failed,这是一个断言错误,在release模式下不会出现,但在debug模式下几乎是必现。原因嘛,打开Eigen给出的网址可以明确:数据结构未对齐(unaligned arrays)。这个问题对于刚接触openMVG的人来说还是很烦人的,openMVG代码很优雅,很多数据类型都是从模板类或函数延伸,通过虚函数扩展各项具体方法,而且非常强烈的依赖Eigen这个库,所以给定位问题带来了阻碍。经过一天的攻坚,大概确认了原因:

//原来

typedef std::vector FeatsT;

//改成

typedef std::vector> FeatsT;

//其它类似的地方都要改,包括返回vector的函数,也加上 EIGEN_MAKE_ALIGNED_OPERATOR_NEW

#1. 核心库

#1.1 图像

#Image Container

openMVG提供一个基本的类用作图像容器:Image,T代表像素类型,这个类可以处理灰度,RGB,RGBA或者自定义类型的图像。用法很简单:

// A 8-bit gray image:

Image grayscale_image_8bit;

// Multichannel image: (use pre-defined pixel type)

Image rgb_image_8bit;

// 8-bit RGBA image

Image rgba_image_8bit;

Image > rgba_image2_8bit;

这里的 RGBColor,RGBAColor等是openMVG基于Eigen定义好的类型,具体是定义在pixel_types.hpp中。

#Image I/O

openMVG支持ppm/pgm,jpeg,png,tiff格式的文件,例子:

Image rgb_image_gray;

bool bRet = ReadImage("Foo.imgExtension", &rgb_image);

#Drawing operations

用于在图像上画圆,椭圆,直线等。

#1.2 数值

openMVG重新包装了Eigen的基本类型和算法,以便更简单的调用。比如 Vec2代表一个二维点(char型)。

#1.3 特征

这个模块主要是提供特征容器的封装,包括特征,特征描述,关键点集等,基本都是模板类,比如顶一个sift特征描述子可以这样做:

// SIFT like descriptor

typedef Descriptor siftDescriptorData;

#1.4 相机

此模块提供不同的相机模型的抽象类,包括:

#小孔相机模型

/// 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.transe() t;

P_From_KRt(_K, _R, _t, &_P);

}PinholeCamera(const Mat34 & P)

{_P = P;

KRt_From_P(_P, &_K, &_R, &_t);

_C = -_R.transe() _t;

}/// Projection matrix P = K[R|t]

/// Intrinsic parameter (Focal, principal point)

Mat3 _K;

/// Extrinsic Rotation

/// Extrinsic translat/// Considered es (indexed by view.id_e)ion

Vec3 _t;

/// Camera center

Vec3 _C;

};

这部分是比较基础和重要的模块之一,包括了:

多视角集几何中n(>=2)视角的求解算法;

将这些求解算法综合起来以便进行鲁棒估计的通用框架——Kernel;

文档中讲解了单应矩阵,本征矩阵,本质矩阵,位置矩阵等的概念,讲得非常好,建议仔细阅读文档。 简单的解释一下:

本征矩阵:同一个场景在两个相机成像下的关系,也就是物体上的点A在两个视角下成像位置的关系;

位置矩阵:估计相机的位置(被转化为一个最小化问题求解);

Kernel:一个将求解器、数据、度量方案等结合起来的类,这个类将用于鲁棒的估计以上的参数和矩阵;

#1.6 线性规划

一个用于求解多视角几何中线性优化(参数估计)的工具集,文档。

提供一些列鲁棒估计方法,比如:Max-Consensus,Max-Consensus,AC-Ransac A Contrario Ransac等。

#1.7 匹配

提供的接口包括:NNS,K-NN,FLANN,KVLD,Cascade hashing Nearest Neighbor等。这些接口可用于在二维或三维点集,以及更高维的特征描述集中。

#1.8

多视几何里的是指在一系列的中找到对应的特征点(同一点在不同视角下的位置)。

#1.9 sfm

openMVG提供的sfm模块包含了处理SfM问题的一系列方法个数据存储接口,例如相机位置估计,结构测量,BA等。 SfM_Data类包含了SfM所有的输入:

struct SfM_Data

{/// Considered views

Views views; // 包含图像文件名,id_view,id_e,id_intrinsic,image size。

Poses es; // 相机的三维位置

/// Considered camera intrinsics (indexed by view.id_cam)

Intrinsics intrinsics; // 相机内参

/// Structure (3D points with their 2D observations)

Landmarks structure; // 二维视图特征关联的3D点

}下面是例子:

#1. features_siftPutativeMatches

这个样例做了这么几件事(直接翻译):

分别提取两张图像的SIFT特征(使用非免费的vlsift)并形成特征描述;

根据特征描述子匹配两张图像上的特征点(BRUTE_FORCE_L2方法);

刚开始的时候会遇到Assertion failed断言错误,处理办法见上一篇文章。运行成功项目目录下会生成三个文件:00_images.jpg,01_features.jpg,02_siftMatches.svg。

这个例子是图像MSER(参考)和TBMR特征提取的样例,MSER(Maximally Stable Extremal Regions)极值稳定区域是一种对图像灰度具有仿射变换不变性,也许也是这个样例起名的原因。TBMR(tree-based Morse regions)这个算法不是特别了解,具体可以在google学术中搜索。

#3. features_image_matching

这个样例给出了利用Image_describer接口提取特征描述子,并匹配和显示结果的样例。示例中可以选择SIFT,AKAZE_MLDB或者AKAZE算法,AKAZE介绍可看这里,是一种比SIFT更稳定的特征检测算法。程序中关于解析输入参数的部分可以注释掉(如果你是用过VS2013 debug),直接修改sImage_describer_type这个值以测试。

#4. features_kvld_filter 和 features_repeatability

这两个也是关于特征提取和匹配的,kvld这个例子中由于之前更改了regions.h中的内容,所以有些函数接口也要做相应改变,具体也是在vector中增加对齐函数选项。

#5. multiview_robust_homography_guided 和 multiview_robust_fundamental_guided

这两个样例是估计单应矩阵和本征矩阵的,并且能够根据这些信息反过来确定匹配点。两个样例运行时间都很长(分辨率教大时),个在用另外的照片时还遇到报错,大概是在DoG时出错,具体也没有细究了·····

提取EXIF信息,编译后通过命令行执行,给出的参数格式:--imafile 你的照片路径,路径中使用/斜杠。

#7. multiview_robust_essential

估计本质矩阵并计算3D结构。这个例子可以直接运行,生成的点云十分稀疏且不带颜色信息。

C++怎么调用openMVG库

OpenMVG (open Multiple View Geometry):开源多视角立体几何库,这是一个cv届处理多视角立体几何的开源库,信奉逗简单,可维护地,提供了一套强大的接口,每个模块都被测试过,尽力提供一致可靠的体验。

地址:github

文档:documents

openMVG能够:

解决多视角立体几何的精准匹配问题;

完整的SfM工具链(校正,参估,重建,表面处理等);

openMVG尽力提供可读性性强的代码,方便开发者二次开发,核心功能是尽量精简的,所以你可能需要其它库来完善你的系统。openMVG分成了几个大的模块:

核心库:各个功能的核心算法实现;

样例:教你怎么用;

工具链:也就是连起来用咯(乱序图像集的特征匹配,SfM,处理色彩和纹理);

#0. 安装(win10+VS2013)

步当然是从github clone代码,然后按照 BUILD 说明作,需要注意的是:

template inline T operator|(T x, T y){

return static_cast(static_cast(x) | static_cast(y));

};

建议和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的地方直接去掉,或者改成模板函数也是可以的:

运行样例,这里遇到一个坑:DenseStoraage.h line 86报错:R6010 Assertion failed,这是一个断言错误,在release模式下不会出现,但在debug模式下几乎是必现。原因嘛,打开Eigen给出的网址可以明确:数据结构未对齐(unaligned arrays)。这个问题对于刚接触openMVG的人来说还是很烦人的,openMVG代码很优雅,很多数据类型都是从模板类或函数延伸,通过虚函数扩展各项具体方法,而且非常强烈的依赖Eigen这个库,所以给定位问题带来了阻碍。经过一天的攻坚,大概确认了原因:

//原来

typedef std::vector FeatsT;

//改成

typedef std::vector> FeatsT;

//其它类似的地方都要改,包括返回vector的函数,也加上 EIGEN_MAKE_ALIGNED_OPERATOR_NEW

#1. 核心库

#1.1 图像

#Image Container

openMVG提供一个基本的类用作图像容器:Image,T代表像素类型,这个类可以处理灰度,RGB,RGBA或者自定义类型的图像。用法很简单:

// A 8-bit gray image:

Image grayscale_image_8bit;

// Multichannel image: (use pre-defined pixel type)

Image rgb_image_8bit;

// 8-bit RGBA image

Image rgba_image_8bit;

Image > rgba_image2_8bit;

这里的 RGBColor,RGBAColor等是openMVG基于Eigen定义好的类型,具体是定义在pixel_types.hpp中。

#Image I/O

openMVG支持ppm/pgm,jpeg,png,tiff格式的文件,例本质矩阵:基于本征矩阵和内参矩阵建立,描述相机和本征矩阵位置之间的相对关系;子:

Image rgb_image_gray;

bool bRet = ReadImage("Foo.imgExtension", &rgb_image);

#Drawing operations

用于在图像上画圆,椭圆,直线等。

#1.2 数值

openMVG重新包装了Eigen的基本类型和算法,以便更简单的调用。比如 Vec2代表一个二维点(char型)。

#1.3 特征

这个模块主要是提供特征容器的封装,包括特征,特征描述,关键点集等,基本都是模板类,比如顶一个sift特征描述子可以这样做:

// SIFT like descriptor

typedef Descriptor siftDescriptorData;

#1.4 相机

此模块提供不同的相机模型的抽象类,包括:

#小孔相机模型

/// 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.transe() t;

P_From_KRt(_K, _R, _t, &_P);

}PinholeCamera(const Mat34 & P)

{_P = P;

KRt_From_P(_P, &_K, &_R, &_t);

_C = -_R.transe() _t;

}/// Projection matrix P = K[R|t]

/// Intrinsic parameter (Focal, principal point)

Mat3 _K;

/// Extrinsic Rotation

/// Extrinsic translation

Vec3 _t;

/// Camera center

Vec3 _C;

};

这部分是比较基础和重要的模块之一,包括了:

多视角集几何中n(>=2)视角的求解算法;

将这些求解算法综合起来以便进行鲁棒估计的通用框架——Kernel;

文档中讲解了单应矩阵,本征矩阵,本质矩阵,位置矩阵等的概念,讲得非常好,建议仔细阅读文档。 简单的解释一下:

本征矩阵:同一个场景在两个相机成像下的关系,也就是物体上的点A在两个视角下成像位置的关系;

位置矩阵:估计相机的位置(被转化为一个最小化问题求解);

Kernel:一个将求解器、数据、度量方案等结合起来的类,这个类将用于鲁棒的估计以上的参数和矩阵;

#1.6 线性规划

一个用于求解多视角几何中线性优化(参数估计)的工具集,文档。

提供一些列鲁棒估计方法,比如:Max-Consensus,Max-Consensus,AC-Ransac A Contrario Ransac等。

#1.7 匹配

提供的接口包括:NNS,K-NN,FLANN,KVLD,Cascade hashing Nearest Neighbor等。这些接口可用于在二维或三维点集,以及更高维的特征描述集中。

#1.8

多视几何里的是指在一系列的中找到对应的特征点(同一点在不同视角下的位置)。

#1.9 sfm

openMVG提供的sfm模块包含了处理SfM问题的一系列方法个数据存储接口,例如相机位置估计,结构测量,BA等。 SfM_Data类包含了SfM所有的输入:

struct SfM_Data

{/// Considered views

Views views; // 包含图像文件名,id_view,id_e,id_intrinsic,image size。

Poses es; // 相机的三维位置

/// Considered camera intrinsics (indexed by view.id_cam)

Intrinsics intrinsics; // 相机内参

/// Structure (3D points with their 2D observations)

Landmarks structure; // 二维视图特征关联的3D点

}下面是例子:

#1. features_siftPutativeMatches

这个样例做了这么几件事(直接翻译):

分别提取两张图像的SIFT特征(使用非免费的vlsift)并形成特征描述;

根据特征描述子匹配两张图像上的特征点(BRUTE_FORCE_L2方法);

刚开始的时候会遇到Assertion failed断言错误,处理办法见上一篇文章。运行成功项目目录下会生成三个文件:00_images.jpg,01_features.jpg,02_siftMatches.svg。

这个例子是图像MSER(参考)和TBMR特征提取的样例,MSER(Maximally Stable Extremal Regions)极值稳定区域是一种对图像灰度具有仿射变换不变性,也许也是这个样例起名的原因。TBMR(tree-based Morse regions)这个算法不是特别了解,具体可以在google学术中搜索。

#3. features_image_matching

这个样例给出了利用Image_describer接口提取特征描述子,并匹配和显示结果的样例。示例中可以选择SIFT,AKAZE_MLDB或者AKAZE算法,AKAZE介绍可看这里,是一种比SIFT更稳定的特征检测算法。程序中关于解析输入参数的部分可以注释掉(如果你是用过VS2013 debug),直接修改sImage_describer_type这个值以测试。

#4. features_kvld_filter 和 features_repeatability

这两个也是关于特征提取和匹配的,kvld这个例子中由于之前更改了regions.h中的内容,所以有些函数接口也要做相应改变,具体也是在vector中增加对齐函数选项。

#5. multiview_robust_homography_guided 和 multiview_robust_fundamental_guided

这两个样例是估计单应矩阵和本征矩阵的,并且能够根据这些信息反过来确定匹配点。两个样例运行时间都很长(分辨率教大时),个在用另外的照片时还遇到报错,大概是在DoG时出错,具体也没有细究了·····

提取EXIF信息,编译后通过命令行执行,给出的参数格式:--imafile 你的照片路径,路径中使用/斜杠。

#7. multiview_robust_essential

估计本质矩阵并计算3D结构。这个最简单的相机模型,如图: 相机模型包括内参和外参,也就是大家熟悉的几样:投影矩阵,旋转、平移矩阵,焦距、主点等,具体参见说明。 看一个例子:openMVG提供的PinholeCamera类:例子可以直接运行,生成的点云十分稀疏且不带颜色信息。

openmvG要怎么安装啊,有没有教程呀?

另一篇:learn openMVG-安装和

OpenMVG (open Multiple View Geometry):开源多视角立体几何库,这是一个cv届处理多视角立体几何的开源库,信奉逗简单,可维护地,提供了一套强大的接口,每个模块都被测试过,尽力提供一致可靠的体验。

#1.5 多视角几何

地址:github

文档:documents

openMVG能够:

解决多视角立体几何的精准匹配问题;

完整的SfM工具链(校正,参估,重建,表面处理等);

openMVG尽力提供可读性性强的代码,方便开发者二次开发,核心功能是尽量精简的,所以你可能需要其它库来完善你的系统。openMVG分成了几个大的模块:

核心库:各个功能的核心算法实现;

样例:教你怎么用;

工具链:也就是连起来用咯(乱序图像集的特征匹配,SfM,处理色彩和纹理);

#0. 安装(win10+VS2013)

步当然是从github clone代码,然后按照 BUILD 说明作,需要注意的是:

template inline T operator|(T x, T y){

return static_cast(static_cast(x) | static_cast(y));

};

建议和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的地方直接去掉,或者改成模板函数也是可以的:

运行样例,这里遇到一个坑:DenseStoraage.h line 86报错:R6010 Assertion failed,这是一个断言错误,在release模式下不会出现,但在debug模式下几乎是必现。原因嘛,打开Eigen给出的网址可以明确:数据结构未对齐(unaligned arrays)。这个问题对于刚接触openMVG的人来说还是很烦人的,openMVG代码很优雅,很多数据类型都是从模板类或函数延伸,通过虚函数扩展各项具体方法,而且非常强烈的依赖Eigen这个库,所以给定位问题带来了阻碍。经过一天的攻坚,大概确认了原因:

//原来

typedef std::vector FeatsT;

//改成

typedef std::vector> FeatsT;

//其它类似的地方都要改,包括返回vector的函数,也加上 EIGEN_MAKE_ALIGNED_OPERATOR_NEW

#1. 核心库

#1.1 图像

#Image Container

openMVG提供一个基本的类用作图像容器:Image,T代表像素类型,这个类可以处理灰度,RGB,RGBA或者自定义类型的图像。用法很简单:

// A 8-bit gray image:

Image grayscale_image_8bit;

// Multichannel image: (use pre-defined pixel type)

Image rgb_image_8bit;

// 8-bit RGBA image

Image rgba_image_8bit;

Image > rgba_image2_8bit;

这里的 RGBColor,RGBAColor等是openMVG基于Eigen定义好的类型,具体是定义在pixel_types.hpp中。

#Image I/O

openMVG支持ppm/pgm,jpeg,png,tiff格式的文件,例子:

Image rgb_image_gray;

bool bRet = ReadImage("Foo.imgExtension", &rgb_image);

#Drawing operations

用于在图像上画圆,椭圆,直线等。

#1.2 数值

openMVG重新包装了Eigen的基本类型和算法,以便更简单的调用。比如 Vec2代表一个二维点(char型)。

#1.3 特征

这个模块主要是提供特征容器的封装,包括特征,特征描述,关键点集等,基本都是模板类,比如顶一个sift特征描述子可以这样做:

// SIFT like descriptor

typedef Descriptor siftDescriptorData;

#1.4 相机

此模块提供不同的相机模型的抽象类,包括:

#小孔相机模型

/// 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.transe() t;

P_From_KRt(_K, _R, _t, &_P);

}PinholeCamera(const Mat34 & P)

{_P = P;

KRt_From_P(_P, &_K, &_R, &_t);

_C = -_R.transe() _t;

}/// Projection matrix P = K[R|t]

/// Intrinsic parameter (Focal, principal point)

Mat3 _K;

/// Extrinsic Rotation

/// Extrinsic translation

Vec3 _t;

/// Camera center

Vec3 _C;

};

这部分是比较基础和重要的模块之一,包括了:

多视角集几何中n(>=2)视角的求解算法;

将这些求解算法综合起来以便进行鲁棒估计的通用框架——Kernel;

文档中讲解了单应矩阵,本征矩阵,本质矩阵,位置矩阵等的概念,讲得非常好,建议仔细阅读文档。 简单的解释一下:

本征矩阵:同一个场景在两个相机成像下的关系,也就是物体上的点A在两个视角下成像位置的关系;

位置矩阵:估计相机的位置(被转化为一个最小化问题求解);

Kernel:一个将求解器、数据、度量方案等结合起来的类,这个类将用于鲁棒的估计以上的参数和矩阵;

#1.6 线性规划

一个用于求解多视角几何中线性优化(参数估计)的工具集,文档。

提供一些列鲁棒估计方法,比如:Max-Consensus,Max-Consensus,AC-Ransac A Contrario Ransac等。

#1.7 匹配

提供的接口包括:NNS,K-NN,FLANN,KVLD,Cascade hashing Nearest Neighbor等。这些接口可用于在二维或三维点集,以及更高维的特征描述集中。

#1.8

多视几何里的是指在一系列的中找到对应的特征点(同一点在不同视角下的位置)。

#1.9 sfm

openMVG提供的sfm模块包含了处理SfM问题的一系列方法个数据存储接口,例如相机位置估计,结构测量,BA等。 SfM_Data类包含了SfM所有的输入:

struct SfM_Data

{/// Considered views

Views views; // 包含图像文件名,id_view,id_e,id_intrinsic,image size。

Poses es; // 相机的三维位置

/// Considered camera intrinsics (indexed by view.id_cam)

Intrinsics intrinsics; // 相机内参

/// Structure (3D points with their 2D observations)

Landmarks structure; // 二维视图特征关联的3D点

}下面是例子:

#1. features_siftPutativeMatches

这个样例做了这么几件事(直接翻译):

分别提取两张图像的SIFT特征(使用非免费的vlsift)并形成特征描述;

根据特征描述子匹配两张图像上的特征点(BRUTE_FORCE_L2方法);

刚开始的时候会遇到Assertion failed断言错误,处理办法见上一篇文章。运行成功项目目录下会生成三个文件:00_images.jpg,01_features.jpg,02_siftMatches.svg。

这个例子是图像MSER(参考)和TBMR特征提取的样例,MSER(Maximally Stable Extremal Regions)极值稳定区域是一种对图像灰度具有仿射变换不变性,也许也是这个样例起名的原因。TBMR(tree-based Morse regions)这个算法不是特别了解,具体可以在google学术中搜索。

#3. features_image_matching

这个样例给出了利用Image_describer接口提取特征描述子,并匹配和显示结果的样例。示例中可以选择SIFT,AKAZE_MLDB或者AKAZE算法,AKAZE介绍可看这里,是一种比SIFT更稳定的特征检测算法。程序中关于解析输入参数的部分可以注释掉(如果你是用过VS2013 debug),直接修改sImage_describer_type这个值以测试。

#4. features_kvld_filter 和 features_repeatability

这两个也是关于特征提取和匹配的,kvld这个例子中由于之前更改了regions.h中的内容,所以有些函数接口也要做相应改变,具体也是在vector中增加对齐函数选项。

#5. multiview_robust_homography_guided 和 multiview_robust_fundamental_guided

这两个样例是估计单应矩阵和本征矩阵的,并且能够根据这些信息反过来确定匹配点。两个样例运行时间都很长(分辨率教大时),个在用另外的照片时还遇到报错,大概是在DoG时出错,具体也没有细究了·····

提取EXIF信息,编译后通过命令行执行,给出的参数格式:--imafile 你的照片路径,路径中使用/斜杠。

#7. multiview_robust_essential

估计本质矩阵并计算3D结构。这个例子可以直接运行,生成的点云十分稀疏且不带颜色信息。

模板匹配概述

提供一系列SfM需要用到的特征提取和匹配方法;

模板匹配是通过一张模板去另一张图中找到与模板相似部分的一种算法。一个模板是一张小,这个有一定的尺寸,有角度(一般是不旋转的矩形, 角度为0)。

单应矩阵:描述两个投影平面之间的关系;

模板匹配算法一般是通过滑窗的方式在待匹配的图像上滑动,通过比较模板与子图的相似度,找到相似度的子图。这种算法最核心部分在于如何设计一个相似性函数。

最容易想到的一个相似性函数便是欧式距离:

将这个相似性函数展开,可以得:

可以看出,只有第二项是有意义的,因为项和第三项的值在选定模板后是固定的。对于欧式距离相似函数,值越大表示越不相似,也就是说,第二项的值越小则越不相似。

将第二项进行归一化:

那么当R(i, j)为1时,表示模板与子图完全相等。

cv::matchTemplate(const CvArr image, //欲搜索的图像。它应该是单通道、8-比特或32-比特 浮点数图像

const CvArr template,//搜索模板,不能大于输入图像,且与输入图像具有一样的数据类型

CvArr result, //比较结果的映射图像。单通道、32-比特浮点数.

若图像是W×H而templ是w×h,则result一定是(W-w+1)×(H-h+1)

int mod//CV_TM_SQDIFF、CV_TM_SQDIFF_NORMED、CV_TM_CCORR、

CV_TM_CCORR_NORMED、CV_TM_CCOEFF、CV_TM_CCOEFF_NORMED

);

函数来进行模板匹配。其中的mod参数具体如下:

在通过matchTemplate函数进行模板匹配后,可以得到一个映射图,这张图中值的地方便是匹配度的子图的左上角坐标,可以使用cv::minMaxLoc函数获得子图位置和相应分数,再进行后续作。

使用传统的模板匹配速度较快,但是无法应对旋转和缩放问题。要解决旋转不变的 问题,必须要得到旋转不变的特征量,例如特征点。

使用SIFT或SURF计算得到模板和待匹配图像的特征点,然后使用RANSAC或者FLANN进行特征点匹配, 进行仿射变换便可得到匹配的位置。

python opencv实现(surf):

# - - coding:utf-8 - -

author = 'Microco'

运行的具体信息如下:

作系统:ubuntu 14.04

运行环境:

opencv版本:opencv 3.0

模板大小:126x96 png

匹配图像大小:750x407 jpg

特征提取时间:0.15 s

KNN匹配时间:0.0024s

匹配效果: