傅里叶变换在图像处理中应用十分广泛。
本文主要是通过实现傅里叶正逆变换,熟悉时域到频域,频域到时域的换算过程。
正变换公式:
逆变换
#include <stdio.h>
#include <complex>
#include <stdlib.h>
#include <vector>
#include <assert.h>
#include <opencv2/opencv.hpp>
#define PI 3.1415926
template<class T>
double static_cast_double(T a)
{
return static_cast<double>(a);
}
template<class T>
float static_cast_float(T a)
{
return static_cast<float>(a);
}
template<class T>
unsigned char static_cast_uchar(T a)
{
return static_cast<unsigned char>(a);
}
class dft{
public:
dft(){};
virtual ~dft(){};
public:
cv::Mat dt(const cv::Mat& src, bool backwards = false);
cv::Mat reduce(const cv::Mat& ft);
protected:
cv::Mat pt(const cv::Mat& src);
cv::Mat bt(const cv::Mat& src);
};
cv::Mat dft::pt(const cv::Mat& src)
{
int M = src.rows;
int N = src.cols;
int u, v, m, n;
std::complex<double> ci{ 0, 1 };
std::vector<float> real_t;
std::vector<float> imag_t;
for (u = 0; u < M; u++)
for (v = 0; v < N; v++)
{
std::complex<double> sum_0(0.0, 0.0);
for (m = 0; m < M; m++)
{
std::complex<double> sum_1(0.0, 0.0);
for (n = 0; n < N; n++)
{
sum_1 += std::exp(-2 * PI*n*v / N*ci) * static_cast_double(src.at<uchar>(m, n));
}
sum_1 /= (double)N;
sum_0 += sum_1 * std::exp(-2 * PI*m*u / M*ci);
}
std::complex<double> tmp = sum_0 / (double)M;
real_t.push_back(static_cast_float(tmp.real()));
imag_t.push_back(static_cast_float(tmp.imag()));
}
cv::Mat s1(real_t);
s1 = s1.reshape(0, M);
cv::Mat s2(imag_t);
s2 = s2.reshape(0, M);
cv::Mat s[2] = { s1, s2 };
cv::Mat dst;
cv::merge(s, 2, dst);
return dst;
}
cv::Mat dft::bt(const cv::Mat& ft)
{
assert(ft.channels() == 2);
int M = ft.rows;
int N = ft.cols;
double M_ = static_cast_double(M);
double N_ = static_cast_double(N);
std::vector<cv::Mat> ft_mats;
cv::split(ft, ft_mats);
int m, n, u, v;
std::complex<double> ci{ 0.0, 1.0 };
std::vector<uchar> real_t;
for (m = 0; m < M; m++)
for (n = 0; n < N; n++)
{
std::complex<double>sum{ 0.0, 0.0 };
for (u = 0; u < M; u++)
for (v = 0; v < N; v++)
{
float rt = ft_mats[0].at<float>(u, v);
float it = ft_mats[1].at<float>(u, v);
std::complex<double> temp{ rt, it };
sum += temp * std::exp(2 * PI*(m*u / M_ + n*v / N_));
}
real_t.push_back(static_cast_uchar(sum.real()));
}
cv::Mat real(real_t);
real = real.reshape(0, M);
return real;
}
cv::Mat dft::reduce(const cv::Mat& ft)
{
assert(ft.channels() == 2);
std::vector<cv::Mat> ft_mats;
cv::split(ft, ft_mats);
cv::magnitude(ft_mats[0], ft_mats[1], ft_mats[0]);
cv::Mat magnitudeImage = ft_mats[0];
magnitudeImage += cv::Scalar::all(1);
cv::log(magnitudeImage, magnitudeImage);
//magnitudeImage.convertTo(magnitudeImage, CV_8UC1, 255, 0);
int cx = magnitudeImage.cols / 2;
int cy = magnitudeImage.rows / 2;
cv::Mat q0(magnitudeImage(cv::Rect(0, 0, cx, cy)));
cv::Mat q1(magnitudeImage(cv::Rect(cx, 0, cx, cy)));
cv::Mat q2(magnitudeImage(cv::Rect(0, cy, cx, cy)));
cv::Mat q3(magnitudeImage(cv::Rect(cx, cy, cx, cy)));
cv:: Mat tmp;
q0.copyTo(tmp);
q3.copyTo(q0);
tmp.copyTo(q3);
q1.copyTo(tmp);
q2.copyTo(q1);
tmp.copyTo(q2);
cv::normalize(magnitudeImage, magnitudeImage, 0, 1, cv::NORM_MINMAX);
return magnitudeImage;
}
cv::Mat dft::dt(const cv::Mat& src, bool backwards)
{
return backwards ? bt(src) : pt(src);
}
int main(int argc, char** argv)
{
cv::Mat src = cv::imread("apple.jpg", 0);
cv::resize(src, src, cv::Size(src.cols / 8, src.rows / 8));
dft* dftops = new dft();
cv::Mat ft = dftops->dt(src);
ft = dftops->reduce(ft);
cv::imshow("fft.jpg", ft);
cv::waitKey(0);
delete dftops;
return 0;
}