圖片DFT變換


今天閑着無聊,做了一下DFT變換。
原理在《數字圖像處理(第3版)》P125

在opencv中處理過程為:

  1. 以灰度圖像的方式讀入一張圖片
  2. 將灰度圖片由 CV_8UC1 變換成 CV_32FC1 ,並且對圖片進行填充
  3. 構建圖片的復數形式 (包括添加I部分全零)
  4. 調用DFT進行變換
  5. 計算歐拉距離,作為|C| 部分
  6. log 變換 (log(1+|C|))
  7. 裁剪掉填充部分
  8. 調整頻率部分,使得得到像書中那樣的頻譜,否則亮的部分在四個角落
  9. 展示圖片

我的實驗效果:

我的代碼地址:https://github.com/cyssmile/openCV_learning_notes/blob/master/opencv_test/opencv_029/opencv_029.cpp

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

/*
* Preprocessing and DFT
* cyssmile
* 2020/03/24
*/
void takeDFT(Mat& source, Mat& destination);
/*
* show DFT
* cyssmile
* 2020/03/24
*/
void showDFT(Mat& source);
/*
* Quadrant change to make High frequency part in the middle
* cyssmile
* 2020/03/24
*/
void changeQuadrant(Mat& source);
/*
* invertDFT
* cyssmile
* 2020/03/24
*/
int main(int argc, char** argv)
{
	Mat original = imread("D:/images/needDeal.jpg", IMREAD_GRAYSCALE);
	if (original.empty())
	{
		cout << "can`t open this ph" << endl;
	}
	namedWindow("input", WINDOW_FREERATIO);
	imshow("input", original);
	Mat destination;
	takeDFT(original, destination);
	showDFT(destination);
	waitKey(0);
	destroyAllWindows();
	return 0;
}

void takeDFT(Mat& source, Mat& destination)
{
	int h = getOptimalDFTSize(source.rows);
	int w = getOptimalDFTSize(source.cols);
	copyMakeBorder(source, source, 0, h - source.rows, 0, w - source.cols, BORDER_DEFAULT);
	//copyMakeBorder(original, original, 0, h - original.rows, 0, w - original.cols, BORDER_CONSTANT, Scalar::all(0));
	// CV_8UC1 to CV_32FC1
	Mat originalFloat;
	//original.convertTo(originalFloat,CV_32FC1,1.0/255.0);
	source.convertTo(originalFloat, CV_32FC1, 1.0 / 255.0);

	// ready dft data complex;
	Mat originalComplex[2] = { originalFloat,Mat::zeros(originalFloat.size(),CV_32F) };
	Mat dftOriginal;
	merge(originalComplex, 2, dftOriginal);

	dft(dftOriginal, destination, DFT_COMPLEX_OUTPUT);
	// spectrum  Tailoring   to Even
	//destination = destination(Rect(0, 0, dftOriginal.rows & -2, dftOriginal.cols & -2));

}
void showDFT(Mat& source)
{
	Mat sourceComplex[2];
	split(source, sourceComplex);
	Mat logReady;
	magnitude(sourceComplex[0], sourceComplex[1], logReady);
	logReady += Scalar::all(1);
	log(logReady, logReady);
	changeQuadrant(logReady);
	normalize(logReady, logReady, 0, 1, NORM_MINMAX);
	namedWindow("spectrum", WINDOW_FREERATIO);
	imshow("spectrum", logReady);
}
void changeQuadrant(Mat& source)
{
	//draw spectrum
	int cx = source.cols / 2;
	int cy = source.rows / 2;

	Mat q0(source, Rect(0, 0, cx, cy));
	Mat q1(source, Rect(cx, 0, cx, cy));
	Mat q2(source, Rect(0, cy, cx, cy));
	Mat q3(source, Rect(cx, cy, cx, cy));

	Mat tmp;
	q0.copyTo(tmp);
	q3.copyTo(q0);
	tmp.copyTo(q3);

	q1.copyTo(tmp);
	q2.copyTo(q1);
	tmp.copyTo(q2);
}

之前在計算幅度值的時候,參數調用錯了

之前錯誤的是

magnitude(originalComplex[0], originalComplex[0], originalComplex[1]);

正確的應該是 (R,I dst)

magnitude(originalComplex[0], originalComplex[1], originalComplex[0]);

錯誤示范

首先由這個頻譜我們看出,這有點像椒鹽噪聲,不連續。而通過傅里葉變換的頻譜應該是比較光滑的。
其次 我們繪制頻譜值采用log(1+|C|), 那么就與幅值有關。
果然我在觀察幅值的計算函數時,發現參數順序不對。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM