C++离散傅里叶变换
一、序言:
该教程基于之前的图像处理类MYCV,是对其的补充。
二、设计目标
对图像进行简单的离散傅里叶变换,并输出生成的频谱图。
三、需要提前掌握的知识
二维傅里叶变换公式:
四、详细步骤
1.首先定义一个方法,该方法对输入的图像进行傅里叶变换
输入:MyImage源图像
输出:ComplexNu进行离散傅里叶变换后的复数数组
定义:
static ComplexNumber* Dft2(MyImage const &Scr);
实现:
ComplexNumber* MyCV::Dft2(MyImage const &Scr)
{
int width = Scr.m_width;
int height = Scr.m_height;
// 将 scr_data 转化为灰度
MyImage *grayimage = Gray(Scr);
unsigned char* gray_data = grayimage->m_data;
int gray_bytesPerLine = grayimage->m_bytesPerLine;
// 将 gray_data 转化为 double 型,并去掉用于填充的多余空间
double *double_data = new double[width*height];
for(int i=0;i<height;i++)
for(int j=0;j<width;j++)
{
double_data[i*width+j]=(double)gray_data[i*gray_bytesPerLine+j];
}
// 对 double_data 进行傅里叶变换
ComplexNumber *dft2_data = new ComplexNumber[width*height];
double fixed_factor_for_axisX = (-2 * PI) / height;
// evaluate -i2π/N of -i2πux/N, and store the value for computing efficiency
double fixed_factor_for_axisY = (-2 * PI) / width;
// evaluate -i2π/N of -i2πux/N, and store the value for computing efficiency
for (int u = 0; u<height; u++) {
for (int v = 0; v<width; v++) {
for (int x = 0; x<height; x++) {
for (int y = 0; y<width; y++) {
double powerX = u * x * fixed_factor_for_axisX; // evaluate -i2πux/N
double powerY = v * y * fixed_factor_for_axisY; // evaluate -i2πux/N
ComplexNumber cplTemp;
cplTemp.m_rl = double_data[y + x*width] * cos(powerX + powerY);
// evaluate f(x) * e^(-i2πux/N), which is equal to f(x) * (cos(-i2πux/N)+sin(-i2πux/N)i) according to Euler's formula
cplTemp.m_im = double_data[y + x*width] * sin(powerX + powerY);
dft2_data[v + u*width] = dft2_data[v + u*width] + cplTemp;
}
}
}
}
// 返回傅里叶数组
return dft2_data;
}
2.为了让傅里叶变换可视化,旭阳对其进行标准化和中性化
输入:ComplexNumber离散傅里叶变换生成的复数数组
输出:MyImage可视化后的图像
定义:
static MyImage* Dft22MyImage(ComplexNumber *Scr,int width,int height);
实现:
MyImage* MyCV::Dft22MyImage(ComplexNumber *Scr, int const width, int const height)
{
// 将傅里叶数组归一化
// 取模
double mold[width*height];
for(int i = 0 ;i<width*height;i++)
{
mold[i] = Scr[i].get_mold();
}
// 获取最小值
double min = mold[0];
for(int i = 0;i<width*height;i++)
{
if(mold[i]<min)
min = mold[i];
}
// 获取去掉前几大值的最大值
double maxqueue[20] = {0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.},max;
for(int i = 0;i<width*height;i++){
if(mold[i]>maxqueue[0])
maxqueue[0] = mold[i];
}
for(int j =1;j<20;j++){
for(int i = 0;i<width*height;i++){
if(mold[i]>maxqueue[j]&&mold[i]<maxqueue[j-1])
maxqueue[j] = mold[i];
}
}
max = maxqueue[19];
unsigned char *normalized_data = new unsigned char[width*height];
for(int i=0;i<height;i++)
for(int j=0;j<width;j++)
{
unsigned char t = (unsigned char)((mold[i*width+j]-min)/(max-min)*255);
if(t>255)
t = 255;
normalized_data[i*width+j]=t;
}
// 将图像中心化
unsigned char* center_data = new unsigned char[width*height];
for (int u = 0; u<height; u++)
{
for (int v = 0; v<width; v++) {
if ((u<(height / 2)) && (v<(width / 2))) {
center_data[v + u*width] =
normalized_data[width / 2 + v + (height / 2 + u)*width];
}
else if ((u<(height / 2)) && (v >= (width / 2))) {
center_data[v + u*width] =
normalized_data[(v - width / 2) + (height / 2 + u)*width];
}
else if ((u >= (height / 2)) && (v<(width / 2))) {
center_data[v + u*width] =
normalized_data[(width / 2 + v) + (u - height / 2)*width];
}
else if ((u >= (height / 2)) && (v >= (width / 2))) {
center_data[v + u*width] =
normalized_data[(v - width / 2) + (u - height / 2)*width];
}
}
}
// 向中心化的数组填充空间
int bytesPerLine = (width*8+31)/32*4;
unsigned char *dst_data = new unsigned char[bytesPerLine*height];
for(int i=0;i<height;i++)
for(int j=0;j<width;j++)
{
dst_data[i*bytesPerLine+j] = center_data[i*width+j];
}
return new MyImage(dst_data,width,height,MyImage::format::GRAY8);
}
至此,离散傅里叶变换的方法实现完成,效果图如下:
如果上述教程或代码中有任何错误,欢迎批评和指证。
原文链接: https://www.cnblogs.com/akakakkk/p/8541497.html
欢迎关注
微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍
原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/270154
非原创文章文中已经注明原地址,如有侵权,联系删除
关注公众号【高性能架构探索】,第一时间获取最新文章
转载文章受原作者版权保护。转载请注明原作者出处!