一杯清酒邀明月
天下本无事,庸人扰之而烦耳。

一、序言:

该教程基于之前的图像处理类MYCV,是对其的补充。

二、设计目标

对图像进行简单的离散傅里叶变换,并输出生成的频谱图。

三、需要提前掌握的知识

二维傅里叶变换公式:

四、详细步骤

1.首先定义一个方法,该方法对输入的图像进行傅里叶变换

输入:MyImage 源图像

输出:ComplexNu 进行离散傅里叶变换后的复数数组

定义:

static ComplexNumber* Dft2(MyImage const &Scr);

实现:

 1 ComplexNumber* MyCV::Dft2(MyImage const &Scr)
 2 {
 3     int width = Scr.m_width;
 4     int height = Scr.m_height;
 5 
 6     // 将 scr_data 转化为灰度
 7     MyImage *grayimage = Gray(Scr);
 8     unsigned char* gray_data = grayimage->m_data;
 9     int gray_bytesPerLine = grayimage->m_bytesPerLine;
10 
11     // 将 gray_data 转化为 double 型,并去掉用于填充的多余空间
12     double *double_data = new double[width*height];
13 
14     for(int i=0;i<height;i++)
15         for(int j=0;j<width;j++)
16         {
17             double_data[i*width+j]=(double)gray_data[i*gray_bytesPerLine+j];
18         }
19 
20     // 对 double_data 进行傅里叶变换
21     ComplexNumber *dft2_data = new ComplexNumber[width*height];
22     double fixed_factor_for_axisX = (-2 * PI) / height;
23     // evaluate -i2π/N of -i2πux/N, and store the value for computing efficiency
24     double fixed_factor_for_axisY = (-2 * PI) / width;
25     // evaluate -i2π/N of -i2πux/N, and store the value for computing efficiency
26 
27     for (int u = 0; u<height; u++) {
28             for (int v = 0; v<width; v++) {
29                 for (int x = 0; x<height; x++) {
30                     for (int y = 0; y<width; y++) {
31                         double powerX = u * x * fixed_factor_for_axisX; // evaluate -i2πux/N
32                         double powerY = v * y * fixed_factor_for_axisY; // evaluate -i2πux/N
33                         ComplexNumber cplTemp;
34                         cplTemp.m_rl = double_data[y + x*width] * cos(powerX + powerY);
35                         // 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
36                         cplTemp.m_im = double_data[y + x*width] * sin(powerX + powerY);
37                         dft2_data[v + u*width] = dft2_data[v + u*width] + cplTemp;
38                     }
39                 }
40             }
41         }
42 
43     // 返回傅里叶数组
44     return dft2_data;
45 }

2.为了让傅里叶变换可视化,旭阳对其进行标准化和中性化

输入:ComplexNumber 离散傅里叶变换生成的复数数组

输出:MyImage 可视化后的图像

定义:

static MyImage* Dft22MyImage(ComplexNumber *Scr,int width,int height);

实现:

 1 MyImage* MyCV::Dft22MyImage(ComplexNumber *Scr, int const width, int const height)
 2 {
 3     // 将傅里叶数组归一化
 4     // 取模
 5     double mold[width*height];
 6     for(int i = 0 ;i<width*height;i++)
 7     {
 8         mold[i] = Scr[i].get_mold();
 9     }
10 
11     // 获取最小值
12     double min = mold[0];
13     for(int i = 0;i<width*height;i++)
14     {
15         if(mold[i]<min)
16             min = mold[i];
17     }
18 
19     // 获取去掉前几大值的最大值
20     double maxqueue[20] = {0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.,0.},max;
21 
22     for(int i = 0;i<width*height;i++){
23         if(mold[i]>maxqueue[0])
24             maxqueue[0] = mold[i];
25     }
26 
27     for(int j =1;j<20;j++){
28         for(int i = 0;i<width*height;i++){
29             if(mold[i]>maxqueue[j]&&mold[i]<maxqueue[j-1])
30                 maxqueue[j] = mold[i];
31         }
32     }
33 
34     max = maxqueue[19];
35 
36     unsigned char *normalized_data = new unsigned char[width*height];
37 
38     for(int i=0;i<height;i++)
39         for(int j=0;j<width;j++)
40         {
41             unsigned char t = (unsigned char)((mold[i*width+j]-min)/(max-min)*255);
42             if(t>255)
43                 t = 255;
44             normalized_data[i*width+j]=t;
45         }
46 
47     // 将图像中心化
48     unsigned char* center_data = new unsigned char[width*height];
49 
50     for (int u = 0; u<height; u++){
51         for (int v = 0; v<width; v++) {
52             if ((u<(height / 2)) && (v<(width / 2))) {
53                 center_data[v + u*width] =
54                     normalized_data[width / 2 + v + (height / 2 + u)*width];
55             }
56             else if ((u<(height / 2)) && (v >= (width / 2))) {
57                 center_data[v + u*width] =
58                     normalized_data[(v - width / 2) + (height / 2 + u)*width];
59             }
60             else if ((u >= (height / 2)) && (v<(width / 2))) {
61                 center_data[v + u*width] =
62                     normalized_data[(width / 2 + v) + (u - height / 2)*width];
63             }
64             else if ((u >= (height / 2)) && (v >= (width / 2))) {
65                 center_data[v + u*width] =
66                     normalized_data[(v - width / 2) + (u - height / 2)*width];
67             }
68         }
69     }
70 
71     // 向中心化的数组填充空间
72     int bytesPerLine = (width*8+31)/32*4;
73     unsigned char *dst_data = new unsigned char[bytesPerLine*height];
74 
75     for(int i=0;i<height;i++)
76         for(int j=0;j<width;j++)
77         {
78             dst_data[i*bytesPerLine+j] = center_data[i*width+j];
79         }
80 
81     return new MyImage(dst_data,width,height,MyImage::format::GRAY8);
82 }

至此,离散傅里叶变换的方法实现完成,效果图如下:

 

 

posted on 2022-02-21 13:59  一杯清酒邀明月  阅读(399)  评论(0编辑  收藏  举报