利用OpenCV实现图像拼接的代码

图像拼接是利用连续帧图像生成全景图或更高分辨率的图像,通常图像拼接技术需要消除图像拼接部分的缝隙间隔,因些需要进行重叠区域匹配修复。通常图像拼接分为以下三个步骤:

⑴特征点检测。图像拼接操作对序列图像一般要求重叠区域不少于10%,对序列图像进行特征点检测,可利用OpenCV中提供的角点检测方法来对序列图像进行特征点提取。特征点筛选采用RANSAC提取有效样本特征点,OpenCV提供了函数FindHomography,可以进行特征筛选,同时可以计算出3×3转换矩阵。

⑵图像标定。计算出两幅图像之间的最优空间位置和色彩之间的变换关系,该映射关系矩阵能有效地将一幅图像中的点最优地映射到另一幅图像中,映射关系矩阵是该步骤的核心,根据上一步骤中得到的转换矩阵可计算出对应的透视变换。

⑶图像融合。根据标定步骤得到图像的输出投影,同时调整图像的空间颜色,以弥补曝光差异。缝隙调整是为了最大限度地减少图像之间拼接缝隙的可见性,最后对得到的图像进行事以得到全景图。

OpenCV提供了图像拼接类库Stitcher可完成图像间的缝合连接。Stitcher包含多个成员函数,estimateTransform函数实现匹配给定图像及估计每个摄像机的旋转矩阵;composePanorama函数实现组成给定图像的偏移,将图像偏移存储在内部并可供其他函数调用;stitch成员函数实现拼接给定图像。
OpenCV下实现图像拼接的代码如下:

代码中用到的三张图像的下载链接为:图像拼接_免费高速下载|百度网盘-分享无限制

说明一下:代码中stitch函数使用Stitcher类实现图像拼接,而stitch2则自己实现算法,并且stitch2只能实现两幅图的拼接

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/features2d/features2d.hpp>
#include <opencv2/xfeatures2d/nonfree.hpp>
#include <opencv2/calib3d/calib3d.hpp>
#include <opencv2/stitching.hpp>
#include <iostream>
#include <vector>  
using namespace std;
using namespace cv;
void stitch(std::vector<cv::Mat> imgs, cv::Mat& resultMat)
{
	bool Flag = true;
	// 定义Stitcher类
	Stitcher stitcher = Stitcher::createDefault(Flag);
	Stitcher::Status status = stitcher.stitch(imgs, resultMat);
	if (status != Stitcher::OK) {
		std::cout << "error" << std::endl;
	}
}
void stitch2(Mat& srcImage1, Mat& srcImage2, Mat& panorama)
{
	// SURF特征点描述
	Mat srcImage2Warped;
	// 初始化SURF检测描述子
	cv::Ptr<Feature2D> surf = xfeatures2d::SURF::create();

	// 关键点及特征描述矩阵声明
	vector<cv::KeyPoint> kPointMat, kPointMat2;;
	cv::Mat desMat1, desMat2;

	surf->detectAndCompute(srcImage1, Mat(), kPointMat, desMat1);
	surf->detectAndCompute(srcImage2, Mat(), kPointMat2, desMat2);

	// FLANN 关键点匹配
	// FLANN 初始化 RANSAC一致性 最近邻特征
	FlannBasedMatcher matcher;
	std::vector< DMatch > matches;
	matcher.match(desMat1, desMat2, matches);
	double max_dist = 0, min_dist = 100;
	// 特征点最大与最小距离查找
	for (int i = 0; i < desMat1.rows; i++)
	{
		double dist = matches[i].distance;
		if (dist < min_dist) min_dist = dist;
		if (dist > max_dist) max_dist = dist;
	}
	// 使用good 特征构建距离限定 
	std::vector< DMatch > good_matches;
	for (int i = 0; i < desMat1.rows; i++)
	{
		if (matches[i].distance < 3 * min_dist)
		{
			good_matches.push_back(matches[i]);
		}
	}
	// 图像的关键点匹配
	std::vector<Point2f> srcImage1_matchedKPs;
	std::vector<Point2f> srcImage2_matchedKPs;
	for (size_t i = 0; i < good_matches.size(); i++)
	{
		srcImage1_matchedKPs.push_back(
			kPointMat[good_matches[i].queryIdx].pt);		srcImage2_matchedKPs.push_back(
				kPointMat2[good_matches[i].trainIdx].pt);
	}
	// 计算图像1与图像2的映射
	Mat H = findHomography(Mat(srcImage2_matchedKPs),
		Mat(srcImage1_matchedKPs), CV_RANSAC);
	// 仿射变换
	warpPerspective(srcImage2, srcImage2Warped, H,
		Size(srcImage2.cols * 2, srcImage2.rows), INTER_CUBIC);
	panorama = srcImage2Warped.clone();
	// 结果输出
	Mat roi(panorama, Rect(0, 0,
		srcImage1.cols, srcImage1.rows));
	srcImage1.copyTo(roi);
}
int main(int argc, char* argv[])
{
	cv::Mat image1 = imread("..\\images\\img07.JPG");
	cv::Mat image2 = imread("..\\images\\img08.JPG");
	cv::Mat image3 = imread("..\\images\\img09.JPG");
	if (!image1.data || !image2.data || !image3.data)
		return -1;
	vector<Mat> imgs;
	imgs.push_back(image1);
	imgs.push_back(image2);
	imgs.push_back(image3);
	cv::Mat resultMat1, resultMat2;
	stitch(imgs, resultMat1);
	cv::imshow("resultMat1", resultMat1);
	stitch2(image1, image2, resultMat2);
	cv::imshow("resultMat2", resultMat2);
	cv::waitKey(0);
	return 0;
}

运行结果如下图所示

猜你喜欢

转载自blog.csdn.net/wenhao_ir/article/details/52071204#comments_22445076