OpenCV stitch圖像拼接

配置環境: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等等。

1

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

 

1

2

3

4

5

6

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章