網上搜的都是一行代碼Stitcher::Status status = stitcher.stitch(imgs, pano);就出來的傻瓜拼接,連opencv基本的包都沒用。
自己好歹用了下基本的包實現了下。
魯棒性不太好,圖片少的時候沒事,圖片一多就出現了內存錯誤和木有特征點的錯誤。
#include <iostream>
#include <fstream>
#include <io.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/stitching/stitcher.hpp"
#include "opencv2/stitching/warpers.hpp"
#define MaxPics 30
//F:\Program Files\opencv\modules\stitching\include\opencv2\stitching
using namespace std;
using namespace cv;
bool try_use_gpu = false;
int filenum;
vector<Mat> imgs;
string result_name = "result.jpg";
//void printUsage();
//int parseCmdArgs(int argc, char** argv);
int readDir(char *path,char fnames[MaxPics][100]);
int readDir(char *path,char fnames[MaxPics][100])
{
struct _finddata_t c_file;
intptr_t hFile;
filenum=0;
char fullpath[100];
sprintf(fullpath,"%s\\*.jpg",path);
// Find first .c file in current directory
if( (hFile = _findfirst( fullpath, &c_file )) == -1L )
printf( "No *.jpg files in current directory %s!\n",fullpath);
else
{
printf( "Listing of .jpg files in %s directory\n\n",path);
printf( "RDO HID SYS ARC FILE SIZE\n", ' ' );
printf( "--- --- --- --- ---- ----\n", ' ' );
do {
printf( ( c_file.attrib & _A_RDONLY ) ? " Y " : " N " );
printf( ( c_file.attrib & _A_SYSTEM ) ? " Y " : " N " );
printf( ( c_file.attrib & _A_HIDDEN ) ? " Y " : " N " );
printf( ( c_file.attrib & _A_ARCH ) ? " Y " : " N " );
//ctime_s( buffer, _countof(buffer), &c_file.time_write );
printf( " %-15s %9ld\n",c_file.name, c_file.size );
sprintf(fnames[filenum],"%s\\%s",path,c_file.name);
filenum++;
} while( _findnext( hFile, &c_file ) == 0 );
_findclose( hFile );
}
return filenum;
}
int main(int argc, char* argv[])
{
clock_t start,finish;
double totaltime;
start=clock();
argv[1]="pic";
char fdir[MaxPics][100];
filenum = readDir(argv[1],fdir);
Mat img, pano;
for(int i=0 ; i<filenum ;i++){
img = imread(fdir[i]);
imgs.push_back(img);
}
Stitcher stitcher = Stitcher::createDefault(try_use_gpu);
stitcher.setRegistrationResol(0.1);//為了加速,我選0.1,默認是0.6,最大值1最慢,此方法用於特征點檢測階段,如果找不到特征點,調高吧
//stitcher.setSeamEstimationResol(0.1);//默認是0.1
//stitcher.setCompositingResol(-1);//默認是-1,用於特征點檢測階段,找不到特征點的話,改-1
stitcher.setPanoConfidenceThresh(1);//默認是1,見過有設0.6和0.4的
stitcher.setWaveCorrection(false);//默認是true,為加速選false,表示跳過WaveCorrection步驟
//stitcher.setWaveCorrectKind(detail::WAVE_CORRECT_HORIZ);//還可以選detail::WAVE_CORRECT_VERT ,波段修正(wave correction)功能(水平方向/垂直方向修正)。因為setWaveCorrection設的false,此語句沒用
//找特征點surf算法,此算法計算量大,但對剛體運動、縮放、環境影響等情況下較為穩定
detail::SurfFeaturesFinder *featureFinder = new detail::SurfFeaturesFinder();
stitcher.setFeaturesFinder(featureFinder);
//找特征點ORB算法,但是發現草地這組圖,這個算法不能完成拼接
//detail::OrbFeaturesFinder *featureFinder = new detail::OrbFeaturesFinder();
//stitcher.setFeaturesFinder(featureFinder);
//Features matcher which finds two best matches for each feature and leaves the best one only if the ratio between descriptor distances is greater than the threshold match_conf.
detail::BestOf2NearestMatcher *matcher = new detail::BestOf2NearestMatcher(false, 0.5f/*=match_conf默認是0.65,我選0.8,選太大了就沒特征點啦,0.8都失敗了*/);
stitcher.setFeaturesMatcher(matcher);
// Rotation Estimation,It takes features of all images, pairwise matches between all images and estimates rotations of all cameras.
//Implementation of the camera parameters refinement algorithm which minimizes sum of the distances between the rays passing through the camera center and a feature,這個耗時短
stitcher.setBundleAdjuster(new detail::BundleAdjusterRay());
//Implementation of the camera parameters refinement algorithm which minimizes sum of the reprojection error squares.
//stitcher.setBundleAdjuster(new detail::BundleAdjusterReproj());
//Seam Estimation
//Minimum graph cut-based seam estimator
//stitcher.setSeamFinder(new detail::GraphCutSeamFinder(detail::GraphCutSeamFinderBase::COST_COLOR));//默認就是這個
//stitcher.setSeamFinder(new detail::GraphCutSeamFinder(detail::GraphCutSeamFinderBase::COST_COLOR_GRAD));//GraphCutSeamFinder的第二種形式
//啥SeamFinder也不用,Stub seam estimator which does nothing.
stitcher.setSeamFinder(new detail::NoSeamFinder);
//Voronoi diagram-based seam estimator.
//stitcher.setSeamFinder(new detail::VoronoiSeamFinder);
//exposure compensators曝光補償
//stitcher.setExposureCompensator(new detail::BlocksGainCompensator());//默認的就是這個
//不要曝光補償
stitcher.setExposureCompensator(new detail::NoExposureCompensator());
//Exposure compensator which tries to remove exposure related artifacts by adjusting image intensities
//stitcher.setExposureCompensator(new detail::detail::GainCompensator());
//Exposure compensator which tries to remove exposure related artifacts by adjusting image block intensities
//stitcher.setExposureCompensator(new detail::detail::BlocksGainCompensator());
//Image Blenders
//Blender which uses multi-band blending algorithm
//stitcher.setBlender(new detail::MultiBandBlender(try_use_gpu));//默認的是這個
//Simple blender which mixes images at its borders
stitcher.setBlender(new detail::FeatherBlender());//這個簡單,耗時少
//柱面?球面OR平面?默認為球面
PlaneWarper* cw = new PlaneWarper();
//SphericalWarper* cw = new SphericalWarper();
//CylindricalWarper* cw = new CylindricalWarper();
stitcher.setWarper(cw);
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;
}
cout<<"程序開始";
imwrite(result_name, pano);
finish=clock();
totaltime=(double)(finish-start)/CLOCKS_PER_SEC;
cout<<"\n此程序的運行時間為"<<totaltime<<"秒!"<<endl;
return 0;
}
至於其他的拼接方式,http://academy.nearsoft.com/project-updates/makingapanoramapicture寫的挺好。我引用之,並總結如下
1,Stitcher class from OpenCV library
- Pros
- Extremely simple. Build panorama in just one command.
- It performs from finding features through blending in the selected projection by itself.
- Cons
- Uses SURF algorithm (patented, not allowed for commercial use).
- Slow at searching for features, running on a smartphone
2,BoofCV
- Pros
- Still easy to use.
- Java native.
- Cons
- It blends without warping into the spherical projection.
- Still uses SURF.
當然自己實現最好,我的上述代碼就是第一種了