亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

opencv實踐項目之圖像拼接詳細(xì)步驟

 更新時間:2023年05月09日 10:05:28   作者:wyw0000  
OpenCV的應(yīng)用領(lǐng)域非常廣泛,包括圖像拼接、圖像降噪、產(chǎn)品質(zhì)檢、人機交互、人臉識別、動作識別、動作跟蹤、無人駕駛等,下面這篇文章主要給大家介紹了關(guān)于opencv實踐項目之圖像拼接的相關(guān)資料,需要的朋友可以參考下

1.簡介

圖像拼接是計算機視覺中最成功的應(yīng)用之一。如今,很難找到不包含此功能的手機或圖像處理API。在本文中,我們將討論如何使用OpenCV進(jìn)行圖像拼接。也就是,給定兩張共享某些公共區(qū)域的圖像,目標(biāo)是“縫合”它們并創(chuàng)建一個全景圖像場景。當(dāng)然也可以是給定多張圖像,但是總會轉(zhuǎn)換成兩張共享某些公共區(qū)域圖像拼接的問題。

2. 步驟

拼接的兩幅圖

2.1 特征檢測與提取

給定上述一對圖像,我們希望將它們縫合以創(chuàng)建全景場景。重要的是要注意,兩個圖像都需要有一些公共區(qū)域。當(dāng)然,我們上面給出的兩張圖像時比較理想的,有時候兩個圖像雖然具有公共區(qū)域,但是同樣還可能存在縮放、旋轉(zhuǎn)、來自不同相機等因素的影響。但是無論哪種情況,我們都需要檢測圖像中的特征點。

2.2 關(guān)鍵點檢測

最初的并且可能是幼稚的方法是使用諸如Harris Corners之類的算法來提取關(guān)鍵點。然后,我們可以嘗試基于某種相似性度量(例如歐幾里得距離)來匹配相應(yīng)的關(guān)鍵點。眾所周知,角點具有一個不錯的特性:角點不變。這意味著,一旦檢測到角點,即使旋轉(zhuǎn)圖像,該角點仍將存
在。

但是,如果我們旋轉(zhuǎn)然后縮放圖像怎么辦?在這種情況下,我們會很困難,因為角點的大小不變。也就是說,如果我們放大圖像,先前檢測到的角可能會變成一條線!

總而言之,我們需要旋轉(zhuǎn)和縮放不變的特征。那就是更強大的方法(如SIFT,SURF和ORB)。

2.3 關(guān)鍵點和描述符

諸如SIFT和SURF之類的方法試圖解決角點檢測算法的局限性。通常,角點檢測器算法使用固定大小的內(nèi)核來檢測圖像上的感興趣區(qū)域(角)。不難看出,當(dāng)我們縮放圖像時,該內(nèi)核可能變得太小或太大。為了解決此限制,諸如SIFT之類的方法使用高斯差分(DoD)。想法是將DoD應(yīng)用于同一圖像的不同縮放版本。它還使用相鄰像素信息來查找和完善關(guān)鍵點和相應(yīng)的描
述符。

首先,我們需要加載2個圖像,一個查詢圖像和一個訓(xùn)練圖像。最初,我們首先從兩者中提取關(guān)鍵點和描述符。通過使用OpenCV detectAndCompute()函數(shù),我們可以一步完成它。請注意,為了使用detectAndCompute(),我們需要一個關(guān)鍵點檢測器和描述符對象的實例。它可以是ORB,SIFT或SURF等。此外,在將圖像輸入給detectAndCompute()之前,我們將其轉(zhuǎn)換為灰度。

代碼:

void detectAndDescribe(const cv::Mat &image, Extract_Features_Method method, std::vector<KeyPoint> &keypoints, cv::Mat &descriptor)
{
	switch (method)
	{
	case Extract_Features_Method::METHOD_SIFT:
	{
		Ptr<cv::SIFT> detector = cv::SIFT::create(800);
		detector->detectAndCompute(image, cv::Mat(), keypoints, descriptor);
		break;
	}
	case Extract_Features_Method::METHOD_SURF:
	{
		int minHessian = 400;
		Ptr<cv::xfeatures2d::SURF> detector = cv::xfeatures2d::SURF::create(minHessian);
		detector->detectAndCompute(image, cv::Mat(), keypoints, descriptor);
		break;
	}
	case Extract_Features_Method::METHOD_BRISK:
	{
		int minHessian = 400;
		
		Ptr<BRISK> detector = BRISK::create(minHessian);
		detector->detectAndCompute(image, cv::Mat(), keypoints, descriptor);
		break;
	}
	case Extract_Features_Method::METHOD_ORB:
	{
		int minHessian = 400;

		Ptr<ORB> detector = ORB::create(minHessian);
		detector->detectAndCompute(image, cv::Mat(), keypoints, descriptor);
		break;
	}
	default:
		break;
	}
}

我們?yōu)閮蓚€圖像都設(shè)置了一組關(guān)鍵點和描述符。如果我們使用SIFT作為特征提取器,它將為每個關(guān)鍵點返回一個128維特征向量。如果選擇SURF,我們將獲得64維特征向量。

2.4 特征匹配

現(xiàn)在,我們想比較兩組特征,并盡可能顯示更多相似性的特征點對。使 用 OpenCV , 特 征 點 匹 配 需 要 Matcher 對 象 。 在 這 里 , 我 們 探 索 兩 種 方 式 : 暴 力 匹 配 器(BruteForce)和KNN(k最近鄰)。

BruteForce(BF)Matcher的作用恰如其名。給定2組特征(來自圖像A和圖像B),將A組的每個特征與B組的所有特征進(jìn)行比較。默認(rèn)情況下,BF Matcher計算兩點之間的歐式距離。因此,對于集合A中的每個特征,它都會返回集合B中最接近的特征。對于SIFT和SURF,OpenCV建議使用歐幾里得距離。對于ORB和BRISK等其他特征提取器,建議使用漢明距離。我們要使用OpenCV創(chuàng)建BruteForce Matcher,一般情況下,我們只需要指定2個參數(shù)即可。第一個是距離度量。第二個是是否進(jìn)行交叉檢測的布爾參數(shù)。

具體代碼如下:

auto createMatcher(Extract_Features_Method method, bool crossCheck)
{
	if (method == Extract_Features_Method::METHOD_SIFT || method == Extract_Features_Method::METHOD_SURF)
	{
		return cv::BFMatcher(cv::NORM_L2, crossCheck);
	}
	return cv::BFMatcher(cv::NORM_HAMMING, crossCheck);
}

交叉檢查布爾參數(shù)表示這兩個特征是否具有相互匹配才視為有效。換句話說,對于被認(rèn)為有效的一對特征(f1,f2),f1需要匹配f2,f2也必須匹配f1作為最接近的匹配。此過程可確保提供更強大的匹配功能集,這在原始SIFT論文中進(jìn)行了描述。

但是,對于要考慮多個候選匹配的情況,可以使用基于KNN的匹配過程。KNN不會返回給定特征的單個最佳匹配,而是返回k個最佳匹配。需要注意的是,k的值必須由用戶預(yù)先定義。如我們所料,KNN提供了更多的候選功能。但是,在進(jìn)一步操作之前,我們需要確保所有這些匹配對都具有魯棒性。

2.5 比率測試

為了確保KNN返回的特征具有很好的可比性,SIFT論文的作者提出了一種稱為比率測試的技術(shù)。一般情況下,我們遍歷KNN得到匹配對,之后再執(zhí)行距離測試。對于每對特征(f1,f2),如果f1和f2之間的距離在一定比例之內(nèi),則將其保留,否則將其丟棄。同樣,必須手動選擇比率值。

本質(zhì)上,比率測試與BruteForce Matcher的交叉檢查選項具有相同的作用。兩者都確保一對檢測到的特征確實足夠接近以至于被認(rèn)為是相似的。下面2個圖顯示了BF和KNN Matcher在SIFT特征上的匹配結(jié)果。我們選擇僅顯示100個匹配點以清晰顯示。

需要注意的是,即使做了多種篩選來保證匹配的正確性,也無法完全保證特征點完全正確匹配。盡管如此,Matcher算法仍將為我們提供兩幅圖像中最佳(更相似)的特征集。接下來,我們利用這些點來計算將兩個圖像的匹配點拼接在一起的變換矩陣。

這種變換稱為單應(yīng)矩陣。簡而言之,單應(yīng)性是一個3x3矩陣,可用于許多應(yīng)用中,例如相機姿態(tài)估計,透視校正和圖像拼接。它將點從一個平面(圖像)映射到另一平面。

2.6 估計單應(yīng)性

隨機采樣一致性(RANSAC)是用于擬合線性模型的迭代算法。與其他線性回歸器不同,RANSAC被設(shè)計為對異常值具有魯棒性。

像線性回歸這樣的模型使用最小二乘估計將最佳模型擬合到數(shù)據(jù)。但是,普通最小二乘法對異常值非常敏感。如果異常值數(shù)量很大,則可能會失敗。RANSAC通過僅使用數(shù)據(jù)中的一組數(shù)據(jù)估計參數(shù)來解決此問題。下圖顯示了線性回歸和RANSAC之間的比較。需要注意數(shù)據(jù)集包含相當(dāng)多的離群值。

我們可以看到線性回歸模型很容易受到異常值的影響。那是因為它試圖減少平均誤差。因此,它傾向于支持使所有數(shù)據(jù)點到模型本身的總距離最小的模型。包括異常值。相反,RANSAC僅將模型擬合為被識別為點的點的子集。這個特性對我們的用例非常重要。在這里,我們將使用RANSAC來估計單應(yīng)矩陣。事實證明,單應(yīng)矩陣對我們傳遞給它的數(shù)據(jù)質(zhì)量非常敏感。因此,重要的是要有一種算法(RANSAC),該算法可以從不屬于數(shù)據(jù)分布的點中篩選出明顯屬于數(shù)據(jù)分布的點。

估計了單應(yīng)矩陣后,我們需要將其中一張圖像變換到一個公共平面上。在這里,我們將對其中一張圖像應(yīng)用透視變換。透視變換可以組合一個或多個操作,例如旋轉(zhuǎn),縮放,平移或剪切。我們可以使用OpenCV warpPerspective()函數(shù)。它以圖像和單應(yīng)矩陣作為輸入。

3. 完整代碼

typedef enum
{
	METHOD_SIFT,
	METHOD_SURF,
	METHOD_BRISK,
	METHOD_ORB
}Extract_Features_Method;

void detectAndDescribe(const cv::Mat &image, Extract_Features_Method method, std::vector<KeyPoint> &keypoints, cv::Mat &descriptor)
{
	switch (method)
	{
	case Extract_Features_Method::METHOD_SIFT:
	{
		Ptr<cv::SIFT> detector = cv::SIFT::create(800);
		detector->detectAndCompute(image, cv::Mat(), keypoints, descriptor);
		break;
	}
	case Extract_Features_Method::METHOD_SURF:
	{
		int minHessian = 400;
		Ptr<cv::xfeatures2d::SURF> detector = cv::xfeatures2d::SURF::create(minHessian);
		detector->detectAndCompute(image, cv::Mat(), keypoints, descriptor);
		break;
	}
	case Extract_Features_Method::METHOD_BRISK:
	{
		int minHessian = 400;
		
		Ptr<BRISK> detector = BRISK::create(minHessian);
		detector->detectAndCompute(image, cv::Mat(), keypoints, descriptor);
		break;
	}
	case Extract_Features_Method::METHOD_ORB:
	{
		int minHessian = 400;

		Ptr<ORB> detector = ORB::create(minHessian);
		detector->detectAndCompute(image, cv::Mat(), keypoints, descriptor);
		break;
	}
	default:
		break;
	}
}

auto createMatcher(Extract_Features_Method method, bool crossCheck)
{

	if (method == Extract_Features_Method::METHOD_SIFT || method == Extract_Features_Method::METHOD_SURF)
	{
		return cv::BFMatcher(cv::NORM_L2, crossCheck);
	}

	return cv::BFMatcher(cv::NORM_HAMMING, crossCheck);
}

int main()//stich_demo()
{
	string imgPath1 = "E:\\code\\Yolov5_Tensorrt_Win10-master\\pictures\\stich1.jpg";
	string imgPath2 = "E:\\code\\Yolov5_Tensorrt_Win10-master\\pictures\\stich2.jpg";
	Mat img1 = imread(imgPath1, IMREAD_GRAYSCALE);
	Mat img2 = imread(imgPath2, IMREAD_GRAYSCALE);

	std::vector<cv::KeyPoint> keypoint1;
	cv::Mat describe1;
	detectAndDescribe(img1, Extract_Features_Method::METHOD_SIFT, keypoint1, describe1);

	std::vector<cv::KeyPoint> keypoint2;
	cv::Mat describe2;
	detectAndDescribe(img2, Extract_Features_Method::METHOD_SIFT, keypoint2, describe2);

	auto matcher = createMatcher(Extract_Features_Method::METHOD_SIFT, false);

	vector<DMatch> firstMatches;
	matcher.match(describe1, describe2, firstMatches);
	
	vector<cv::Point2f> points1, points2;
	for (vector<DMatch>::const_iterator it = firstMatches.begin(); it != firstMatches.end(); ++it)
	{
		points1.push_back(keypoint1.at(it->queryIdx).pt);
		points2.push_back(keypoint2.at(it->trainIdx).pt);
	}

	auto inliers = vector<uchar>(keypoint1.size(), 0);
	cv::Mat h12 = cv::findHomography(points1, points2, inliers, RANSAC, 1.0);
	Mat h21;
	invert(h12, h21, DECOMP_LU);
	
	Mat canvas;
	Mat img1_color = imread(imgPath1);
	Mat img2_color = imread(imgPath2);

	warpPerspective(img2_color, canvas, h21, Size(img1.cols * 2, img1.rows));
	imshow("warp", canvas);
	img1_color.copyTo(canvas(Range::all(), Range(0, img1.cols)));

	imshow("canvas", canvas);

	waitKey(0);

	return 0;
}

生成的全景圖像如下所示。如我們所見,結(jié)果中包含了兩個圖像中的內(nèi)容。另外,我們可以看到一些與照明條件和圖像邊界邊緣效應(yīng)有關(guān)的問題。理想情況下,我們可以執(zhí)行一些處理技術(shù)來標(biāo)準(zhǔn)化亮度,例如直方圖匹配,這會使結(jié)果看起來更真實和自然一些。

本文參考Python視覺實戰(zhàn)項目71講,將其中的python代碼移植到c++

總結(jié)

到此這篇關(guān)于opencv實踐項目之圖像拼接詳細(xì)步驟的文章就介紹到這了,更多相關(guān)opencv圖像拼接內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 使用Python從有道詞典網(wǎng)頁獲取單詞翻譯

    使用Python從有道詞典網(wǎng)頁獲取單詞翻譯

    這篇文章主要介紹了使用Python從有道詞典網(wǎng)頁獲取單詞翻譯的相關(guān)資料,需要的朋友可以參考下
    2016-07-07
  • Python的凈值數(shù)據(jù)接口調(diào)用示例分享

    Python的凈值數(shù)據(jù)接口調(diào)用示例分享

    這篇文章主要介紹了Python的凈值數(shù)據(jù)接口調(diào)用示例分享的相關(guān)資料,需要的朋友可以參考下
    2016-03-03
  • python SocketServer源碼深入解讀

    python SocketServer源碼深入解讀

    這篇文章主要介紹了python SocketServer源碼深入解讀,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-09-09
  • PyQt5實現(xiàn)簡單數(shù)據(jù)標(biāo)注工具

    PyQt5實現(xiàn)簡單數(shù)據(jù)標(biāo)注工具

    這篇文章主要為大家詳細(xì)介紹了PyQt5實現(xiàn)簡單數(shù)據(jù)標(biāo)注工具,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-03-03
  • Python面向?qū)ο笾甒eb靜態(tài)服務(wù)器

    Python面向?qū)ο笾甒eb靜態(tài)服務(wù)器

    這篇文章主要為大家詳細(xì)介紹了Python面向?qū)ο笾甒eb靜態(tài)服務(wù)器,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-09-09
  • python使用openpyxl庫處理Excel文件詳細(xì)教程

    python使用openpyxl庫處理Excel文件詳細(xì)教程

    這篇文章主要給大家介紹了關(guān)于python使用openpyxl庫處理Excel文件詳細(xì)教程的相關(guān)資料,openpyxl屬于第三方模塊,在python中用來處理excel文件,可以對excel進(jìn)行的操作有讀寫、修改、調(diào)整樣式及插入圖片等,需要的朋友可以參考下
    2023-11-11
  • pyqt5 QlistView列表顯示的實現(xiàn)示例

    pyqt5 QlistView列表顯示的實現(xiàn)示例

    這篇文章主要介紹了pyqt5 QlistView列表顯示的實現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-03-03
  • 使用python進(jìn)行波形及頻譜繪制的方法

    使用python進(jìn)行波形及頻譜繪制的方法

    今天小編就為大家分享一篇使用python進(jìn)行波形及頻譜繪制的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-06-06
  • Python實現(xiàn)模擬錕斤拷等各類亂碼詳解

    Python實現(xiàn)模擬錕斤拷等各類亂碼詳解

    說到亂碼問題就不得不提到錕斤拷,這算是非常常見的一種亂碼形式,那么它到底是經(jīng)過何種錯誤操作產(chǎn)生的呢?本文我們就來一步步探究
    2023-02-02
  • Python時間獲取及轉(zhuǎn)換知識匯總

    Python時間獲取及轉(zhuǎn)換知識匯總

    這篇文章主要介紹了Python時間獲取及轉(zhuǎn)換知識匯總的相關(guān)資料,非常不錯,具有參考借鑒價值,需要的朋友可以參考下
    2017-01-01

最新評論