【OpenCV】 全景拼接——多张图像拼接

本文参考:https://blog.csdn.net/zhaocj/article/details/78798687

多张图像拼接:参考OpenCV4.1.1帮助文档中Examples—<samples/cpp/stitching_detailed.cpp>

stitching_detailed 图像拼接流程

【stitching_detailed程序运行流程】

1.命令行调用程序,输入源图像以及程序的参数

2.特征点检测,判断是使用surf还是orb,默认是surf。

3.对图像的特征点进行匹配,使用最近邻方法,将最优的匹配的置信度保存下来,同时保存两幅图像匹配特征点的单应性矩阵。

4.删除置信度比较低的图像间的匹配,利用并查集算法,确保匹配图像的拼接集。

 5.对所有拼接集图像进行相机参数粗略估计,然后求出旋转矩阵。

6.使用光束平均法进一步精准的估计出旋转矩阵。

7.波形校正,水平或者垂直。

8.曝光补偿器、接缝寻找器。

9.融合,多频段融合,全景图。


通过对【stitching_detailed源代码】的调整,加入拼接图片得到了全景图。具体代码请移步:【OpenCV】全景拼接_多张图像拼接

【运行结果】

没有使用 曝光补偿器 和 接缝拼接器。

【程序代码】

#include <iostream>
#include <fstream>
#include <string>
#include "opencv2/opencv_modules.hpp"
#include <opencv2/core/utility.hpp>
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/stitching/detail/autocalib.hpp"
#include "opencv2/stitching/detail/blenders.hpp"
#include "opencv2/stitching/detail/timelapsers.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/warpers.hpp"
#include "opencv2/stitching/warpers.hpp"
#include "opencv2/xfeatures2d/nonfree.hpp"

using namespace cv;
using namespace std;
using namespace cv::detail;

int main()
{
	//获取图片路径
	vector<String>image_names;  //所有图片名字
	String filepath = "C:\\Users\\Desktop\\photo\\*.jpg";   //图片存储路径
	glob(filepath, image_names, false);
	size_t num_images = image_names.size(); //图片数量
	cout << "检索到的图片为:" << endl;
	for (int i = 0; i < num_images; ++i)
	{
		cout << "Image #" <<i+1<<": "<< image_names[i]<<endl;
	}
	cout << endl;

	//存储图像、尺寸、特征点
	vector<ImageFeatures> features(num_images);  //存储图像特征点
	vector<Mat> images(num_images); //存储所有图像
	vector<Size> images_sizes(num_images); //存储图像的尺寸
	Ptr<Feature2D> featurefinder = xfeatures2d::SIFT::create();//特征点检测方法
	for (int i = 0; i < num_images; ++i)
	{
		images[i] = cv::imread(samples::findFile(image_names[i]));//读取每一张图片
		images_sizes[i] = images[i].size();
		computeImageFeatures(featurefinder, images[i], features[i]);    //计算图像特征
		//features[i].img_idx = i;
		cout << "image #" << i + 1 << "特征点为: " << features[i].keypoints.size() << " 个"<<"  "<< "尺寸为: " << images_sizes[i] << endl;
	}
	cout << endl;

	//图像特征点匹配
	vector<MatchesInfo> pairwise_matches; //表示特征匹配信息变量
	Ptr<FeaturesMatcher> matcher = makePtr<BestOf2NearestMatcher>(false, 0.3f, 6, 6); //定义特征匹配器,2NN方法
	(*matcher)(features, pairwise_matches);  //进行特征匹配

	//预估相机参数
	Ptr<Estimator> estimator;
	estimator = makePtr<HomographyBasedEstimator>();  //水平估计
	vector<CameraParams> cameras;  //相机参数素组
	(*estimator)(features, pairwise_matches, cameras);  //得到相机参数
	cout << "预估相机参数:" << endl;
	for (size_t i = 0; i < cameras.size(); ++i)
	{
		Mat R;
		cameras[i].R.convertTo(R, CV_32F);
		cameras[i].R = R;
		cout << "camera #" << i + 1 << ":\n内参数矩阵K:\n" << cameras[i].K() << "\n旋转矩阵R:\n" << cameras[i].R << "\n焦距focal: " << cameras[i].focal << endl;
	}
	cout << endl;

	//光束平差,精确相机参数
	Ptr<detail::BundleAdjusterBase> adjuster;
	adjuster = makePtr<detail::BundleAdjusterRay>();
	(*adjuster)(features, pairwise_matches, cameras);
	cout << "精确相机参数" << endl;
	for (size_t i = 0; i < cameras.size(); ++i)
	{
		Mat R;
		cameras[i].R.convertTo(R, CV_32F);
		cameras[i].R = R;
		cout << "camera #" << i + 1 << ":\n内参数矩阵K:\n" << cameras[i].K() << "\n旋转矩阵R:\n" << cameras[i].R << "\n焦距focal: " << cameras[i].focal << endl;
	}
	cout << endl;

	//波形矫正
	vector<Mat> mat;
	for (size_t i = 0; i < cameras.size(); ++i)
		mat.push_back(cameras[i].R);
	waveCorrect(mat, WAVE_CORRECT_HORIZ); //水平校正
	for (size_t i = 0; i < cameras.size(); ++i)
		cameras[i].R = mat[i];
	cout << endl;

	//创建mask图像
	vector<Mat> masks(num_images);
	for (int i = 0; i < num_images; ++i)
	{
		masks[i].create(images[i].size(), CV_8U);
		masks[i].setTo(Scalar::all(255));
	}

	//图像、掩码变换
	vector<Mat> masks_warp(num_images);  //mask扭曲
	vector<Mat> images_warp(num_images); //图像扭曲
	vector<Point> corners(num_images);   //图像左角点
	vector<Size> sizes(num_images);		 //图像尺寸
	Ptr<WarperCreator> warper_creator=makePtr<cv::CylindricalWarper>();  //柱面投影
	Ptr<RotationWarper> warper = warper_creator->create(static_cast<float>(cameras[0].focal));  //因为图像焦距都一样
	for (int i = 0; i < num_images; ++i)
	{
		Mat K;
		cameras[i].K().convertTo(K, CV_32F);
		corners[i] = warper->warp(images[i], K, cameras[i].R, INTER_LINEAR, BORDER_REFLECT, images_warp[i]);  //扭曲图像images->images_warp
		sizes[i] = images_warp[i].size();
		warper->warp(masks[i], K, cameras[i].R, INTER_NEAREST, BORDER_CONSTANT, masks_warp[i]);  //扭曲masks->masks_warped
	}
	for (int i = 0; i < num_images; ++i)
	{
		cout << "Image #" << i + 1 << "  corner: " << corners[i] << "  " << "size: " << sizes[i] << endl;
	}
	cout << endl;

	//图像融合
	Ptr<Blender> blender; //定义图像融合器
	blender = Blender::createDefault(Blender::NO, false); //简单融合方法
	blender->prepare(corners, sizes);  //生成全景图像区域
	for (int i = 0; i < num_images; ++i)
	{
		images_warp[i].convertTo(images_warp[i], CV_16S);
		blender->feed(images_warp[i], masks_warp[i], corners[i]);  //处理图像 初始化数据
	}
	Mat result, result_mask;
	blender->blend(result, result_mask);  //blend( InputOutputArray dst, InputOutputArray dst_mask  )混合并返回最后的pano。
	imwrite("result.jpg", result);

	return 0;
}

Standing up to your own...That would take a real hero.
能勇敢地坚持自己,那才是真正的英雄。

  • 14
    点赞
  • 98
    收藏
    觉得还不错? 一键收藏
  • 8
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值