欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C++ OpenCV實(shí)戰(zhàn)之圖像全景拼接

 更新時(shí)間:2022年01月04日 16:23:42   作者:Zero___Chen  
本文主要介紹了如何使用OpenCV C++ 進(jìn)行圖像全景拼接,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)OpenCV有一定的幫助,感興趣的可以了解一下

前言

本文將使用OpenCV C++ 進(jìn)行圖像全景拼接。目前使用OpenCV對(duì)兩幅圖像進(jìn)行拼接大致可以分為兩類。

一、使用OpenCV內(nèi)置API Stitcher 進(jìn)行拼接。

二、使用特征檢測(cè)算法匹配兩幅圖中相似的點(diǎn)、計(jì)算變換矩陣、最后對(duì)其進(jìn)行透視變換就可以了。

一、OpenCV Stitcher

imageA

imageB

原圖如圖所示。本案例的需求是將上述兩幅圖片拼接成一幅圖像。首先使用OpenCV提供的Stitcher進(jìn)行拼接。關(guān)于Stitcher的具體原理請(qǐng)大家自行查找相關(guān)資料。

1.功能源碼

bool OpenCV_Stitching(Mat imageA, Mat imageB)
{
	vector<Mat>images;
	images.push_back(imageA);
	images.push_back(imageB);

	Ptr<Stitcher>stitcher = Stitcher::create();

	Mat result;
	Stitcher::Status status = stitcher->stitch(images, result);// 使用stitch函數(shù)進(jìn)行拼接

	if (status != Stitcher::OK) return false;

	imshow("OpenCV圖像全景拼接", result);

	return true;
}

2.效果

這就是使用OpenCV 內(nèi)置Stitcher拼接出來(lái)的效果。

二、圖像全景拼接

1.特征檢測(cè)

使用方法二進(jìn)行圖像全景拼接。目前網(wǎng)上教程大致流程歸為:

1、使用特征檢測(cè)算子提取兩幅圖像的關(guān)鍵點(diǎn),然后進(jìn)行特征描述子匹配。我這里使用的是SURF算子。當(dāng)然SIFT等其他特征檢測(cè)算子也可以。

	//創(chuàng)建SURF特征檢測(cè)器
	int Hessian = 800;
	Ptr<SURF>detector = SURF::create(Hessian);

	//進(jìn)行圖像特征檢測(cè)、特征描述
	vector<KeyPoint>keypointA, keypointB;
	Mat descriptorA, descriptorB;
	detector->detectAndCompute(imageA, Mat(), keypointA, descriptorA);
	detector->detectAndCompute(imageB, Mat(), keypointB, descriptorB);

	//使用FLANN算法進(jìn)行特征描述子的匹配
	FlannBasedMatcher matcher;
	vector<DMatch>matches;
	matcher.match(descriptorA, descriptorB, matches);

 如圖為使用FLANN算法進(jìn)行特征描述子匹配的結(jié)果。我們需要把那些匹配程度高的關(guān)鍵點(diǎn)篩選出來(lái)用以下面計(jì)算兩幅圖像的單應(yīng)性矩陣。

2、篩選出匹配程度高的關(guān)鍵點(diǎn)

	double Max = 0.0;
	for (int i = 0; i < matches.size(); i++)
	{
		//float distance –>代表這一對(duì)匹配的特征點(diǎn)描述符(本質(zhì)是向量)的歐氏距離,數(shù)值越小也就說(shuō)明兩個(gè)特征點(diǎn)越相像。
		double dis = matches[i].distance;
		if (dis > Max)
		{
			Max = dis;
		}
	}

	//篩選出匹配程度高的關(guān)鍵點(diǎn)
	vector<DMatch>goodmatches;
	vector<Point2f>goodkeypointA, goodkeypointB;
	for (int i = 0; i < matches.size(); i++)
	{
		double dis = matches[i].distance;
		if (dis < 0.15*Max)
		{
			//int queryIdx –>是測(cè)試圖像的特征點(diǎn)描述符(descriptor)的下標(biāo),同時(shí)也是描述符對(duì)應(yīng)特征點(diǎn)(keypoint)的下標(biāo)。
			goodkeypointA.push_back(keypointA[matches[i].queryIdx].pt);
			//int trainIdx –> 是樣本圖像的特征點(diǎn)描述符的下標(biāo),同樣也是相應(yīng)的特征點(diǎn)的下標(biāo)。
			goodkeypointB.push_back(keypointB[matches[i].trainIdx].pt);
			goodmatches.push_back(matches[i]);
		}
	}

如圖為imageA篩選出來(lái)的關(guān)鍵點(diǎn)。

如圖為imageB篩選出來(lái)的關(guān)鍵點(diǎn)。

從上圖可以看出,我們已經(jīng)篩選出imageA,imageB共有的關(guān)鍵點(diǎn)部分。接下來(lái),我們需要使用這兩個(gè)點(diǎn)集計(jì)算兩幅圖的單應(yīng)性矩陣。

2.計(jì)算單應(yīng)性矩陣

計(jì)算單應(yīng)性變換矩陣

    //獲取圖像A到圖像B的投影映射矩陣,尺寸為3*3
    Mat H = findHomography(goodkeypointA, goodkeypointB, RANSAC);
    Mat M = (Mat_<double>(3, 3) << 1.0, 0, imageA.cols, 0, 1.0, 0, 0, 0, 1.0);
    Mat Homo = M * H;

3.透視變換

根據(jù)計(jì)算出來(lái)的單應(yīng)性矩陣對(duì)imageA進(jìn)行透視變換

    //進(jìn)行透視變換
    Mat DstImg;
    warpPerspective(imageA, DstImg, Homo, Size(imageB.cols + imageA.cols, imageB.rows));
    imshow("透視變換", DstImg);

如圖所示為imageA進(jìn)行透視變換得到的結(jié)果。

4.圖像拼接

根據(jù)上述操作,我們已經(jīng)得到了經(jīng)透視變換的imageA,接下來(lái)只需將imageA與imageB拼接起來(lái)就可以了。

    imageB.copyTo(DstImg(Rect(imageA.cols, 0, imageB.cols, imageB.rows)));
    imshow("圖像全景拼接", DstImg);

5.功能源碼

bool Image_Stitching(Mat imageA, Mat imageB, bool draw)
{
	//創(chuàng)建SURF特征檢測(cè)器
	int Hessian = 800;
	Ptr<SURF>detector = SURF::create(Hessian);

	//進(jìn)行圖像特征檢測(cè)、特征描述
	vector<KeyPoint>keypointA, keypointB;
	Mat descriptorA, descriptorB;
	detector->detectAndCompute(imageA, Mat(), keypointA, descriptorA);
	detector->detectAndCompute(imageB, Mat(), keypointB, descriptorB);

	//使用FLANN算法進(jìn)行特征描述子的匹配
	FlannBasedMatcher matcher;
	vector<DMatch>matches;
	matcher.match(descriptorA, descriptorB, matches);

	double Max = 0.0;
	for (int i = 0; i < matches.size(); i++)
	{
		//float distance –>代表這一對(duì)匹配的特征點(diǎn)描述符(本質(zhì)是向量)的歐氏距離,數(shù)值越小也就說(shuō)明兩個(gè)特征點(diǎn)越相像。
		double dis = matches[i].distance;
		if (dis > Max)
		{
			Max = dis;
		}
	}

	//篩選出匹配程度高的關(guān)鍵點(diǎn)
	vector<DMatch>goodmatches;
	vector<Point2f>goodkeypointA, goodkeypointB;
	for (int i = 0; i < matches.size(); i++)
	{
		double dis = matches[i].distance;
		if (dis < 0.15*Max)
		{
			//int queryIdx –>是測(cè)試圖像的特征點(diǎn)描述符(descriptor)的下標(biāo),同時(shí)也是描述符對(duì)應(yīng)特征點(diǎn)(keypoint)的下標(biāo)。
			goodkeypointA.push_back(keypointA[matches[i].queryIdx].pt);
			//int trainIdx –> 是樣本圖像的特征點(diǎn)描述符的下標(biāo),同樣也是相應(yīng)的特征點(diǎn)的下標(biāo)。
			goodkeypointB.push_back(keypointB[matches[i].trainIdx].pt);
			goodmatches.push_back(matches[i]);
		}
	}

	if (draw)
	{
		Mat result;
		drawMatches(imageA, keypointA, imageB, keypointB, goodmatches, result);
		imshow("特征匹配", result);

		Mat temp_A = imageA.clone();
		for (int i = 0; i < goodkeypointA.size(); i++)
		{
			circle(temp_A, goodkeypointA[i], 3, Scalar(0, 255, 0), -1);
		}
		imshow("goodkeypointA", temp_A);

		Mat temp_B = imageB.clone();
		for (int i = 0; i < goodkeypointB.size(); i++)
		{
			circle(temp_B, goodkeypointB[i], 3, Scalar(0, 255, 0), -1);
		}
		imshow("goodkeypointB", temp_B);
	}

	//findHomography計(jì)算單應(yīng)性矩陣至少需要4個(gè)點(diǎn)
	/*
	計(jì)算多個(gè)二維點(diǎn)對(duì)之間的最優(yōu)單映射變換矩陣H(3x3),使用MSE或RANSAC方法,找到兩平面之間的變換矩陣
	*/
	if (goodkeypointA.size() < 4 || goodkeypointB.size() < 4) return false;


	//獲取圖像A到圖像B的投影映射矩陣,尺寸為3*3
	Mat H = findHomography(goodkeypointA, goodkeypointB, RANSAC);
	Mat M = (Mat_<double>(3, 3) << 1.0, 0, imageA.cols, 0, 1.0, 0, 0, 0, 1.0);
	Mat Homo = M * H;


	//進(jìn)行透視變換
	Mat DstImg;
	warpPerspective(imageA, DstImg, Homo, Size(imageB.cols + imageA.cols, imageB.rows));
	imshow("透視變換", DstImg);

	imageB.copyTo(DstImg(Rect(imageA.cols, 0, imageB.cols, imageB.rows)));
	imshow("圖像全景拼接", DstImg);

	return true;
}

6.效果

最終拼接效果如圖所示。

三、源碼

#include<iostream>
#include<opencv2/opencv.hpp>
#include<opencv2/xfeatures2d.hpp>
#include<opencv2/stitching.hpp>
using namespace std;
using namespace cv;
using namespace cv::xfeatures2d;

//1、使用特征檢測(cè)算法找到兩張圖像中相似的點(diǎn),計(jì)算變換矩陣
//2、將A透視變換后得到的圖片與B拼接


bool Image_Stitching(Mat imageA, Mat imageB, bool draw)
{
	//創(chuàng)建SURF特征檢測(cè)器
	int Hessian = 800;
	Ptr<SURF>detector = SURF::create(Hessian);

	//進(jìn)行圖像特征檢測(cè)、特征描述
	vector<KeyPoint>keypointA, keypointB;
	Mat descriptorA, descriptorB;
	detector->detectAndCompute(imageA, Mat(), keypointA, descriptorA);
	detector->detectAndCompute(imageB, Mat(), keypointB, descriptorB);

	//使用FLANN算法進(jìn)行特征描述子的匹配
	FlannBasedMatcher matcher;
	vector<DMatch>matches;
	matcher.match(descriptorA, descriptorB, matches);

	double Max = 0.0;
	for (int i = 0; i < matches.size(); i++)
	{
		//float distance –>代表這一對(duì)匹配的特征點(diǎn)描述符(本質(zhì)是向量)的歐氏距離,數(shù)值越小也就說(shuō)明兩個(gè)特征點(diǎn)越相像。
		double dis = matches[i].distance;
		if (dis > Max)
		{
			Max = dis;
		}
	}

	//篩選出匹配程度高的關(guān)鍵點(diǎn)
	vector<DMatch>goodmatches;
	vector<Point2f>goodkeypointA, goodkeypointB;
	for (int i = 0; i < matches.size(); i++)
	{
		double dis = matches[i].distance;
		if (dis < 0.15*Max)
		{
			//int queryIdx –>是測(cè)試圖像的特征點(diǎn)描述符(descriptor)的下標(biāo),同時(shí)也是描述符對(duì)應(yīng)特征點(diǎn)(keypoint)的下標(biāo)。
			goodkeypointA.push_back(keypointA[matches[i].queryIdx].pt);
			//int trainIdx –> 是樣本圖像的特征點(diǎn)描述符的下標(biāo),同樣也是相應(yīng)的特征點(diǎn)的下標(biāo)。
			goodkeypointB.push_back(keypointB[matches[i].trainIdx].pt);
			goodmatches.push_back(matches[i]);
		}
	}

	if (draw)
	{
		Mat result;
		drawMatches(imageA, keypointA, imageB, keypointB, goodmatches, result);
		imshow("特征匹配", result);

		Mat temp_A = imageA.clone();
		for (int i = 0; i < goodkeypointA.size(); i++)
		{
			circle(temp_A, goodkeypointA[i], 3, Scalar(0, 255, 0), -1);
		}
		imshow("goodkeypointA", temp_A);

		Mat temp_B = imageB.clone();
		for (int i = 0; i < goodkeypointB.size(); i++)
		{
			circle(temp_B, goodkeypointB[i], 3, Scalar(0, 255, 0), -1);
		}
		imshow("goodkeypointB", temp_B);
	}

	//findHomography計(jì)算單應(yīng)性矩陣至少需要4個(gè)點(diǎn)
	/*
	計(jì)算多個(gè)二維點(diǎn)對(duì)之間的最優(yōu)單映射變換矩陣H(3x3),使用MSE或RANSAC方法,找到兩平面之間的變換矩陣
	*/
	if (goodkeypointA.size() < 4 || goodkeypointB.size() < 4) return false;


	//獲取圖像A到圖像B的投影映射矩陣,尺寸為3*3
	Mat H = findHomography(goodkeypointA, goodkeypointB, RANSAC);
	Mat M = (Mat_<double>(3, 3) << 1.0, 0, imageA.cols, 0, 1.0, 0, 0, 0, 1.0);
	Mat Homo = M * H;


	//進(jìn)行透視變換
	Mat DstImg;
	warpPerspective(imageA, DstImg, Homo, Size(imageB.cols + imageA.cols, imageB.rows));
	imshow("透視變換", DstImg);

	imageB.copyTo(DstImg(Rect(imageA.cols, 0, imageB.cols, imageB.rows)));
	imshow("圖像全景拼接", DstImg);

	return true;
}


bool OpenCV_Stitching(Mat imageA, Mat imageB)
{
	vector<Mat>images;
	images.push_back(imageA);
	images.push_back(imageB);

	Ptr<Stitcher>stitcher = Stitcher::create();

	Mat result;
	Stitcher::Status status = stitcher->stitch(images, result);// 使用stitch函數(shù)進(jìn)行拼接

	if (status != Stitcher::OK) return false;

	imshow("OpenCV圖像全景拼接", result);

	return true;
}

int main()
{

	Mat imageA = imread("image1.jpg");
	Mat imageB = imread("image2.jpg");
	if (imageA.empty() || imageB.empty())
	{
		cout << "No Image!" << endl;
		system("pause");
		return -1;
	}

	if (!Image_Stitching(imageA, imageB, true))
	{
		cout << "can not stitching the image!" << endl;
	}

	if (!OpenCV_Stitching(imageA, imageB))
	{
		cout << "can not stitching the image!" << endl;
	}

	waitKey(0);
	system("pause");
	return 0;
}


總結(jié)

本文使用OpenCV C++進(jìn)行圖像全景拼接,關(guān)鍵步驟有以下幾點(diǎn)。

1、使用特征檢測(cè)算子提取兩幅圖像的關(guān)鍵點(diǎn),然后進(jìn)行特征描述子匹配。

2、篩選出匹配程度高的關(guān)鍵點(diǎn)計(jì)算兩幅圖的單應(yīng)性矩陣。

3、利用計(jì)算出來(lái)的單應(yīng)性矩陣對(duì)其中一張圖片進(jìn)行透視變換。

4、將透視變換的圖片與另一張圖片進(jìn)行拼接。

以上就是C++ OpenCV實(shí)戰(zhàn)之圖像全景拼接的詳細(xì)內(nèi)容,更多關(guān)于 OpenCV圖像全景拼接的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論