Opencv 使用串联匹配图像拼接

opencv自带的stitching速度很慢, 其中一个最大的原因是每一张图都要和其它的图去匹配,如果有10张图,除去自身不用匹配外,要匹配 10X(10-1) = 90 次。10张532*300图拼接耗时14s左右,还姑且能忍受。可是100张图要匹配9900次。耗时不是简单的线性增长。
Stitch读入图像不用按照从左到右的顺序,拼接结果和运行时间都是一样的。

我们拍摄全景图的时候都是从左到右,或者从右到左,前后两张图一般有部分重合。所以一个节省时间的好办法就是我们这里只对前后两张图匹配,然后连成一串。即用串联匹配代替原匹配。
一些修改:
1.把匹配方法换成串联匹配

2.把费时的光束平差法改成"ray";//射线发散误差方法

3.再把费时的曝光补偿改成ExposureCompensator::GAIN;//增益法

4.接着把也费时的寻找接缝线改成"voronoi"; //逐点法

#include "opencv2/core/core.hpp"
#include "highgui.h"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/features2d/features2d.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/nonfree/nonfree.hpp"
#include "opencv2/legacy/legacy.hpp"
#include "cvaux.h" //必须引此头文件
#include "opencv2/stitching/detail/autocalib.hpp"
#include "opencv2/stitching/detail/blenders.hpp"
#include "opencv2/stitching/detail/camera.hpp"
#include "opencv2/stitching/detail/exposure_compensate.hpp"
#include "opencv2/stitching/detail/matchers.hpp"
#include "opencv2/stitching/detail/motion_estimators.hpp"
#include "opencv2/stitching/detail/seam_finders.hpp"
#include "opencv2/stitching/detail/util.hpp"
#include "opencv2/stitching/detail/warpers.hpp"
#include "opencv2/stitching/warpers.hpp"

#include 
#include 
#include 
#include 
#include
using namespace cv;
using namespace std;
using namespace detail;

void f2_matcher(vector &features, vector &f2_matches)
{

	//vector f2_matches;    //特征匹配
	BestOf2NearestMatcher matcher(false, 0.3f, 6, 6);    //定义特征匹配器,2NN方法
	matcher(features, f2_matches);    //进行特征匹配


}



void i_matcher(vector &features, vector &pairwise_matches)
{
	int num_images=features.size ();
	//1。串联匹配
	vector > f2_2;//f2_2[i] 表示 i 和 i+1 的匹配关系(0 开头,比图像数小 1)
    for (int i = 1; i < num_images; ++i)
    {
		vector f2;
		vector m2;
		f2.push_back (features[i-1]);
		f2.push_back (features[i]);
		f2_matcher(f2,m2);
		f2_2.push_back(m2);

	}


	//2。把串联匹配 ----按opencv stitching 拼接的匹配关系组在一起
	MatchesInfo f;//大小: n x n (n个图)
    for (int i = 0; i < num_images; ++i)
    {
		for (int j = 0; j < num_images; ++j)
		{
			//cout<<"i,j:"< imgs;    //输入图像
	Mat img;
	char temp[100];
    double ge[100];//100张图的特征点个数
    for (int i = 1; i<= 100; i++)
    {
    sprintf(temp, "D:\\低分辨率截图重命名\\%d.jpg", i);// 将图片以数字命名:例如1.jpg 2.jpg等
    img = imread(temp);
    imgs.push_back(img);
	}
    int num_images =100;    //图像数量
	vector features(num_images);    //表示图像特征

    Point2f point;
	KeyPoint kp;
	float temp1 = 0, temp2 = 0;
	char ptsname[100];
	char descname[100];
	ifstream g("D:\\特征\\特征点个数.txt");//将100张图的特征点个数导入数组
    assert(g.is_open());
	for(int i=1;i<=100;i++)
{
    g>>ge[i-1];
}
    g.close();
	for(int i=1;i<=100;i++)
{
    sprintf(ptsname, "D:\\特征\\pts%d.txt",i); //格式化输出文件名
    ifstream infile(ptsname);
	assert(infile.is_open());   //若失败,则输出错误消息,并终止程序运行
	for (int a = 0; !infile.eof(); a++)
	{
		infile >> temp1 >> temp2;
		point.x = temp1;
		point.y = temp2;
		kp = KeyPoint(point, 1.f);
		features[i-1].keypoints.push_back(kp);
	}
	infile.close();
	//infile.clear();

	sprintf(descname, "D:\\特征\\desc%d.txt",i); //格式化输出文件名
    ifstream des(descname);
	assert(des.is_open());   //若失败,则输出错误消息,并终止程序运行
    cout<> features[i-1].descriptors.at(k, j);
		}
			}
	des.close();
	//des.clear();
}
	vector pairwise_matches;    //表示特征匹配信息变量
	BestOf2NearestMatcher matcher(false, 0.3f, 6, 6);    //定义特征匹配器,2NN方法
	//matcher(features, pairwise_matches);    //进行特征匹配
    i_matcher(features, pairwise_matches);//这里用我们自己的匹配代替
cout<<"96行";

	HomographyBasedEstimator estimator;    //定义参数评估器
	vector cameras;    //表示相机参数
	estimator(features, pairwise_matches, cameras);    //进行相机参数评估
cout<<'1';
	for (size_t i = 0; i < cameras.size(); ++i)    //转换相机旋转参数的数据类型
	{
		Mat R;
		cameras[i].R.convertTo(R, CV_32F);
		cameras[i].R = R;
	}

	Ptr adjuster;    //光束平差法,精确相机参数
	//adjuster = new detail::BundleAdjusterReproj();    //重映射误差方法
	adjuster = new detail::BundleAdjusterRay();    //射线发散误差方法
cout<<"96行";
	adjuster->setConfThresh(1);    //设置匹配置信度,该值设为1
	(*adjuster)(features, pairwise_matches, cameras);    //精确评估相机参数
cout<<"96行";
	vector rmats;
	for (size_t i = 0; i < cameras.size(); ++i)    //复制相机的旋转参数
		rmats.push_back(cameras[i].R.clone());
	waveCorrect(rmats, WAVE_CORRECT_HORIZ);    //进行波形校正
	for (size_t i = 0; i < cameras.size(); ++i)    //相机参数赋值
		cameras[i].R = rmats[i];
	rmats.clear();    //清变量

	vector corners(num_images);    //表示映射变换后图像的左上角坐标
	vector masks_warped(num_images);    //表示映射变换后的图像掩码
	vector images_warped(num_images);    //表示映射变换后的图像
	vector sizes(num_images);    //表示映射变换后的图像尺寸
	vector masks(num_images);    //表示源图的掩码
cout<<"129行";
	for (int i = 0; i < num_images; ++i)    //初始化源图的掩码
	{
		masks[i].create(imgs[i].size(), CV_8U);    //定义尺寸大小
		masks[i].setTo(Scalar::all(255));    //全部赋值为255,表示源图的所有区域都使用
	}

	Ptr warper_creator;    //定义图像映射变换创造器
	warper_creator = new cv::PlaneWarper();    //平面投影
	//warper_creator = new cv::CylindricalWarper();    //柱面投影
	//warper_creator = new cv::SphericalWarper();    //球面投影
	//warper_creator = new cv::FisheyeWarper();    //鱼眼投影
	//warper_creator = new cv::StereographicWarper();    //立方体投影

	//定义图像映射变换器,设置映射的尺度为相机的焦距,所有相机的焦距都相同
	Ptr warper = warper_creator->create(static_cast(cameras[0].focal));
	for (int i = 0; i < num_images; ++i)
	{
		Mat_ K;
		cameras[i].K().convertTo(K, CV_32F);    //转换相机内参数的数据类型
		//对当前图像镜像投影变换,得到变换后的图像以及该图像的左上角坐标
		corners[i] = warper->warp(imgs[i], K, cameras[i].R, INTER_LINEAR, BORDER_REFLECT, images_warped[i]);
		sizes[i] = images_warped[i].size();    //得到尺寸
		//得到变换后的图像掩码
		warper->warp(masks[i], K, cameras[i].R, INTER_NEAREST, BORDER_CONSTANT, masks_warped[i]);
	}

	imgs.clear();    //清变量
	masks.clear();

	//创建曝光补偿器,应用增益补偿方法
	Ptr compensator =
		ExposureCompensator::createDefault(ExposureCompensator::GAIN);
	compensator->feed(corners, images_warped, masks_warped);    //得到曝光补偿器
	for (int i = 0; i < num_images; ++i)    //应用曝光补偿器,对图像进行曝光补偿
	{
		compensator->apply(i, corners[i], images_warped[i], masks_warped[i]);
	}

	//在后面,我们还需要用到映射变换图的掩码masks_warped,因此这里为该变量添加一个副本masks_seam
	vector masks_seam(num_images);
	for (int i = 0; i < num_images; i++)
		masks_warped[i].copyTo(masks_seam[i]);

	Ptr seam_finder;    //定义接缝线寻找器
   //seam_finder = new NoSeamFinder();    //无需寻找接缝线
   seam_finder = new VoronoiSeamFinder();    //逐点法
   //seam_finder = new DpSeamFinder(DpSeamFinder::COLOR);    //动态规范法
   //seam_finder = new DpSeamFinder(DpSeamFinder::COLOR_GRAD);
   //图割法
   //seam_finder = new GraphCutSeamFinder(GraphCutSeamFinder::COST_COLOR);
	//seam_finder = new GraphCutSeamFinder(GraphCutSeamFinder::COST_COLOR_GRAD);

	vector images_warped_f(num_images);
	for (int i = 0; i < num_images; ++i)    //图像数据类型转换
		images_warped[i].convertTo(images_warped_f[i], CV_32F);

	images_warped.clear();    //清内存

	//得到接缝线的掩码图像masks_seam
	seam_finder->find(images_warped_f, corners, masks_seam);
cout<<"190行";
	vector images_warped_s(num_images);
	Ptr blender;    //定义图像融合器

	//blender = Blender::createDefault(Blender::NO, false);    //简单融合方法
	//羽化融合方法
	//blender = Blender::createDefault(Blender::FEATHER, false);
	//FeatherBlender* fb = dynamic_cast(static_cast(blender));
	//fb->setSharpness(0.005);    //设置羽化锐度

	blender = Blender::createDefault(Blender::MULTI_BAND, false);    //多频段融合
	MultiBandBlender* mb = dynamic_cast(static_cast(blender));
	mb->setNumBands(8);   //设置频段数,即金字塔层数

	blender->prepare(corners, sizes);    //生成全景图像区域

	//在融合的时候,最重要的是在接缝线两侧进行处理,而上一步在寻找接缝线后得到的掩码的边界就是接缝线处,因此我们还需要在接缝线两侧开辟一块区域用于融合处理,这一处理过程对羽化方法尤为关键
	//应用膨胀算法缩小掩码面积
	vector dilate_img(num_images);
	Mat element = getStructuringElement(MORPH_RECT, Size(20, 20));    //定义结构元素
	for (int k = 0; k < num_images; k++)
	{
		images_warped_f[k].convertTo(images_warped_s[k], CV_16S);    //改变数据类型
		dilate(masks_seam[k], masks_seam[k], element);    //膨胀运算
		//映射变换图的掩码和膨胀后的掩码相“与”,从而使扩展的区域仅仅限于接缝线两侧,其他边界处不受影响
		masks_seam[k] = masks_seam[k] & masks_warped[k];
		blender->feed(images_warped_s[k], masks_seam[k], corners[k]);    //初始化数据
	}

	masks_seam.clear();    //清内存
	images_warped_s.clear();
	masks_warped.clear();
	images_warped_f.clear();

	Mat result, result_mask;
	//完成融合操作,得到全景图像result和它的掩码result_mask
	blender->blend(result, result_mask);

	imwrite("pano.jpg", result);    //存储全景图像

	return 0;

}

你可能感兴趣的:(opencv,图像拼接)