2次元フーリエをするには?


ヨシ  2003-11-01 03:32:54  No: 52382

入力画像サイズが128×128(24bit)以上でも正しい結果が得られるようにするには、どのようにしたら良いでしょうか?256×256だとうまく結果がでません。
どなたか教えて頂けないでしょうか??
下位は今の時点の作成プログラムです。
                        
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#define PI 3.141592
#define OPT 1  //OPT=1 光学的DFT(直流分が中央)
        //OPT=0 通常のDFT(直流分が左端)

#define X_EXP 7     //X_EXP = log2(X_SIZE)
#define Y_EXP 7     //Y_EXP = log2(Y_SIZE)

#define ysize 128
#define xsize 128
unsigned char image_in[ysize][xsize][3]; 
unsigned char image_out[ysize][xsize][3]; 

/* BMPファイル用 */
typedef unsigned short WORD;
typedef unsigned long DWORD;

WORD  bfType;
DWORD bfSize;
WORD  bfReserved1,
      bfReserved2;
DWORD bfOffBits;
DWORD biSize, 
      biWidth, biHeight;
WORD  biPlanes,
      biBitCount;
DWORD biCompression, 
      biSizeImage,
      biXPelsPerMeter,
      biYPelsPerMeter,
      biClrUsed, 
      biClrImportant;

void readBMP(char *filename,unsigned char image[ysize][xsize][3]);
void writeBmp(char *filename,unsigned char image[ysize][xsize][3]);

void fft1core(double a_rl[], double a_im[], int length, int ex, double sin_tb1[], double cos_tb1[], double buf[]);
void cstb(int length, int inv, double sin_tb1[], double cos_tb1[]);
void birv(double a[], int length, int ex, double b[]);

int fft2(double a_rl[ysize][xsize], double a_im[ysize][xsize], int inv);
int fft(double a_rl[ysize][xsize], double a_im[ysize][xsize], int inv);

void rvmtx1(double a[ysize][xsize], double b[xsize][ysize]);
void rvmtx2(double a[xsize][ysize], double b[ysize][xsize]);

int fftimge(unsigned char image_in[ysize][xsize][3], unsigned char image_out[ysize][xsize][3]);
int fftfilter(unsigned char image_in[ysize][xsize][3], 
              unsigned char image_out[ysize][xsize][3],int a, int b);

int inv=1;

void main(void)
{
  
  char input[100],output[100];
  
  
  
  printf("入力画像ファイル名(input.bmp):");
  scanf("%s",input);
  printf("出力画像ファイル名(output.bmp):");
  scanf("%s",output);
  
  readBMP(input,image_in);
  

  fftimge(image_in,image_out);
  writeBmp(output,image_out);

  
  

  
}

/*----------------------------------------------------------------------
                  BMP形式のカラー画像を読み込む関数
 image:    カラー画像配列
 xsize:    画像横サイズ
 ysize:    画像縦サイズ
 filename: ファイル名(.bmp)
-----------------------------------------------------------------------*/

void readBMP(char *filename,unsigned char image[ysize][xsize][3])
{
  long i,j,k;
  FILE *fp;
  

  if((fp = fopen(filename,"rb")) == NULL){
    printf("readBMP: Open erorr!\n");
    exit(1);
  }

/* ヘッダー情報 */
  fread(&bfType, sizeof(bfType), 1, fp);
  fread(&bfSize, sizeof(bfSize), 1, fp);
  fread(&bfReserved1, sizeof(bfReserved1), 1, fp);
  fread(&bfReserved2, sizeof(bfReserved2), 1, fp);
  fread(&bfOffBits, sizeof(bfOffBits), 1, fp);

  fread(&biSize, sizeof(biSize), 1, fp);
  fread(&biWidth, sizeof(biWidth), 1, fp);
  fread(&biHeight, sizeof(biHeight), 1, fp);
  fread(&biPlanes, sizeof(biPlanes), 1, fp);
  fread(&biBitCount, sizeof(biBitCount), 1, fp);
  fread(&biCompression, sizeof(biCompression), 1, fp);
  fread(&biSizeImage, sizeof(biSizeImage), 1, fp);
  fread(&biXPelsPerMeter, sizeof(biXPelsPerMeter), 1, fp);
  fread(&biYPelsPerMeter, sizeof(biYPelsPerMeter), 1, fp);
  fread(&biClrUsed, sizeof(biClrUsed), 1, fp);
  fread(&biClrImportant, sizeof(biClrImportant), 1, fp);

  /* ビットマップデータ */
  for (i=0; i<biHeight; i++)
  {
    for (j=0; j<biWidth; j++)
      {
        for (k=0; k<3; k++) 
          fread(&image[i][j][2-k], 1, 1, fp);
      }
  }  
  fclose(fp);

  

}

/* 
   unsigned char型配列に格納された
   24ビット-ビットマップデータをBMPファイルに出力する
  [注意] 画像の横幅は4の倍数であること!
*/
void writeBmp(char *filename,unsigned char image[ysize][xsize][3])
{
  FILE *fp;
  int i, j, k;
  
  /* ファイルオープン */
  if ((fp = fopen(filename, "wb"))==NULL) {
    printf("writeBmp: Open error!\n");
    exit(1);
  }
  printf("output file : %s\n", filename);

  /* ヘッダー情報 */
  fwrite(&bfType, sizeof(bfType), 1, fp);
  fwrite(&bfSize, sizeof(bfSize), 1, fp);
  fwrite(&bfReserved1, sizeof(bfReserved1), 1, fp);
  fwrite(&bfReserved2, sizeof(bfReserved2), 1, fp);
  fwrite(&bfOffBits, sizeof(bfOffBits), 1, fp);

  fwrite(&biSize, sizeof(biSize), 1, fp);
  fwrite(&biWidth, sizeof(biWidth), 1, fp);
  fwrite(&biHeight, sizeof(biHeight), 1, fp);
  fwrite(&biPlanes, sizeof(biPlanes), 1, fp);
  fwrite(&biBitCount, sizeof(biBitCount), 1, fp);
  fwrite(&biCompression, sizeof(biCompression), 1, fp);
  fwrite(&biSizeImage, sizeof(biSizeImage), 1, fp);
  fwrite(&biXPelsPerMeter, sizeof(biXPelsPerMeter), 1, fp);
  fwrite(&biYPelsPerMeter, sizeof(biYPelsPerMeter), 1, fp);
  fwrite(&biClrUsed, sizeof(biClrUsed), 1, fp);
  fwrite(&biClrImportant, sizeof(biClrImportant), 1, fp);

  /* ビットマップデータ */
  for (i=0; i<biHeight; i++)
  {
    for (j=0; j<biWidth; j++) 
    {
      for (k=0; k<3; k++)
      { 
        fwrite(&image[i][j][2-k], 1, 1, fp);
      }
    }
  }
  fclose(fp);
}

/*--------------------      1次元FFTの実行      ----------------------
     a_rl: データの次数部(入出力兼用)
     a_im: データの虚数部(入出力兼用)
     ex:   データの個数を2のべき乗で与える(データの個数=2のex乗個)
     inv:  1:FFT, -1:I_FFT
----------------------------------------------------------------------*/
int fft1(double a_rl[], double a_im[], int ex, int inv)
{
  int i,length=1;
  double *sin_tb1;    //sin計算用テーブル
  double *cos_tb1;    //cos計算用テーブル
  double *buf;        //作業用バッファ

  /*- データの個数の計算 -*/
  for(i=0;i<ex;i++){
    length*=2;
  }

  sin_tb1=(double *)malloc(length*sizeof(double));
  cos_tb1=(double *)malloc(length*sizeof(double));
  buf=(double *)malloc(length*sizeof(double));

  if((sin_tb1==NULL)||(cos_tb1==NULL)||(buf==NULL)){
    return -1;
  }

  cstb(length,inv, sin_tb1, cos_tb1);  
  fft1core(a_rl, a_im, length, ex, sin_tb1, cos_tb1, buf);
  free(sin_tb1);
  free(cos_tb1);
  return 0;

}

/*---------------     1次元FFTの計算の核になる部分     ---------------
 sin_tb1: sin計算用テーブル
 cos_tb1: cos計算用テーブル
---------------------------------------------------------------------*/
void fft1core(double a_rl[], double a_im[], int length, 
              int ex, double sin_tb1[], double cos_tb1[], double buf[])
{
  int i,j,k,w,j1,j2;
  int numb,lenb,timb;
  double xr, xi, yr, yi, nrml;

  if(OPT==1){
    for(i=1;i<length;i+=2){
      a_rl[i]=-a_rl[i];
      a_im[i]=-a_im[i];
    }
  }

  numb=1;
  lenb=length;
  for(i=0;i<ex;i++){
    lenb/=2;
    timb=0;
    for(j=0;j<numb;j++){
      w=0;
      for(k=0;k<lenb;k++){
        j1=timb+k;
        j2=j1+lenb;
        xr=a_rl[j1];
        xi=a_im[j1];
        yr=a_rl[j2];
        yi=a_im[j2];
        a_rl[j1]=xr+yr;
        a_im[j1]=xi+yi;
        xr=xr-yr;
        xi=xi-yi;
        a_rl[j2]=xr*cos_tb1[w]-xi*sin_tb1[w];
        a_im[j2]=xr*sin_tb1[w]+xi*cos_tb1[w];
        w+=numb;
      }
      timb+=(2*lenb);
    }
    numb*=2;
  }

  birv(a_rl, length, ex, buf);     //実数データの並べ替え
  birv(a_im, length, ex, buf);     //虚数データの並べ替え

  if(OPT==1){
    for(i=1;i<length;i+=2){
      a_rl[i]=-a_rl[i];
      a_im[i]=-a_im[i];
    }
  }

  nrml=(double)(1.0/sqrt((double)length));
  for(i=0;i<length;i++){
    a_rl[i]*=nrml;
    a_im[i]*=nrml;
  }
  
}      

/*-------------      sin・cosテーブルの作成      -------------*/
void cstb(int length, int inv, double sin_tb1[], double cos_tb1[])
{
  int i;
  double xx, arg;

  xx=(double)(((-PI)*2.0)/(double)length);

  if(inv<0){
    xx=-xx;
  }
  
  for(i=0;i<length;i++){
    arg=(double)i*xx;
    sin_tb1[i]=(double)sin(arg);
    cos_tb1[i]=(double)cos(arg);
  }
}

/*-----------      データの並べ換え      -----------
  a:  データの配列
  b:  作業用バッファ
--------------------------------------------------*/
void birv(double a[], int length, int ex, double b[])
{
  int i,ii,k,bit;

  for(i=0;i<length;i++){
    for(k=0, ii=i, bit=0; ;bit<<=1, ii>>=1){
      bit=(ii&1)|bit;
      if(++k==ex)break;
    }
    b[i]=a[bit];
  }

  for(i=0;i<length;i++){
    a[i]=b[i];
  }
}

/*------------------------------------------------------------------------------
                           2次元のFFTを実行する関数
  a_rl:  データ実数部(入出力兼用)
  a_im:  データ虚数部(入出力兼用)
  inv:   1:FFT, -1:I_FFT
------------------------------------------------------------------------------*/
int fft2(double a_rl[ysize][xsize], double a_im[ysize][xsize], int inv)
{
  int i;
  double *b_rl;       //データ転置作業用配列(実数部)
  double *b_im;       //データ転置作業用配列(虚数部)
  double *hsin_tb1;   //水平用sin計算用テーブル
  double *hcos_tb1;   //水平用cos計算用テーブル
  double *vsin_tb1;   //垂直用sin計算用テーブル
  double *vcos_tb1;   //垂直用cos計算用テーブル
  double *buf_x;      //作業用バッファ(水平方向)
  double *buf_y;      //作業用バッファ(垂直方向)

  /*----------      memory allocation      ----------*/
  b_rl = (double *)calloc((size_t)xsize*ysize, sizeof(double));
  b_im = (double *)calloc((size_t)xsize*ysize, sizeof(double));
  hsin_tb1 = (double *)calloc((size_t)xsize, sizeof(double));
  hcos_tb1 = (double *)calloc((size_t)xsize, sizeof(double));
  vsin_tb1 = (double *)calloc((size_t)ysize, sizeof(double));
  vcos_tb1 = (double *)calloc((size_t)ysize, sizeof(double));
  buf_x = (double *)malloc((size_t)xsize*sizeof(double));
  buf_y = (double *)malloc((size_t)ysize*sizeof(double));

  if((b_rl==NULL)||(b_im==NULL)||(hsin_tb1==NULL)||(hcos_tb1==NULL)||
    (vsin_tb1==NULL)||(vcos_tb1==NULL)||(buf_x==NULL)||(buf_y==NULL)){
    return -1;
  }

  /*--- 水平用sin,cosテーブル作成 ---*/
  cstb(xsize, inv, hsin_tb1, hcos_tb1);

  /*--- 垂直用sin,cosテーブル作成 ---*/
  cstb(ysize, inv, vsin_tb1, vcos_tb1);

  /*--- 水平方向のFFT ---*/
  for(i=0;i<ysize;i++){
    fft1core(&a_rl[(long)i][0], &a_im[(long)i][0], 
                 xsize, X_EXP, hsin_tb1, hcos_tb1, buf_x);
  }

  /*--- 2次元データの転置 ---*/
  rvmtx1((double (*)[xsize])a_rl, (double (*)[xsize])b_rl);
  rvmtx1((double (*)[xsize])a_im, (double (*)[xsize])b_im);

  /*--- 垂直方向のFFT ---*/
  for(i=0;i<xsize;i++){
    fft1core(&b_rl[(long)ysize*i], &b_im[(long)ysize*i], 
                 ysize, Y_EXP, vsin_tb1, vcos_tb1, buf_y);
  }

  /*--- 2次元データの転置 ---*/
  rvmtx2((double (*)[ysize])b_rl, (double (*)[ysize])a_rl);
  rvmtx2((double (*)[ysize])b_im, (double (*)[ysize])a_im);

  free(b_rl);
  free(b_im);
  free(hsin_tb1);
  free(hcos_tb1);
  free(vsin_tb1);
  free(vcos_tb1);

  return 0;

}

/*-----------------------------------------------------------------------------------
                            2次元データの転置を行う関数
  a:     2次元入力データ
  b:     2次元出力データ
  xsize: 水平データ個数
  ysize: 垂直データ個数
-----------------------------------------------------------------------------------*/
void rvmtx1(double a[ysize][xsize], double b[xsize][ysize])
{
  int i,j;

  for(i=0;i<ysize;i++){
    for(j=0;j<xsize;j++){
      b[j][i] = a[i][j];
    }
  }
}

/*-----------------------------------------------------------------------------------
                            2次元データの転置を行う関数
  a:     2次元入力データ
  b:     2次元出力データ
  xsize: 水平データ個数
  ysize: 垂直データ個数
-----------------------------------------------------------------------------------*/
void rvmtx2(double a[xsize][ysize], double b[ysize][xsize])
{
  int i,j;

  for(i=0;i<ysize;i++){
    for(j=0;j<xsize;j++){
      b[i][j] = a[j][i];
    }
  }
}

/*----------------------------------------------------------------------------------------
                              2次元FFTの結果を画像化するプログラム
      解説:このプログラムでは振幅特性を濃度として画像化を行っています.

/*-----------------------------------------------------------------------------------------
                            2次元FFTの結果を画像化する関数
  image_in:   入力画像配列(実世界領域)
  image_out:  出力画像配列(周波数領域)
------------------------------------------------------------------------------------------*/
int fftimge(unsigned char image_in[ysize][xsize][3], unsigned char image_out[ysize][xsize][3])
{
  long i,j;
  double *ar;   //データ実数部(入出力兼用)
  double *ai;   //データ虚数部(入出力兼用)
  double norm;  //振幅幅
  double max;
  double data;
  int k;

    /*--------------     memory allocation     --------------*/
  ar = (double *)malloc((size_t)ysize*xsize*sizeof(double));
  ai = (double *)malloc((size_t)ysize*xsize*sizeof(double));

  if((ar==NULL)||(ai==NULL)){
    return -1;
  }

  /*--- 原画像を読み込み,2次元FFTの入力データに変換する ---*/
  for(i=0;i<ysize;i++){
    for(j=0;j<xsize;j++){
      
        ar[xsize*i+j] = (double)image_in[i][j][3];
        ai[xsize*i+j] = 0.0;
      }
    
  }

  printf("aa\n");

  /*--- 2次元FFTを実行する ---*/
  if(fft2((double (*)[xsize])ar, (double (*)[ysize])ai, 1)== -1){
    return -1;
  }

  /*--- FFTの結果を画像化する ---*/
  max=0;
  for(i=0;i<ysize;i++){
    for(j=0;j<xsize;j++){
      norm = ar[xsize*i+j]*ar[xsize*i+j]
                  +ai[xsize*i+j]*ai[xsize*i+j];

      if(norm!=0.0){
        norm = log(norm)/2.0;
      }else{
        norm =0.0;
      }

      ar[xsize*i+j] = (double)norm;

      if(norm>max){
        max=norm;
      }

    }
  }

  for(i=0;i<ysize;i++){
    for(j=0;j<xsize;j++){
      ar[xsize*i+j] = (double)(ar[xsize*i+j]*255/max);
    }
  }

  /*--- FFTの結果を画像データに変換する ---*/
  for(i=0;i<ysize;i++)
  {
    for(j=0;j<xsize;j++)
    {
      for(k=0;k<3;k++)
      {
        data = ar[xsize*i+j];
        if(data > 255) data = 255;
        if(data <   0) data = 0;
        image_out[i][j][k] = (unsigned char)data;
      }
    }
  }
  

  free(ar);
  free(ai);

  return 0;

}


YuO  2003-11-01 09:55:32  No: 52383

うまく結果が出ない,というのはどういう状況なのですか?
それがちゃんと説明されないと,まともに答えをつけられる人はいないと思います。
#プログラムの結果は,あなたの書いたコードに対する正しい振る舞いだと思います。

また,デバッガで追ってみて,異常な振る舞いをする場所は無かったのですか?

ちなみに,あまりに面倒なので全くコードは読んでいません。
コードを読んで欲しいなら抜粋して必要部分だけにして,さらに必要なコメントを付けることです。


ボコノン教徒  2003-11-04 20:15:04  No: 52384

こんな長ったらしいソースつけられても、誰も最後まで見ないと思うが...
中身はよーわからんが、とりあえず以下を直してみれば。

> #define X_EXP 7     //X_EXP = log2(X_SIZE)
> #define Y_EXP 7     //Y_EXP = log2(Y_SIZE)

> #define ysize 128
> #define xsize 128

7 -> 8
128 ->256

> #define PI 3.141592

もうちょい、精度上げたほうがいいのでは。


ヨシ  2003-11-05 20:12:25  No: 52385

いろいろと御意見ありがとうございます!
まだまだ自分が未熟なのでもっと勉強します。
YuOさん、ボコノン教徒さん、ありがとうございます!


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加