首頁 > 軟體

C++ OpenCV學習之影象金字塔與影象融合詳解

2022-03-02 10:00:11

1 金字塔

平時你聽到、見到的金字塔是什麼樣的?

這樣?

還是這樣?

實際上除了這些,還有影象金字塔

 

影象金字塔有什麼用?為什麼要稱作影象金字塔?本文帶你研究這些問題。

2 什麼是影象金字塔?

正如生物視覺系統會處理分層次的尺寸一樣,計算機視覺系統實現多解析度影象處理的基礎是影象金字塔。

考慮這樣一個場景:輸入系統一幅影象來檢測人臉。由於事先並不知道人臉在這張圖片中可能的尺寸,所以需要根據輸入生成一個不同大小影象組成的金字塔(應用時常用向量儲存),掃描不同層次來檢測可能的人臉。

此外,影象金字塔在保持細節的條件下進行影象融合等多尺度編輯操作非常有用。

影象金字塔分為兩種:

高斯金字塔

高斯金字塔是最基本的影象金字塔,用於獲得原影象尺度連續的的降取樣序列。高斯金字塔共分O組(Octave),每組分為S層(Layer)。組內各層影象解析度相同但尺度逐層遞增;組間影象按隔點降取樣取得。

拉普拉斯金字塔

拉普拉斯金字塔通過高斯差分得到殘差影象序列,用於影象重建、影象融合、特徵點檢測等。具體做法如圖所示:構造高斯金字塔,每組影象內相鄰兩層相減得到殘差影象序列,從而得到拉普拉斯金字塔。所以高斯金字塔每組有s+3層,而拉普拉斯金字塔每組只有s層。

3 影象金字塔有什麼用?

前面已經提到,影象金字塔的作用主要有:

  • 影象重建
  • 影象多尺度特徵檢測
  • 影象修復
  • 影象融合

下面給出一個基於影象金字塔的影象融合演演算法。

1.選擇待融合影象A與B,以及融合掩碼M,並重取樣使之具有相同大小;

2.分別取得A、B的拉普拉斯金字塔,以及M的高斯金字塔;

3.使用M的高斯金字塔作為加權,對A、B的每層特徵進行融合,得到融合金字塔;

4.融合金字塔仍為拉普拉斯金字塔,對其影象重建得到融合影象。

上面的圖可能有點抽象,看看下面的例子。

4 OpenCV實戰影象金字塔

主函數非常簡單易懂

int main()
{
    Mat img_1 = imread("1.jpg", 1);
    Mat img_2 = imread("2.jpg", 1);
    Mat dstImg;
    imgFusion(img_1, img_2, dstImg, 0.2);
    waitKey(0);
    return 0;
}

試試效果

原圖

融合效果圖

是不是毫無違和感?其中關鍵的融合函數imgFusion()具體是如何實現的呢?

void imgFusion(Mat leftImg, Mat rightImg, Mat& dstImg, float threshold)
{
	vector<Mat> gaussPyrLeft, gaussPyrRight, laplacePyrLeft, laplacePyrRight;		// 宣告高斯金字塔資料結構
	vector<Mat> maskGaussPyr;														// 宣告掩碼的高斯金字塔
	vector<Mat> blendLapPyr;														// 宣告融合拉普拉斯金字塔
	Mat imgHighest;																	// 宣告影象融合的起點影象
	Mat mask = Mat::zeros(PYRHEIGHT, PYRWIDTH, CV_32FC1);							// 構造掩碼,大小與金字塔原影象相同
	mask(Range::all(), Range(mask.cols * threshold, mask.cols)) = 1.0;
	cvtColor(mask, mask, COLOR_GRAY2BGR);											// 將掩碼顏色通道拓展,以適配原影象
	buildGaussPyr(mask, maskGaussPyr, 3);											// 建立掩碼的高斯金字塔

	resize(leftImg, leftImg, Size(PYRWIDTH, PYRHEIGHT));
	resize(rightImg, rightImg, Size(PYRWIDTH, PYRHEIGHT));

	leftImg.convertTo(leftImg, CV_32F);		//轉換成CV_32F, 用於和mask型別匹配,且CV_32F 型別精度高, 有利於計算
	rightImg.convertTo(rightImg, CV_32F);

	// 建立高斯金字塔與拉普拉斯金字塔
	buildGaussPyr(leftImg, gaussPyrLeft, 3);
	buildGaussPyr(rightImg, gaussPyrRight, 3);
	buildLaplacePyr(gaussPyrLeft, laplacePyrLeft, 3);
	buildLaplacePyr(gaussPyrRight, laplacePyrRight, 3);

	// 確定起點影象
	imgHighest = gaussPyrLeft.back().mul(maskGaussPyr.back()) +
		((gaussPyrRight.back()).mul(Scalar(1.0, 1.0, 1.0) - maskGaussPyr.back()));

	// 融合拉普拉斯金字塔
	blendLaplacePyr(laplacePyrLeft, laplacePyrRight, maskGaussPyr, blendLapPyr);

	// 融合影象重建
	dstImg = imgLaplaceBlend(imgHighest, blendLapPyr);
	dstImg.convertTo(dstImg, CV_8UC3);
	imshow("imgProcess::seamOpt_laplace", dstImg);
}

完整原始碼 提取碼:1234

到此這篇關於C++ OpenCV學習之影象金字塔與影象融合詳解的文章就介紹到這了,更多相關C++ OpenCV影象金字塔內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com