今天闲着无聊,做了一下DFT变换。
原理在《数字图像处理(第3版)》P125
在opencv中处理过程为:
以灰度图像的方式读入一张图片
将灰度图片由 CV_8UC1 变换成 CV_32FC1 ,并且对图片进行填充
构建图片的复数形式 (包括添加I部分全零)
调用DFT进行变换
计算欧拉距离,作为|C| 部分
log 变换 (log(1+|C|))
裁剪掉填充部分
调整频率部分,使得得到像书中那样的频谱,否则亮的部分在四个角落
展示图片
我的实验效果:
#include
#include
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|), 那么就与幅值有关。
果然我在观察幅值的计算函数时,发现参数顺序不对。