2020-12-26

数字图像处理(傅里叶变换,可分离的傅里叶变换)

1.(简单)傅里叶变换

下图是傅里叶正反变换的原理
![!在这里插入图片描述](https://img-blog.csdnimg.cn/20201226114836157.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0FiYWlfeQ==,size_16,color_FFFFFF,t_70我这里用的是C++的MFC来实现的二维傅里叶变换,包括傅里叶正变换,反变换,在傅里叶正变换之后还输出来图像变换到频域的频谱,根据频谱可以对图像的噪声类型做进一步判断,并可以根据频谱图设计相应的滤波器(这里我没做,只是提供一下思路)。废话不多说,直接上代码。
注意:
1.用MFC的时候要先写打开图像文件的函数,我这里用的是CImage来写的。
2. 要用的话最好就是正反变换配套使用
这是正变换的函数:

在这里插入代码片void CExImage1View::OnFuliye()
{
	// TODO: 在此添加命令处理程序代码
	int iImageWidth = m_Image.GetWidth();
	int iImageHeight = m_Image.GetHeight();
	std::vector<double>mode;

	for (int i = 0; i < iImageWidth * iImageHeight; i++)
	{
		fRealPart.push_back(0.0);
		fImgPart.push_back(0.0);
	}
	for (int v = 0; v < iImageHeight; v++)
	{
		for (int u = 0; u < iImageWidth; u++)
		{
			double fTempReal = 0.0, fTempIng = 0.0;
			for (int y = 0; y < iImageHeight; y++)
			{
				for (int x = 0; x < iImageWidth; x++)
				{
					fTempReal += pow(-1.0, x + y) * (double)*(BYTE*)m_Image.GetPixelAddress(x, y) * cos(2.0 * PI * ((double)u * x
						/ (double)iImageWidth + (double)v * y / (double)iImageHeight)) / ((double)iImageHeight * iImageWidth);

					fTempIng += -pow(-1.0, x + y) * (double)*(BYTE*)m_Image.GetPixelAddress(x, y) * sin(2.0 * PI * ((double)u * x
						/ (double)iImageWidth + (double)v * y / (double)iImageHeight)) / ((double)iImageHeight * iImageWidth);

				}
			}
			fRealPart[(size_t)v * iImageWidth + u] = fTempReal;
			fImgPart[(size_t)v * iImageWidth + u] = fTempIng;
			mode.push_back(log(sqrt(pow(fRealPart[(size_t)v * iImageWidth + u], 2) + pow(fImgPart[(size_t)v * iImageWidth + u], 2)) + 1));
		}
	}
	double min = mode[0], max = mode[0];
	for (int v = 0; v < iImageHeight; v++)
	{
		for (int u = 0; u < iImageWidth; u++)
		{

			if (max < mode[(size_t)v * iImageWidth + u])
				max = mode[(size_t)v * iImageWidth + u];
			if (min > mode[(size_t)v * iImageWidth + u])
				min = mode[(size_t)v * iImageWidth + u];
		}
	}
	double difference = max - min;

	for (int v = 0; v < iImageHeight; v++)
	{
		for (int u = 0; u < iImageWidth; u++)
		{
			mode[(size_t)v * iImageWidth + u] = (mode[(size_t)v * iImageWidth + u] - min) / difference * 255;
		}
	}
	for (int y = 0; y < iImageHeight; y++)
		for (int x = 0; x < iImageWidth; x++)
			*(byte*)m_Image.GetPixelAddress(x, y) = (byte)mode[(size_t)y * iImageWidth + x];
	Invalidate();
	MessageBox(_T("傅里叶正变换,完成,输出图像频谱"));
}

这是傅里叶反变换的代码:

void CExImage1View::OnFanbianhuan()
{
	// TODO: 在此添加命令处理程序代码
	int iImageWidth = m_Image.GetWidth();
	int iImageHeight = m_Image.GetHeight();
	for (int y = 0; y < iImageHeight; y++)
	{
		for (int x = 0; x < iImageWidth; x++)
		{
			double fTempReal = 0.0, fTempIng = 0.0;
			for (int v = 0; v < iImageHeight; v++)
			{
				for (int u = 0; u < iImageWidth; u++)
				{
					fTempReal += fRealPart[(size_t)v * iImageWidth + u] * cos(2.0 * PI * ((double)u * x / (double)iImageWidth + (double)v * y / (double)iImageHeight)) -
						fImgPart[(size_t)v * iImageWidth + u] * sin(2.0 * PI * ((double)u * x / (double)iImageWidth + (double)v * y / (double)iImageHeight));
					fTempIng += fImgPart[(size_t)v * iImageWidth + u] * cos(2.0 * PI * ((double)u * x / (double)iImageWidth + (double)v * y / (double)iImageHeight)) +
						fRealPart[(size_t)v * iImageWidth + u] * sin(2.0 * PI * ((double)u * x / (double)iImageWidth + (double)v * y / (double)iImageHeight));

				}
			}
			fTempReal = pow(-1.0, x + y) * fTempReal;
			fTempIng = pow(-1.0, x + y) * fTempIng;
			*(BYTE*)m_Image.GetPixelAddress(x, y) = (BYTE)(sqrt(pow(fTempReal, 2) + pow(fTempIng, 2)));
		}
	}
	Invalidate();
	MessageBox(_T("傅里叶反变换,完成"));
}

2.(快速)可分离傅里叶变换

可分离傅里叶正变换:

std::vector<double>fRealPart1, fImgPart1, fRealPart2, fImgPart2, fRealPart3, fImgPart3;
void CExImage1View::OnFuliyekuaiz()
{
	// TODO: 在此添加命令处理程序代码
	std::vector<double>mode;
	int iImageWidth = m_Image.GetWidth();
	int iImageHeight = m_Image.GetHeight();
	int x, y, u, v;
	for (int i = 0; i < iImageWidth * iImageHeight; i++)
	{
		fRealPart1.push_back(0.0);
		fImgPart1.push_back(0.0);
		fRealPart2.push_back(0.0);
		fImgPart2.push_back(0.0);
		fRealPart3.push_back(0.0);
		fImgPart3.push_back(0.0);
	}

	for (v = 0; v < iImageHeight; v++)
	{
		for (x = 0; x < iImageWidth; x++)
		{
			double fTempReal = 0.0, fTempImg = 0.0;
			for (y = 0; y < iImageHeight; y++)
			{
				fTempReal += pow(-1.0, y) * (double)*(BYTE*)m_Image.GetPixelAddress(x, y) *
					cos(-2.0 * PI * ((double)v * y / (double)iImageHeight)) / ((double)iImageWidth * iImageHeight);
				fTempImg += pow(-1.0, y) * (double)*(BYTE*)m_Image.GetPixelAddress(x, y) *
					sin(-2.0 * PI * ((double)v * y / (double)iImageHeight)) / ((double)iImageWidth * iImageHeight);
			}
			fRealPart1[(size_t)v * iImageWidth + x] = fTempReal;
			fImgPart1[(size_t)v * iImageWidth + x] = fTempImg;
		}
	}
	for (v = 0; v < iImageHeight; v++)
	{
		for (u = 0; u < iImageWidth; u++)
		{
			double fTempReal = 0.0, fTempImg = 0.0;
			for (x = 0; x < iImageWidth; x++)
			{
				fTempReal += pow(-1.0, x) * ((double)fRealPart1[(size_t)v * iImageWidth + x] *
					cos(-2.0 * PI * ((double)u * x / (double)iImageWidth)) - fImgPart1[(size_t)v * iImageWidth + x] *
					sin(-2.0 * PI * ((double)u * x / (double)iImageWidth)));
				fTempImg += pow(-1.0, x) * ((double)fRealPart1[(size_t)v * iImageWidth + x] *
					sin(-2.0 * PI * ((double)u * x / (double)iImageWidth)) + fImgPart1[(size_t)v * iImageWidth + x] *
					cos(-2.0 * PI * ((double)u * x / (double)iImageWidth)));
			}
			fRealPart2[(size_t)v * iImageWidth + u] = fTempReal;
			fImgPart2[(size_t)v * iImageWidth + u] = fTempImg;
			mode.push_back(log(sqrt(pow(fRealPart2[(size_t)v * iImageWidth + u], 2) + pow(fImgPart2[(size_t)v * iImageWidth + u], 2)) + 1));
		}
	}

	double min = mode[0], max = mode[0];
	for (int v = 0; v < iImageHeight; v++)
	{
		for (int u = 0; u < iImageWidth; u++)
		{

			if (max < mode[(size_t)v * iImageWidth + u])
				max = mode[(size_t)v * iImageWidth + u];
			if (min > mode[(size_t)v * iImageWidth + u])
				min = mode[(size_t)v * iImageWidth + u];
		}
	}
	double difference = max - min;

	for (int v = 0; v < iImageHeight; v++)
	{
		for (int u = 0; u < iImageWidth; u++)
		{
			*(byte*)m_Image.GetPixelAddress(u, v) = (byte)((mode[(size_t)v * iImageWidth + u] - min) / difference * 255);
		}
	}
	Invalidate();
	MessageBox(_T("可分离傅里叶正变换,完成,输出图像频谱"));
}

可分离傅里叶反变换:

void CExImage1View::OnFuliyekuaif()
{
	// TODO: 在此添加命令处理程序代码
	int iImageWidth = m_Image.GetWidth();
	int iImageHeight = m_Image.GetHeight();
	int x, y, u, v;
	for (u = 0; u < iImageWidth; u++)
	{
		for (y = 0; y < iImageHeight; y++)
		{
			double fTempReal = 0.0, fTempIng = 0.0;
			for (v = 0; v < iImageHeight; v++)
			{
				fTempReal += fRealPart2[(size_t)v * iImageWidth + u] * cos(2.0 * PI * ((double)v * y / (double)iImageHeight)) -
					fImgPart2[(size_t)v * iImageWidth + u] * sin(2.0 * PI * ((double)v * y / (double)iImageHeight));
				fTempIng += fImgPart2[(size_t)v * iImageWidth + u] * cos(2.0 * PI * ((double)v * y / (double)iImageHeight)) +
					fRealPart2[(size_t)v * iImageWidth + u] * sin(2.0 * PI * ((double)v * y / (double)iImageHeight));

			}
			fTempReal = pow(-1.0, v) * fTempReal;
			fTempIng = pow(-1.0, v) * fTempIng;
			fRealPart3[(size_t)y * iImageWidth + u] = fTempReal;
			fImgPart3[(size_t)y * iImageWidth + u] = fTempIng;
		}
	}


	for (y = 0; y < iImageHeight; y++)
	{
		for (x = 0; x < iImageWidth; x++)
		{
			double fTempReal = 0.0, fTempIng = 0.0;


			for (u = 0; u < iImageWidth; u++)
			{
				fTempReal += fRealPart3[(size_t)y * iImageWidth + u] * cos(2.0 * PI * ((double)u * x / (double)iImageWidth)) -
					fImgPart3[(size_t)y * iImageWidth + u] * sin(2.0 * PI * ((double)u * x / (double)iImageWidth));
				fTempIng += fImgPart3[(size_t)y * iImageWidth + u] * cos(2.0 * PI * ((double)u * x / (double)iImageWidth)) +
					fRealPart3[(size_t)y * iImageWidth + u] * sin(2.0 * PI * ((double)u * x / (double)iImageWidth));

			}

			fTempReal = pow(-1.0, x + y) * fTempReal;
			fTempIng = pow(-1.0, x + y) * fTempIng;
			double fTpp = (sqrt(pow(fTempReal, 2) + pow(fTempIng, 2)));
			if (fTpp - 255 > 0)
			{
				fTpp = 255;
			}
			else if (fTpp < 0)
			{
				fTpp = 0;
			}
			*(BYTE*)m_Image.GetPixelAddress(x, y) = (byte)fTpp;
		}
	}
	Invalidate();
	MessageBox(_T("可分离傅里叶反变换,完成"));

}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

十八闲客yxg

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值