【图像处理】离散傅里叶正逆变换c++

傅里叶变换在图像处理中应用十分广泛。
本文主要是通过实现傅里叶正逆变换,熟悉时域到频域,频域到时域的换算过程。
正变换公式:

在这里插入图片描述逆变换
在这里插入图片描述

#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;
}

在这里插入图片描述

发布了35 篇原创文章 · 获赞 13 · 访问量 6326

猜你喜欢

转载自blog.csdn.net/qq_35306281/article/details/103378993
今日推荐