配置环境:VS2010+OpenCV2.4.9
为了使用OpenCV实现图像拼接头痛了好长时间,一直都没时间做,今天下定决心去实现基本的图像拼接。
首先,看一看使用OpenCV进行拼接的方法
基本都是用Stitcher类中的stitch方法。下面是网上的代码,同时也是opencvsamplescppstitching.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.nn"
40 "stitching img1 img2 [...imgN]nn"
41 "Flags:n"
42 " --try_use_gpu (yes|no)n"
43 " Try to use GPU. The default value is 'no'. All default valuesn"
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 valuen";
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
原文链接: https://www.cnblogs.com/wyuzl/p/7676691.html
欢迎关注
微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍
原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/261374
非原创文章文中已经注明原地址,如有侵权,联系删除
关注公众号【高性能架构探索】,第一时间获取最新文章
转载文章受原作者版权保护。转载请注明原作者出处!