1. 程式人生 > >opencv顯示影象的傅立葉譜影象(頻譜)原始碼詳解

opencv顯示影象的傅立葉譜影象(頻譜)原始碼詳解

1. 頻率域

通過傅立葉變換連線空間域和頻率域,其是頻率域濾波的基礎。這裡將結合opencv中的sample文件(\source\sample目錄下的dft.cpp),對一副灰度影象進行傅立葉變換,並顯示其傅立葉譜影象。

2. 傅立葉譜顯示

#include<opencv.hpp>
#include<iostream>

int main(void)
{
	//載入一副灰度影象
	cv::Mat src=cv::imread("D:/Opencv Picture/Lena.jpg", CV_LOAD_IMAGE_GRAYSCALE);
	if (!src.data)
	{
		std::cout << "Image Load Fail!!!" << "\n";
		return 1;
	}
	cv::imshow("SRC", src);

	//擴充影象尺寸到最佳尺寸,邊界用0填充
	int r = cv::getOptimalDFTSize(src.rows);
	int c = cv::getOptimalDFTSize(src.cols);
	cv::Mat padded;
	cv::copyMakeBorder(src, padded, 0, r - src.rows, 0, c - src.cols, cv::BORDER_CONSTANT,cv::Scalar::all(0));

	//為傅立葉變換的結果(複數,包含實部和虛部,所以需要建立一個二維的陣列)分配儲存空間,
	//需要用至少float型來儲存
	//最後將二維數組合併為二通道--傅立葉變換需要
	cv::Mat dst1[] = { cv::Mat_<float>(padded), cv::Mat::zeros(padded.size(), CV_32F) };
	cv::Mat dst2;
	cv::merge(dst1,2, dst2);

	//傅立葉變換,結果依舊儲存在dst2中
	cv::dft(dst2, dst2);

	//將複數換算成幅值
	cv::split(dst2, dst1);//把二通道影象分解為二維陣列,儲存到dst1中,dst1[0]中存放的為實部
	cv::magnitude(dst1[0], dst1[1], dst1[0]);//結果存放在dst1[0]中
	cv::Mat magnitudeImage = dst1[0];


	//對數尺度縮放以便於顯示
	//計算log(1 + sqrt(Re(DFT(dst2))**2 + Im(DFT(dst2))**2))
	magnitudeImage += cv::Scalar::all(1);
	cv::log(magnitudeImage, magnitudeImage);


	//剪下和重分佈幅度圖象限
	//若有奇數行或奇數列,進行頻譜裁剪
	magnitudeImage = magnitudeImage(cv::Rect(0, 0, magnitudeImage.cols & -2, magnitudeImage.rows & -2));//任何一個數&-2的結果一定是偶數

	//重新排列傅立葉影象的象限,使原點位於影象中心
	int cx = magnitudeImage.cols / 2;
	int cy = magnitudeImage.rows / 2;
	cv::Mat q0(magnitudeImage(cv::Rect(0, 0, cx, cy)));
	cv::Mat q1(magnitudeImage(cv::Rect(cx, 0, cx, cy)));
	cv::Mat q2(magnitudeImage(cv::Rect(0, cy, cx, cy)));
	cv::Mat q3(magnitudeImage(cv::Rect(cy, cy, cx, cy)));

	cv::Mat tmp;
	q0.copyTo(tmp);
	q3.copyTo(q0);
	tmp.copyTo(q3);
	q1.copyTo(tmp);
	q2.copyTo(q1);
	tmp.copyTo(q2);


	//將幅度值歸一化到0~1之間,這是因為magnitudeImage中的資料型別是浮點型,這時用imshow()來顯示函式,會將畫素值乘於255,因此需要歸一化到0~1之間
	cv:normalize(magnitudeImage, magnitudeImage, 0, 1, cv::NORM_MINMAX);

	//顯示最後的頻譜
	cv::imshow("spectrum magnitude", magnitudeImage);

	cv::waitKey();

	return 0;
}

3. 顯示結果

執行結果如下。


下面來一步步看看,各個步驟的作用。如果不進行歸一化處理的結果如下圖所示,整個畫面發白,根本看不到任何資訊。


如果不進行象限調整,結果如下,低頻出現在圖片的四個角(四角發亮),而通過調整之後將低頻調整到了原點附近。


如果不進行尺度調整,可以發現對比度不高,僅僅能看到中心一個亮點,說明尺度調整後,能顯示更多細節。