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); }
至此,離散傅里葉變換的方法實現完成,效果圖如下:
如果上述教程或代碼中有任何錯誤,歡迎批評和指證。