今天閑着無聊,做了一下DFT變換。
原理在《數字圖像處理(第3版)》P125
在opencv中處理過程為:
- 以灰度圖像的方式讀入一張圖片
- 將灰度圖片由 CV_8UC1 變換成 CV_32FC1 ,並且對圖片進行填充
- 構建圖片的復數形式 (包括添加I部分全零)
- 調用DFT進行變換
- 計算歐拉距離,作為|C| 部分
- log 變換 (log(1+|C|))
- 裁剪掉填充部分
- 調整頻率部分,使得得到像書中那樣的頻譜,否則亮的部分在四個角落
- 展示圖片
我的實驗效果:
我的代碼地址: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|), 那么就與幅值有關。
果然我在觀察幅值的計算函數時,發現參數順序不對。