1. 程式人生 > >OpenCV學習筆記(六)離散傅立葉變換

OpenCV學習筆記(六)離散傅立葉變換

離散傅立葉變換:

傅立葉變換將講時域訊號分解為不同頻率的正弦訊號或餘弦訊號疊加之和,時域分析只能反映訊號的幅值隨時間變化得情況,除單頻率分量的簡諧波外,很難對資訊頻率的組成及各頻率分量的大小進行詳細分析,而訊號頻譜分析提供了比時域訊號波形更直觀、更豐富的資訊。在實際的影象處理中,我們僅僅使用了影象幅度資訊,因為幅度影象半酣了我們需要的原影象幾乎所有的幾何資訊。然和,如果你想通過修改幅度影象或者相點陣圖像的方法來間接修改原空間影象,你需要使用逆傅立葉變換來得到修改後的空間影象,這樣你就必須同時保留幅度影象和相點陣圖像。

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
using namespace cv;
using namespace std;
Mat DFT(Mat srcImage)
{
	Mat srcGray;
	cvtColor(srcImage, srcGray, CV_RGB2GRAY);//灰度影象作傅立葉變換
	//將輸入影象延擴到最佳的尺寸
	int nRows = getOptimalDFTSize(srcGray.rows);//2,3,5倍有更高效率的傅立葉變換
	int nCols = getOptimalDFTSize(srcGray.cols);
	Mat resultImage;
	//把灰度影象放在左上角,向右邊和下邊擴充套件影象
	//將新增的畫素初始化為0
	copyMakeBorder(srcGray, resultImage, 0, nRows - srcGray.rows, 0, nCols - srcGray.cols, BORDER_CONSTANT, Scalar::all(0));
	//新建一個兩頁矩陣,分配空間(實部和虛部),實部用於擴充套件後的初始化,虛部初始化0
	Mat planes[] = { Mat_<float>(resultImage), Mat::zeros(resultImage.size(), CV_32F) };
	Mat completeI;
	//把兩頁合成一個2通道的mat
	merge(planes, 2, completeI);
	//對上面合成的mat進行離散傅立葉變換,支援原地操作,傅立葉變換結果為複數,通道1存的是實部,通道2存的是虛部。
	dft(completeI, completeI);
	//把變換的結果分割到各個陣列的兩頁中,方便後續操作
	split(completeI, planes);
	//求傅立葉變化各頻率的幅值,幅值放在第一頁中
	magnitude(planes[0], planes[1], planes[0]);
	Mat dftResultImage = planes[0];
	//傅立葉變換的幅度值範圍大到不適合在螢幕上顯示,高值在螢幕上顯示為白點,而低值為黑點,
	//高低值的變化無法有效分辨,為了在螢幕上凸顯出高低的變化得連續性,我們可以用對數尺度來替換線性尺度
	dftResultImage += 1;
	log(dftResultImage, dftResultImage);
	//前面對原始影象進行了擴充套件,這裡把對原始影象傅立葉變換取出,剔除擴充套件部分
	dftResultImage = dftResultImage(Rect(0, 0, srcGray.cols, srcGray.rows));
	//這一步的目的仍是為了顯示,現在用了重分步後的幅度圖,但是幅度值仍然超過可顯示範圍[0,1]
	//我們使用normalize()函式將幅度歸一化到可顯示範圍
	normalize(dftResultImage, dftResultImage, 0, 1, CV_MINMAX);
	
	//重新分配象限,使(0,0)移動到影象中心,
	//傅立葉變換之前要對源影象乘以(-1)^(x+y),進行中心化
	//這是對傅立葉變換結果進行中心化
	int cx = dftResultImage.cols / 2;
	int cy = dftResultImage.rows / 2;
	Mat tmp;
	//Top-Left--為每一個象限建立ROI
	Mat q0(dftResultImage, Rect(0, 0, cx, cy));
	//Top-Right
	Mat q1(dftResultImage, Rect(cx, 0, cx, cy));
	//Bottom-Left
	Mat q2(dftResultImage, Rect(0, cy, cx, cy));
	//Bottom-Right
	Mat q3(dftResultImage, Rect(cx, cy, cx, cy));
	//交換象限,(Top-Left with Bottom-Right)
	q0.copyTo(tmp);
	q3.copyTo(q0);
	tmp.copyTo(q3);
	//交換象限,(Top-Right with Bottom-Letf)
	q1.copyTo(tmp);
	q2.copyTo(q1);
	tmp.copyTo(q2);
	return dftResultImage;
}
int main()
{
	Mat srcImage = imread("D:\\1.jpg");
	if (!srcImage.data)
		return -1;
	imshow("srcImage", srcImage);
	Mat resultImage = DFT(srcImage);
	imshow("resultImage", resultImage);
	waitKey(0);
	return 0;
}