配置環境:VS2010+OpenCV2.4.9
為了使用OpenCV實現圖像拼接頭痛了好長時間,一直都沒時間做,今天下定決心去實現基本的圖像拼接。
首先,看一看使用OpenCV進行拼接的方法
基本都是用Stitcher類中的stitch方法。下面是網上的代碼,同時也是opencv\samples\cpp\stitching.cpp的代碼。
1 #include <iostream> 2 #include <fstream> 3 #include "opencv2/highgui/highgui.hpp" 4 #include "opencv2/stitching/stitcher.hpp" 5 6 using namespace std; 7 using namespace cv; 8 9 bool try_use_gpu = false; 10 vector<Mat> imgs; 11 string result_name = "result.jpg"; 12 13 void printUsage(); 14 int parseCmdArgs(int argc, char** argv); 15 16 int main(int argc, char* argv[]) 17 { 18 int retval = parseCmdArgs(argc, argv); 19 if (retval) return -1; 20 21 Mat pano; 22 Stitcher stitcher = Stitcher::createDefault(try_use_gpu); 23 Stitcher::Status status = stitcher.stitch(imgs, pano); 24 25 if (status != Stitcher::OK) 26 { 27 cout << "Can't stitch images, error code = " << int(status) << endl; 28 return -1; 29 } 30 31 imwrite(result_name, pano); 32 return 0; 33 } 34 35 36 void printUsage() 37 { 38 cout << 39 "Rotation model images stitcher.\n\n" 40 "stitching img1 img2 [...imgN]\n\n" 41 "Flags:\n" 42 " --try_use_gpu (yes|no)\n" 43 " Try to use GPU. The default value is 'no'. All default values\n" 44 " are for CPU mode.\n" 45 " --output <result_img>\n" 46 " The default is 'result.jpg'.\n"; 47 } 48 49 50 int parseCmdArgs(int argc, char** argv) 51 { 52 if (argc == 1) 53 { 54 printUsage(); 55 return -1; 56 } 57 for (int i = 1; i < argc; ++i) 58 { 59 if (string(argv[i]) == "--help" || string(argv[i]) == "/?") 60 { 61 printUsage(); 62 return -1; 63 } 64 else if (string(argv[i]) == "--try_use_gpu") 65 { 66 if (string(argv[i + 1]) == "no") 67 try_use_gpu = false; 68 else if (string(argv[i + 1]) == "yes") 69 try_use_gpu = true; 70 else 71 { 72 cout << "Bad --try_use_gpu flag value\n"; 73 return -1; 74 } 75 i++; 76 } 77 else if (string(argv[i]) == "--output") 78 { 79 result_name = argv[i + 1]; 80 i++; 81 } 82 else 83 { 84 Mat img = imread(argv[i]); 85 if (img.empty()) 86 { 87 cout << "Can't read image '" << argv[i] << "'\n"; 88 return -1; 89 } 90 imgs.push_back(img); 91 } 92 } 93 return 0; 94 }
感覺這個說的比較繁瑣,我就改寫成了下面的代碼
1 #include <iostream> 2 #include <fstream> 3 #include <opencv2/core/core.hpp> 4 #include "opencv2/highgui/highgui.hpp" 5 #include "opencv2/stitching/stitcher.hpp" 6 #include<Windows.h> 7 8 using namespace std; 9 using namespace cv; 10 11 bool try_use_gpu = false; 12 vector<Mat> imgs; 13 string result_name = "result.jpg"; 14 15 int main() 16 { 17 Mat img1=imread("1.jpg"); 18 Mat img2=imread("2.jpg"); 19 imgs.push_back(img1); 20 imgs.push_back(img2); 21 Mat pano; 22 Stitcher stitcher = Stitcher::createDefault(try_use_gpu); 23 Stitcher::Status status = stitcher.stitch(imgs, pano); 24 if (status != Stitcher::OK) 25 { 26 cout << "Can't stitch images, error code = " << status << endl; 27 return -1; 28 } 29 namedWindow(result_name); 30 imshow(result_name,pano); 31 imwrite(result_name,pano); 32 waitKey(); 33 return 0; 34 }
下面看一下原圖和效果圖,(以四張原圖為例,分為左上,右上,左下,右下)
效果圖如下:
可以發現代碼中最關鍵的兩句就是:
Stitcher stitcher = Stitcher::createDefault(try_use_gpu);
Stitcher::Status status = stitcher.stitch(imgs, pano);
Stitcher是OpenCV的一個類,下面看一下這個類的源代碼:
class CV_EXPORTS Stitcher { public: enum { ORIG_RESOL = -1 }; enum Status { OK, ERR_NEED_MORE_IMGS }; // Creates stitcher with default parameters static Stitcher createDefault(bool try_use_gpu = false); Status estimateTransform(InputArray images); Status estimateTransform(InputArray images, const std::vector<std::vector<Rect> > &rois); Status composePanorama(OutputArray pano); Status composePanorama(InputArray images, OutputArray pano); Status stitch(InputArray images, OutputArray pano); Status stitch(InputArray images, const std::vector<std::vector<Rect> > &rois, OutputArray pano); double registrationResol() const { return registr_resol_; } void setRegistrationResol(double resol_mpx) { registr_resol_ = resol_mpx; } double seamEstimationResol() const { return seam_est_resol_; } void setSeamEstimationResol(double resol_mpx) { seam_est_resol_ = resol_mpx; } double compositingResol() const { return compose_resol_; } void setCompositingResol(double resol_mpx) { compose_resol_ = resol_mpx; } double panoConfidenceThresh() const { return conf_thresh_; } void setPanoConfidenceThresh(double conf_thresh) { conf_thresh_ = conf_thresh; } bool waveCorrection() const { return do_wave_correct_; } void setWaveCorrection(bool flag) { do_wave_correct_ = flag; } detail::WaveCorrectKind waveCorrectKind() const { return wave_correct_kind_; } void setWaveCorrectKind(detail::WaveCorrectKind kind) { wave_correct_kind_ = kind; } Ptr<detail::FeaturesFinder> featuresFinder() { return features_finder_; } const Ptr<detail::FeaturesFinder> featuresFinder() const { return features_finder_; } void setFeaturesFinder(Ptr<detail::FeaturesFinder> features_finder) { features_finder_ = features_finder; } Ptr<detail::FeaturesMatcher> featuresMatcher() { return features_matcher_; } const Ptr<detail::FeaturesMatcher> featuresMatcher() const { return features_matcher_; } void setFeaturesMatcher(Ptr<detail::FeaturesMatcher> features_matcher) { features_matcher_ = features_matcher; } const cv::Mat& matchingMask() const { return matching_mask_; } void setMatchingMask(const cv::Mat &mask) { CV_Assert(mask.type() == CV_8U && mask.cols == mask.rows); matching_mask_ = mask.clone(); } Ptr<detail::BundleAdjusterBase> bundleAdjuster() { return bundle_adjuster_; } const Ptr<detail::BundleAdjusterBase> bundleAdjuster() const { return bundle_adjuster_; } void setBundleAdjuster(Ptr<detail::BundleAdjusterBase> bundle_adjuster) { bundle_adjuster_ = bundle_adjuster; } Ptr<WarperCreator> warper() { return warper_; } const Ptr<WarperCreator> warper() const { return warper_; } void setWarper(Ptr<WarperCreator> warper) { warper_ = warper; } Ptr<detail::ExposureCompensator> exposureCompensator() { return exposure_comp_; } const Ptr<detail::ExposureCompensator> exposureCompensator() const { return exposure_comp_; } void setExposureCompensator(Ptr<detail::ExposureCompensator> exposure_comp) { exposure_comp_ = exposure_comp; } Ptr<detail::SeamFinder> seamFinder() { return seam_finder_; } const Ptr<detail::SeamFinder> seamFinder() const { return seam_finder_; } void setSeamFinder(Ptr<detail::SeamFinder> seam_finder) { seam_finder_ = seam_finder; } Ptr<detail::Blender> blender() { return blender_; } const Ptr<detail::Blender> blender() const { return blender_; } void setBlender(Ptr<detail::Blender> blender) { blender_ = blender; } private: /* hidden */ };
可以看到Stitcher大致有這些成員函數:createDefault,estimateTransform,composePanorama,stitch等等。
Stitcher stitcher = Stitcher::createDefault(try_use_gpu);這句話表示使用默認參數創建Stitcher類的對象stitcher,try_use_gpu表示是否打開GPU,默認不打開,即try_use_gpu=false;下面是這個函數的原型:
C++: Stitcher Stitcher::createDefault(
bool
try_use_gpu=
false
)
參數:Flag indicating whether GPU should be used whenever it’s possible.
return
:Stitcher
class
instance.(即創建了一個對象)
Stitcher::Status status = stitcher.stitch(imgs, pano);這句話表示:
try
to stitch the given images
C++: Status Stitcher::stitch(InputArray images, OutputArray pano) C++: Status Stitcher::stitch(InputArray images, const std::vector<std::vector<Rect>>& rois, OutputArray pano) 參數:images – Input images. rois – Region of interest rectangles.(感興趣區) pano – Final pano. return:Status code.(數據成員中枚舉數組的一項)
|
Stitcher::estimateTransform和Stitcher::composePanorama的使用為高級使用,需要清楚Stitching pipeline的過程。
下面貼出pipeline:
可以看出這個過程很復雜,需要涉及到很多的算法,比如:特征點的提取、特征點匹配、圖像融合等等。這些過程OpenCV都為我們封裝在Stitcher類中,不在此細述。
總結
雖然用OpenCV中的Stitcher類實現了基本的拼接,但是有一個最大的問題是,運行的效率是極低的,就這個代碼中,拼接3張圖片差不多用了一分鍾,這在需要做實時拼接的時候是根本不可能使用的,所以后面需要做的工作任然是弄清楚Stitching pipeline的詳細過程,進一步優化代碼,提高拼接運行效率。
下面貼出參考資料:
http://docs.opencv.org/2.4.2/modules/stitching/doc/high_level.html
下面貼出源代碼和OpenCV中的stiching.cpp和stitching_detailed.cpp的下載地址:
http://download.csdn.net/detail/u013637931/8255767
轉自:http://www.cnblogs.com/CHLL55/p/4161551.html