全景圖概述
每當一個平面圖像映射到一個彎曲的表面就會發(fā)生圖象投影,反之亦然,這中現(xiàn)象特別常見于全景攝影。例如地球的球面可以映射到一塊平坦的紙張。由于在我們周圍的整個視場的可以被認為是作為球體的表面(對于所有觀測角度),我們需要一種能將球形投影到2-D平面以便照片打印的方法。
小的視角相對容易進行形變并投影到平坦的紙上。但是,當試圖把一個球形圖像映射到一個平面上,有些變形是不可避免的。因此,每一種類型的投影僅僅嘗試避免一種類型的失真,這是以犧牲其他失真為代價的。隨著視場角增大,觀測弧(viewing arc)變得更彎曲,從而全景投影類型之間的差異變得更加顯著。什么時候使用那一種投影,在很大程度上取決于每個投影應用。
整個全景拼接的算法流程來說,其實并不算復雜,至少在OpenCV的條件下如此。因為OpenCV自帶了很多函數(shù),完全可以搞定很多內容。
1.選圖,兩張圖的重疊區(qū)域不能太小,我個人認為最少不少于15%,這樣才能保證有足夠的角點匹配。
2.角點檢測。這一步OpenCV提供了很多種方法,譬如Harris角點檢測,而監(jiān)測出的角點用CvSeq存儲,這是一個雙向鏈表。
3.角點提純。在提純的時候,需要使用RANSAC提純。OpenCV自帶了一個函數(shù),F(xiàn)indHomography,不但可以提純,還可以計算出3x3的轉換矩陣。這個轉換矩陣十分重要。
4.角點匹配。經(jīng)過提純后的角點,則需要匹配。
5.圖像變換。這一步我曾經(jīng)嘗試過很多辦法,最后選擇了FindHomography輸出的變換矩陣,這是一個透視變換矩陣。經(jīng)過這個透視變換后的圖像,可以直接拿來做拼接。
6.圖象拼接。完成上面步驟之后,其實這一步很容易。
7.球面變換。這一步需要對坐標系進行轉換,從平面坐標到球面坐標。
OpenCV快速實現(xiàn)全景拼接
最新版的opencv2.4里面有很多新元素。 stitching module 就是一個非常有用的。 在opencv的例程文件夾里,有一個很好的腳本叫做 stitching_detailed.cpp. 這個腳本包括了創(chuàng)建全景圖的全部過程,包括特征提取,匹配,warp,以及合成。安裝好opencv以后,可以簡單的通過命令行來測試這個例程:
$ 。/stitching_detailed Univ*.jpg
這會使用默認參數(shù)來創(chuàng)建一個result.jpg的最終文件,來源的圖片是以 “Univ”開頭的jpg圖像。 可以通過help察看一些設置
$ 。/stitching_detailed --help
例如,可以改變投影的方式,默認是球面投影。 下面的例程用摩卡托投影法:
$ 。/stitching_detailed Univ*.jpg --warp mercator
結果如下:原圖像可以在這里找到
簡單實例
首先看下,opencv實現(xiàn)圖像拼接的最簡單實例,這是將stitching.cpp裁剪到最簡單的代碼,和表現(xiàn)效果。
具體代碼
[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
實現(xiàn)效果如下:
輸入圖像
輸出圖像
全景圖實例2
在前面的例子中,只是簡單的使用函數(shù):stitcher.stitch來生成里默認設置的全景圖,這里繼續(xù)使用新的方式來生成各種類型的全景圖。
實現(xiàn)代碼
具體代碼如下:
#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;
/*創(chuàng)建一個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、創(chuàng)建一個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、生成輸出全景圖,這里使用另一種方式來實現(xiàn)。
/*匹配給定的圖像和估計相機的旋轉*/
Stitcher::Status status = stitcher.estimateTransform(imgs);
/*生成全景圖像*/
status = stitcher.composePanorama(pano);
imwrite(result_name, pano);
imshow(“show”, pano);
效果演示
本例的三種效果圖,對應顯示如下:
1、平面
2、球面
3、立體
評論
查看更多