📄 freqcalculate.cpp
字号:
// ************************************************************************
// 文件名:FreqCalculate.cpp
//
// 图像正交变换函数库:
//
// FFT() - 一维快速付立叶变换
// IFFT() - 一维快速付立叶逆变换
// Fourier() - 二维快速傅立叶变换
// IFourier() - 二维快速傅立叶逆变换
// DCT() - 一维快速离散余弦变换
// IDCT() - 一维快速离散余弦逆变换
// FreqDCT() - 二维快速离散余弦变换
// IFreqDCT() - 二维快速离散余弦逆变换
// WALSH() - 一维沃尔什-哈达玛变换
// IWALSH() - 一维沃尔什-哈达玛逆变换
// FreqWALSH() - 二维沃尔什-哈达玛变换
// IFreqWALSH() - 二维沃尔什-哈达玛逆变换
// DWT() - 二维点阵的小波分解
// IDWT() - 二维点阵的小波重构
//
// DIBFourier() - 图像的付立叶变换
// DIBDCT() - 图像的离散余弦变换
// DIBWalsh() - 图像的沃尔什-哈达玛变换
// DIBDWT() - 图象的二维离散小波变换
//
//*************************************************************************
#include "stdafx.h"
#include "dip_system.h"
#include "FreqCalculate.h"
#include "math.h"
#include <complex>
using namespace std;
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
// 常数π
#define PI 3.1415926535
/////////////////////////////////////////////////////////////////////////////
// CFreqCalculate
CFreqCalculate::CFreqCalculate()
{
}
CFreqCalculate::~CFreqCalculate()
{
}
BEGIN_MESSAGE_MAP(CFreqCalculate, CWnd)
//{{AFX_MSG_MAP(CFreqCalculate)
// NOTE - the ClassWizard will add and remove mapping macros here.
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CFreqCalculate message handlers
/*************************************************************************
*
* 函数名称:
* FFT()
*
* 参数:
* complex<double> * TD - 指向时域数组的指针
* complex<double> * FD - 指向频域数组的指针
* r -2的幂数,即迭代次数
*
* 返回值:
* 无。
*
* 说明:
* 该函数用来实现快速付立叶变换。
*
************************************************************************/
void CFreqCalculate::FFT(complex<double> * TD, complex<double> * FD, int r)
{
// 循环变量
LONG i;
LONG j;
LONG k;
// 中间变量
int p;
// 角度
double angle;
complex<double> *W,*X1,*X2,*X;
// 计算付立叶变换点数
LONG N = 1 << r;
// 分配运算所需存储器
W = new complex<double>[N / 2];
X1 = new complex<double>[N];
X2 = new complex<double>[N];
// 计算加权系数
for(i = 0; i < N / 2; i++)
{
angle = -i * PI * 2 / N;
W[i] = complex<double> (cos(angle), sin(angle));
}
// 将时域点写入X1
memcpy(X1, TD, sizeof(complex<double>) * N);
// 采用蝶形算法进行快速付立叶变换
for(k = 0; k < r; k++)
{
for(j = 0; j < 1 << k; j++)
{
for(i = 0; i < 1<<(r - k -1); i++)
{
p = j * (1<<(r - k));
X2[i + p] = X1[i + p] + X1[i + p + (int)(1<<(r - k -1))];
X2[i + p + (int)(1<<(r - k -1))] = (X1[i + p] - X1[i + p + (int)(1<<(r - k -1))]) * W[i * (1<<k)];
}
}
X = X1;
X1 = X2;
X2 = X;
}
// 重新排序
for(j = 0; j < N; j++)
{
p = 0;
for(i = 0; i < r; i++)
{
if (j&(1<<i))
{
p+=1<<(r - i - 1);
}
}
FD[j] = X1[p];
}
// 释放内存
delete W;
delete X1;
delete X2;
}
/*************************************************************************
*
* 函数名称:
* IFFT()
*
* 参数:
* complex<double> * FD - 指向频域值的指针
* complex<double> * TD - 指向时域值的指针
* r -2的幂数
*
* 返回值:
* 无。
*
* 说明:
* 该函数用来实现快速付立叶逆变换。
*
************************************************************************/
void CFreqCalculate::IFFT(complex<double> * FD, complex<double> * TD, int r)
{
// 循环变量
int i;
complex<double> *X;
// 计算付立叶变换点数
LONG N = 1<<r;
// 分配运算所需存储器
X = new complex<double>[N];
// 将频域点写入X
memcpy(X, FD, sizeof(complex<double>) * N);
// 求共轭
for (i = 0; i < N; i++)
{
X[i] = complex<double> (X[i].real(), -X[i].imag());
}
// 调用快速付立叶变换
FFT(X, TD, r);
// 求时域点的共轭
for (i = 0; i < N; i++)
{
TD[i] = complex<double> (TD[i].real() / N, -TD[i].imag() / N);
}
// 释放内存
delete X;
}
/*************************************************************************
*
* 函数名称:
* Fourier()
*
* 参数:
* complex* TD - 输入的时域序列
* LONG lWidth - 图象宽度
* LONG lHeight - 图象高度
* complex* FD - 输出的频域序列
*
* 返回值:
* BOOL - 成功返回TRUE,否则返回FALSE。
*
* 说明:
* 该函数进行二维快速付立叶变换。
*
************************************************************************/
BOOL CFreqCalculate::Fourier(complex<double> * TD, LONG lWidth, LONG lHeight, complex<double> * FD)
{
// 循环变量
LONG i;
LONG j;
LONG k;
// 更改光标形状
BeginWaitCursor();
// 进行付立叶变换的宽度和高度(2的整数次方)
LONG w = 1;
LONG h = 1;
int wp = 0;
int hp = 0;
// 计算进行付立叶变换的宽度和高度(2的整数次方)
while (w < lWidth)
{
w *= 2;
wp++;
}
while (h < lHeight)
{
h *= 2;
hp++;
}
// 分配内存
complex<double> *TempT, *TempF;
TempT = new complex<double>[h];
TempF = new complex<double>[h];
// 对y方向进行快速付立叶变换
for (i = 0; i < w * 3; i++)
{
// 抽取数据
for (j = 0; j < h; j++)
TempT[j] = TD[j * w * 3 + i];
// 一维快速傅立叶变换
FFT(TempT, TempF, hp);
// 保存变换结果
for (j = 0; j < h; j++)
TD[j * w * 3 + i] = TempF[j];
}
// 释放内存
delete TempT;
delete TempF;
// 分配内存
TempT = new complex<double>[w];
TempF = new complex<double>[w];
// 对x方向进行快速付立叶变换
for (i = 0; i < h; i++)
{
for (k = 0; k < 3; k++)
{
// 抽取数据
for (j = 0; j < w; j++)
TempT[j] = TD[i * w * 3 + j * 3 + k];
// 一维快速傅立叶变换
FFT(TempT, TempF, wp);
// 保存变换结果
for (j = 0; j < w; j++)
FD[i * w * 3 + j * 3 + k] = TempF[j];
}
}
// 释放内存
delete TempT;
delete TempF;
return TRUE;
}
/*************************************************************************
*
* 函数名称:
* IFourier()
*
* 参数:
* LPBYTE TD - 返回的空域数据
* LONG lWidth - 空域图象的宽度
* LONG lHeight - 空域图象的高度
* complex* FD - 输入的频域数据
*
* 返回值:
* BOOL - 成功返回TRUE,否则返回FALSE。
*
* 说明:
* 该函数进行二维快速付立叶逆变换。
*
************************************************************************/
BOOL CFreqCalculate::IFourier(LPBYTE TD, LONG lWidth, LONG lHeight, complex<double> * FD)
{
// 循环变量
LONG i;
LONG j;
LONG k;
// 更改光标形状
BeginWaitCursor();
// 进行付立叶变换的宽度和高度(2的整数次方)
LONG w = 1;
LONG h = 1;
int wp = 0;
int hp = 0;
// 计算进行付立叶变换的宽度和高度(2的整数次方)
while(w < lWidth)
{
w *= 2;
wp++;
}
while(h < lHeight)
{
h *= 2;
hp++;
}
// 计算图像每行的字节数
LONG lLineBytes = WIDTHBYTES(lWidth * 24);
// 分配内存
complex<double> *TempT, *TempF;
TempT = new complex<double>[w];
TempF = new complex<double>[w];
// 对x方向进行快速付立叶变换
for (i = 0; i < h; i++)
{
for (k = 0; k < 3; k++)
{
// 抽取数据
for (j = 0; j < w; j++)
TempF[j] = FD[i * w * 3 + j * 3 + k];
// 一维快速傅立叶变换
IFFT(TempF, TempT, wp);
// 保存变换结果
for (j = 0; j < w; j++)
FD[i * w * 3 + j * 3 + k] = TempT[j];
}
}
// 释放内存
delete TempT;
delete TempF;
TempT = new complex<double>[h];
TempF = new complex<double>[h];
// 对y方向进行快速付立叶变换
for (i = 0; i < w * 3; i++)
{
// 抽取数据
for (j = 0; j < h; j++)
TempF[j] = FD[j * w * 3 + i];
// 一维快速傅立叶变换
IFFT(TempF, TempT, hp);
// 保存变换结果
for (j = 0; j < h; j++)
FD[j * w * 3 + i] = TempT[j];
}
// 释放内存
delete TempT;
delete TempF;
for (i = 0; i < h; i++)
{
for (j = 0; j < w * 3; j++)
{
if (i < lHeight && j < lLineBytes)
*(TD + i * lLineBytes + j) = FD[i * w * 3 + j].real();
}
}
return TRUE;
}
/*************************************************************************
*
* 函数名称:
* DIBFourier()
*
* 参数:
* HDIB hDIB - 待处理的DIB
*
* 返回值:
* BOOL - 成功返回TRUE,否则返回FALSE。
*
* 说明:
* 该函数用来对图像进行付立叶变换。
*
************************************************************************/
BOOL CFreqCalculate::DIBFourier(HDIB hDIB)
{
// 指向源图像的指针
unsigned char* lpSrc;
// 中间变量
double dTemp;
LONG TI,TJ;
// 循环变量
LONG i;
LONG j;
// 指向DIB的指针
LPBYTE lpDIB;
// 指向DIB象素指针
LPBYTE lpDIBBits;
// 锁定DIB
lpDIB = (LPBYTE) ::GlobalLock((HGLOBAL) hDIB);
// 找到DIB图像象素起始位置
lpDIBBits = m_clsDIB.FindDIBBits(lpDIB);
// 判断是否是24-bpp位图
if (m_clsDIB.DIBBitCount(lpDIB) != 24)
{
// 提示用户
MessageBox("请先将其转换为24位色位图,再进行处理!", "系统提示" , MB_ICONINFORMATION | MB_OK);
// 解除锁定
::GlobalUnlock((HGLOBAL) hDIB);
// 返回
return FALSE;
}
// 更改光标形状
BeginWaitCursor();
// DIB的宽度
LONG lWidth = m_clsDIB.DIBWidth(lpDIB);
// DIB的高度
LONG lHeight = m_clsDIB.DIBHeight(lpDIB);
// 计算图像每行的字节数
LONG lLineBytes = WIDTHBYTES(lWidth * 24);
// 进行付立叶变换的宽度和高度(2的整数次方)
LONG w = 1;
LONG h = 1;
int wp = 0;
int hp = 0;
// 计算进行付立叶变换的宽度和高度(2的整数次方)
while(w < lWidth)
{
w *= 2;
wp++;
}
while(h < lHeight)
{
h *= 2;
hp++;
}
// 分配内存
complex<double> *FD, *TD, *TempD;
FD = new complex<double>[w * h * 3];
TD = new complex<double>[w * h * 3];
TempD = new complex<double>[w * h * 3];
// 行
for(i = 0; i < h; i++)
{
// 列
for(j = 0; j < 3 * w; j++)
{
if(i < lHeight && j < lLineBytes)
{
// 获取时域数值
unsigned char Value = *((unsigned char *)lpDIBBits + lLineBytes * i + j);
// 时域赋值
TD[w * i * 3 + j] = complex<double>(Value, 0.0f);
}
else
{
// 否则补零
TD[w * i * 3 + j] = complex<double>(0.0f, 0.0f);
}
}
}
// 进行频谱分析
if (Fourier(TD, lWidth, lHeight, FD) == FALSE)
return FALSE;
// 释放内存
delete []TD;
// 将原点放置于图像中心位置
for(i = 0; i < h; i++)
{
for(j = 0; j < 3 * w; j++)
{
if (i < h / 2)
TI = i + h / 2;
else
TI = i - h / 2;
if (j < w * 3 /2)
TJ = j + 3 * w / 2;
else
TJ = j - 3 * w / 2;
// 保存转换后的频谱图像
TempD[i * w * 3 + j] = FD[TI * w * 3 + TJ];
}
}
// 行
for(i = (int)(h - lHeight) / 2; i < (int)(h + lHeight) / 2; i++)
{
// 列
for(j = (int)(w * 3 - lLineBytes) / 2; j < (int)(w * 3 + lLineBytes) / 2; j += 3)
{
// 计算频谱
dTemp = sqrt(TempD[w * 3 * i + j].real() * TempD[w * 3 * i + j].real() +
TempD[w * 3 * i + j].imag() * TempD[w * 3 * i + j].imag()) / 100;
// 判断是否超过255
if (dTemp > 255)
{
// 对于超过的,直接设置为255
dTemp = 255;
}
// 限制为原图大小范围
TI = i - (h - lHeight) / 2;
TJ = j / 3 - (w - lWidth) / 2;
// 对应象素指针
lpSrc = (unsigned char*)lpDIBBits + lLineBytes * TI + TJ * 3;
// 更新源图像
* (lpSrc) = (BYTE) (dTemp);
* (lpSrc + 1) = (BYTE) (dTemp);
* (lpSrc + 2) = (BYTE) (dTemp);
}
}
// 解除锁定
::GlobalUnlock(hDIB);
// 删除临时变量
delete []FD;
delete []TempD;
// 恢复光标
EndWaitCursor();
// 返回
return TRUE;
}
/*************************************************************************
*
* 函数名称:
* DCT()
*
* 参数:
* double * f - 指向时域值的指针
* double * F - 指向频域值的指针
* r -2的幂数
*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -