第6章 フーリエ変換 【リスト6-1】 複素数計算用関数 typedef struct{double r; double i; } Complex; Complex complex(double r, double i){ Complex X; X.r=r; X.i=i; return X; } Complex addC(Complex A, Complex B){ return complex(A.r+B.r, A.i+B.i); } Complex subC(Complex A, Complex B){ return complex(A.r-B.r, A.i-B.i); } Complex multC(Complex A, Complex B){ return complex(A.r*B.r-A.i*B.i, A.r*B.i+A.i*B.r); } Complex multR(Complex A, double B){ return complex(A.r*B, A.i*B); } Complex expJ(double A){// exp(θj)の設定 return complex(cos(A), sin(A)); } Complex divR(Complex A, double B){ return complex(A.r/B, A.i/B); } (C++用オペレーション定義) Complex operator +(Complex x, Complex y){ return addC(x, y);} Complex operator -(Complex x, Complex y){ return subC(x, y);} Complex operator *(Complex x, Complex y){ return multC(x, y);} Complex operator *(Complex x, double y){ return multR(x, y);} Complex operator /(Complex x, double y){ return divR(x, y);} 【リスト6-2】 DFTと逆DFT #include "myWin.h" #include "math.h" #define XST 420 #define YST 10 #define GWIDTH 400 #define GHIGHT 400 #define RED(X) (X & 0xFF) #define GREEN(X) ((X>>8) & 0xFF) #define BLUE(X) ((X>>16) & 0xFF) static HBITMAP hBM[2];static HDC hBuff[2]; static BITMAP bM[2]; void clearBitmap(int i){//ビットマップのクリア SelectObject(hBuff[i], GetStockObject(NULL_PEN)); PatBlt(hBuff[i], 0,0,GWIDTH,GHIGHT,WHITENESS);//黒塗り } void createBitmap(HWND hw){//ビットマップの設定 HDC hdc=GetDC(hw); for(int i=0;i<2;i++){ hBM[i]=CreateCompatibleBitmap(hdc,GWIDTH,GHIGHT); hBuff[i]=CreateCompatibleDC(hdc); SelectObject(hBuff[i], hBM[i]); clearBitmap(i); } } int pixel(int i, int j){//画像1からピクセルを取り出す return GetPixel(hBuff[1], i,j); } void setPixel(int i, int j, COLORREF C){//画像0にピクセルを設定する SetPixel(hBuff[0], i,j, C); } ------(複素数演算用関数省略: 【リスト6-1】参照)----- #define GWDFT 80 #define GHDFT 80 Complex beforDFT[GWDFT+1][GHDFT+1], tmDFT[GWDFT+1][GHDFT+1]; Complex afterDFT[GWDFT+1][GHDFT+1],reverceDFT[GWDFT+1][GHDFT+1]; //グレースケール画像にして1以下の値にする void setComplexDFT(){ for(int i=0;i=0 ? 1: -1), II=(DI>=0 ? 1: -1); DR=abs(DR); DI=abs(DI); switch(flag){ case 0: spec[i][j] = DI*log(DR+1)/log(10.0);break;//実数部 case 1: spec[i][j] = II*log(DI+1)/log(10.0);break;//虚数部 default: spec[i][j] = DI*II*log(DR+DI+1)/log(10.0);//絶対値 } } double max=spec[0][0], min=spec[0][0]; //最大値と最小値を求める for (int i = 0; i < GWDFT; ++i) for (int j = 0; j < GHDFT; ++j) { if(spec[i][j] > max) max = spec[i][j]; if(spec[i][j] < min) min = spec[i][j]; } for (int i = 0; i < GWDFT; ++i) for (int j = 0; j < GHDFT; ++j){ int C = (int)(((spec[i][j] - min)/(max - min)*255)+0.5);//比例配分 if(C > 255) C = 255; if(C<0)C=0; setPixel(startX+i, startY+j, RGB(C,C,C)); } } //0〜1の値を4種類のいずれかで表示(RED, GREEN, BLUE, グレースケール) void dspValue(Complex DT[GWDFT+1][GHDFT+1], int startX, int startY, int flag){ for (int i = 0; i < GWDFT; i++) { for (int j = 0; j < GHDFT; j++) { int C=(int)(DT[i][j].r*255+0.5);if(C>255)C=255; switch(flag){ case 1 : C=RGB(C, 0, 0);break;//RED表示 case 2 : C=RGB(0, C, 0);break;//GREEN表示 case 3 : C=RGB(0, 0, C);break;//BLUE表示 default: C=RGB(C, C, C);break;//グレースケール表示 } setPixel(startX+i, startY+j, C); } } } //テスト用メイン void procDFT(){ setComplexDFT(); dspValue(beforDFT, 0,0, 0); DFT(beforDFT,afterDFT); dspSpec(afterDFT, 100, 0, 0 ); dspSpec(afterDFT, 200, 0, 1 ); IDFT(afterDFT,reverceDFT); dspValue(reverceDFT, 300,0,0); } void procLButtonDown(HWND hw, WPARAM wp,LPARAM lp){ procDFT(); InvalidateRect(hw,NULL,TRUE); } void procRButtonDown(HWND hw, WPARAM wp,LPARAM lp){ clearBitmap(0);//画像0をクリア InvalidateRect(hw,NULL,TRUE); } void procCreate(HWND hw, WPARAM wp,LPARAM lp){//初期処理 createBitmap(hw);MoveWindow(hw,0,0,850,460,TRUE); hBM[1]=LoadBitmap(hInstance, TEXT("suzume"));//画像1に表示 GetObject(hBM[1],sizeof(BITMAP), &bM[1]); InvalidateRect(hw,NULL,TRUE); } void procPaint(HWND hw, WPARAM wp,LPARAM lp){//画面表示 PAINTSTRUCT ps; HDC hdc = BeginPaint(hw,&ps); SelectObject(hBuff[0],hBM[0]);SelectObject(hBuff[1],hBM[1]); BitBlt(hdc,10,YST,GWIDTH, GHIGHT, hBuff[0], 0,0,SRCCOPY); BitBlt(hdc,XST,YST,GWIDTH, GHIGHT, hBuff[1], 0,0,SRCCOPY); EndPaint(hw,&ps); } LRESULT CALLBACK WndProc(HWND hw, UINT msg, WPARAM wp,LPARAM lp){ switch(msg){ case WM_DESTROY : PostQuitMessage(0) ; return 0; case WM_CREATE : procCreate(hw,wp,lp); return 0; case WM_LBUTTONDOWN : procLButtonDown(hw,wp,lp); return 0; case WM_RBUTTONDOWN : procRButtonDown(hw,wp,lp); return 0; case WM_PAINT : procPaint (hw,wp,lp); return 0; } return DefWindowProc(hw,msg,wp,lp); } 【リスト6-3】 R/G/B別の配列の用意とデータの設定 Complex beforR[GWDFT+1][GHDFT+1],afterR[GWDFT+1][GHDFT+1]; Complex reverceR[GWDFT+1][GHDFT+1]; Complex beforG[GWDFT+1][GHDFT+1],afterG[GWDFT+1][GHDFT+1]; Complex reverceG[GWDFT+1][GHDFT+1]; Complex beforB[GWDFT+1][GHDFT+1],afterB[GWDFT+1][GHDFT+1]; Complex reverceB[GWDFT+1][GHDFT+1]; void setComplex2DFT(){ for(int i=0;irr) afterDFT[i][j]=C0; } } void LPF2(int r){// (方法2) 四隅から半径R分をカット int rr=r*r; int MX=GWDFT-1, MY=GHDFT-1;Complex C0=complex(0,0); for(int i=0;iR) FF=0.5*exp(alfa*(R-XR)); else FF=1-0.5*exp(alfa*(XR-R)); afterDFT[i][j]=multR(afterDFT[i][j], FF); } } 【リスト6-6】 単純なハイパスフィルタ void HPF(int r){ int rr=r*r, DX, DY;Complex C0=complex(0,0); int X0=GWDFT/2, Y0=GHDFT/2; for(int i=0;iR) FF=1-0.5*exp(alfa*(R-XR)); else FF=0.5*exp(alfa*(XR-R)); afterDFT[i][j]=multR(afterDFT[i][j],FF); } } 【リスト6-8】 1次元FFT Complex w_tbl[GWDFT/2]; //回転因子計算用テーブル int b_tbl[GWDFT]; //ビット逆順交換用テーブル static int n_old=0; int fft_tbl(Complex * x, int n_FFT){ Complex xtmp; int pow2, j,jnh,jp,jx,num, ne, n_half, n_half2; num=labs(n_FFT); if(num !=n_old){ //1回目の呼び出しのときのみテーブル作成 pow2=1; //要素数が2のべき乗かどうかを判定 for(j=0;j<32;j++) if(num==pow2) break; else pow2<<=1; if(j>=32){ MessageBox(NULL,TEXT("\n データ数が2のべき乗になっていません"), TEXT("Error"), MB_OK); return 1; } double argV=-2.0*PI/num; //回転因子計算用テーブル作成 for(j=0;j>=1; } n_old=num; } n_half=num/2;//FFT計算開始 for(ne=1; ne>=1; } //ビット逆順入れ換え for(j=0; jGWDFT) x2= x2-GWDFT; if(y2>GHDFT) y2= y2-GHDFT; TM[x2][y2]=DT[x][y]; } } Complex temp[GWDFT+1][GHDFT+1]; void procDFT(){// テスト用 setComplexDFT(); dspValue(beforDFT, 0,0, 0); fft_2d(beforDFT,afterDFT, GWDFT); setDspSpec(temp, afterDFT); memmove(afterDFT, temp,sizeof(Complex)*(GWDFT+1)*(GHDFT+1)); dspSpec(afterDFT, 100, 0, 0 ); dspSpec(afterDFT , 200, 0, 1 ); IDFT(afterDFT,reverceDFT) ; dspValue(reverceDFT, 300,0,0); } 【リスト6-12】 2次元高速逆フーリエ変換(GWDFT=64, GHDFT=64) void rev_fft_2d(Complex afterDFT[][GHDFT+1],Complex reverceDFT[][GHDFT+1], int n_fft){ int num=labs(n_fft); fft_2d(afterDFT,reverceDFT, -num); for(int k=0;k<=num;k++)for(int N=0, N2=num-1;N