opencv实现的全景图种类与步骤

嵌入式设计应用

129人已加入

描述

  全景图概述

  每当一个平面图像映射到一个弯曲的表面就会发生图象投影,反之亦然,这中现象特别常见于全景摄影。例如地球的球面可以映射到一块平坦的纸张。由于在我们周围的整个视场的可以被认为是作为球体的表面(对于所有观测角度),我们需要一种能将球形投影到2-D平面以便照片打印的方法。

  

  小的视角相对容易进行形变并投影到平坦的纸上。但是,当试图把一个球形图像映射到一个平面上,有些变形是不可避免的。因此,每一种类型的投影仅仅尝试避免一种类型的失真,这是以牺牲其他失真为代价的。随着视场角增大,观测弧(viewing arc)变得更弯曲,从而全景投影类型之间的差异变得更加显着。什么时候使用那一种投影,在很大程度上取决于每个投影应用。

  整个全景拼接的算法流程来说,其实并不算复杂,至少在OpenCV的条件下如此。因为OpenCV自带了很多函数,完全可以搞定很多内容。

  1.选图,两张图的重叠区域不能太小,我个人认为最少不少于15%,这样才能保证有足够的角点匹配。

  2.角点检测。这一步OpenCV提供了很多种方法,譬如Harris角点检测,而监测出的角点用CvSeq存储,这是一个双向链表。

  3.角点提纯。在提纯的时候,需要使用RANSAC提纯。OpenCV自带了一个函数,FindHomography,不但可以提纯,还可以计算出3x3的转换矩阵。这个转换矩阵十分重要。

  4.角点匹配。经过提纯后的角点,则需要匹配。

  5.图像变换。这一步我曾经尝试过很多办法,最后选择了FindHomography输出的变换矩阵,这是一个透视变换矩阵。经过这个透视变换后的图像,可以直接拿来做拼接。

  6.图象拼接。完成上面步骤之后,其实这一步很容易。

  7.球面变换。这一步需要对坐标系进行转换,从平面坐标到球面坐标。

  OpenCV快速实现全景拼接

  最新版的opencv2.4里面有很多新元素。 stitching module 就是一个非常有用的。 在opencv的例程文件夹里,有一个很好的脚本叫做 stitching_detailed.cpp. 这个脚本包括了创建全景图的全部过程,包括特征提取,匹配,warp,以及合成。安装好opencv以后,可以简单的通过命令行来测试这个例程:

  $ 。/stitching_detailed Univ*.jpg

  这会使用默认参数来创建一个result.jpg的最终文件,来源的图片是以 “Univ”开头的jpg图像。 可以通过help察看一些设置

  $ 。/stitching_detailed --help

  例如,可以改变投影的方式,默认是球面投影。 下面的例程用摩卡托投影法:

  $ 。/stitching_detailed Univ*.jpg --warp mercator

  结果如下:原图像可以在这里找到

  

  简单实例

  首先看下,opencv实现图像拼接的最简单实例,这是将stitching.cpp裁剪到最简单的代码,和表现效果。

  具体代码

  [cpp] view plain copy#include 《iostream》

  #include 《fstream》

  #include “opencv2/highgui/highgui.hpp”

  #include “opencv2/stitching/stitcher.hpp”

  using namespace std;

  using namespace cv;

  bool try_use_gpu = true; //false;

  vector《Mat》 imgs;

  string result_name = “result.jpg”;

  int parseCmdArgs(int argc, char** argv){

  for (int i = 1; i 《 argc; ++i){

  Mat img = imread(argv[i]);

  if (img.empty()){

  cout 《《 “Can‘t read image ’” 《《 argv[i] 《《 “‘ ”;

  return -1;

  }

  imgs.push_back(img);

  imshow(argv[i], img);

  }

  return 0;

  }

  int main(int argc, char* argv[]){

  int retval = parseCmdArgs(argc, argv);

  if (retval) return -1;

  Mat pano;

  Stitcher stitcher = Stitcher::createDefault(try_use_gpu);

  Stitcher::Status status = stitcher.stitch(imgs, pano);

  if (status != Stitcher::OK){

  cout 《《 “Can’t stitch images, error code = ” 《《 int(status) 《《 endl;

  return -1;

  }

  imwrite(result_name, pano);

  imshow(“show”, pano);

  cv::waitKey(0);

  return 0;

  }

  效果演示

  运行本例:。/tmp 1.jpg 2.jpg 3.jpg

  实现效果如下:

  输入图像

  

  输出图像

  

  全景图实例2

  在前面的例子中,只是简单的使用函数:stitcher.stitch来生成里默认设置的全景图,这里继续使用新的方式来生成各种类型的全景图。

  实现代码

  具体代码如下:

  #include 《iostream》

  #include 《fstream》

  #include “opencv2/highgui/highgui.hpp”

  #include “opencv2/stitching/stitcher.hpp”

  using namespace std;

  using namespace cv;

  bool try_use_gpu = false;

  vector《Mat》 imgs;

  string result_name = “result.jpg”;

  int parseCmdArgs(int argc, char** argv){

  for (int i = 1; i 《 argc-1; ++i){

  Mat img = imread(argv[i]);

  if (img.empty()){

  cout 《《 “Can‘t read image ’” 《《 argv[i] 《《 “‘ ”;

  return -1;

  }

  imgs.push_back(img);

  imshow(argv[i], img);

  }

  return 0;

  }

  int main(int argc, char* argv[]){

  int retval = parseCmdArgs(argc, argv);

  if (retval) return -1;

  Mat pano;

  /*创建一个stitcher对象*/

  Stitcher stitcher = Stitcher::createDefault(try_use_gpu);

  /*设置生成结果图为:1:平面, 2:柱面, 3:立体画面*/

  if(argv[4][0] == ’1‘){

  PlaneWarper* cw = new PlaneWarper();

  stitcher.setWarper(cw);

  }else if(argv[4][0] == ’2‘){

  SphericalWarper* cw = new SphericalWarper();

  stitcher.setWarper(cw);

  }else if(argv[4][0] == ’3‘){

  StereographicWarper *cw = new cv::StereographicWarper();

  stitcher.setWarper(cw);

  }

  /*使用Surf算法来寻找特征点*/

  detail::SurfFeaturesFinder *featureFinder = new detail::SurfFeaturesFinder();

  stitcher.setFeaturesFinder(featureFinder);

  /*匹配给定的图像和估计相机的旋转*/

  Stitcher::Status status = stitcher.estimateTransform(imgs);

  if (status != Stitcher::OK)

  {

  cout 《《 “Can’t stitch images, error code = ” 《《 int(status) 《《 endl;

  return -1;

  }

  /*生成全景图像*/

  status = stitcher.composePanorama(pano);

  if (status != Stitcher::OK)

  {

  cout 《《 “Can‘t stitch images, error code = ” 《《 int(status) 《《 endl;

  return -1;

  }

  imwrite(result_name, pano);

  imshow(“show”, pano);

  cv::waitKey(0);

  return 0;

  }

  代码讲解

  1、填充imgs,将输入的图片全部填充到容器imgs中,并将输入的图片,一一显示出来。

  int parseCmdArgs(int argc, char** argv){

  for (int i = 1; i 《 argc-1; ++i){

  Mat img = imread(argv[i]);

  if (img.empty()){

  cout 《《 “Can‘t read image ’” 《《 argv[i] 《《 “‘ ”;

  return -1;

  }

  imgs.push_back(img);

  imshow(argv[i], img);

  }

  return 0;

  }

  2、创建一个stitcher对象。

  Stitcher stitcher = Stitcher::createDefault(try_use_gpu);

  3、设置生成结果图为:

       1:平面, 2:柱面, 3:立体画面。opencv中提供了很多可以生成的全景图种类。在它提供的复杂版实例:stitching_detailed.cpp,

  有如下种类可以选择:

  plane|cylindrical|spherical|fisheye|stereographic|compressedPlaneA2B1|

  compressedPlaneA1.5B1|compressedPlanePortraitA2B1|compressedPlanePortraitA1.5B1|paniniA2B1|

  paniniA1.5B1|paniniPortraitA2B1|paniniPortraitA1.5B1|mercator|transverseMercator

  本例中,只使用了3种作为选择:

  /*设置生成结果图为:1:平面, 2:柱面, 3:立体画面*/

  if(argv[4][0] == ‘1’){

  PlaneWarper* cw = new PlaneWarper();

  stitcher.setWarper(cw);

  }else if(argv[4][0] == ‘2’){

  SphericalWarper* cw = new SphericalWarper();

  stitcher.setWarper(cw);

  }else if(argv[4][0] == ‘3’){

  StereographicWarper *cw = new cv::StereographicWarper();

  stitcher.setWarper(cw);

  }

  4、选择寻找特征点的算法,opencv中提供了Surf和Orb两种方式可以选择,本例中使用的是Surf。

  detail::SurfFeaturesFinder *featureFinder = new detail::SurfFeaturesFinder();

  stitcher.setFeaturesFinder(featureFinder);

  5、生成输出全景图,这里使用另一种方式来实现。

  /*匹配给定的图像和估计相机的旋转*/

  Stitcher::Status status = stitcher.estimateTransform(imgs);

  /*生成全景图像*/

  status = stitcher.composePanorama(pano);

  imwrite(result_name, pano);

  imshow(“show”, pano);

  效果演示

  本例的三种效果图,对应显示如下:

  1、平面

 

  2、球面

  

  3、立体

 

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分