图片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|), 那么就与幅值有关。
果然我在观察幅值的计算函数时,发现参数顺序不对。

posted @ 2020-03-23 22:15  cyssmile  阅读(1060)  评论(0编辑  收藏  举报