チーム20B1

課題名

メディアンフィルタとFFT、エッジフィルタとFFT

研究者名

Ryuku Saitou,Asahi Nakanishi

概要

画像にメディアンフィルタをかけて、その変換前後の周波数成分をFFTを用いて観察した。
さらに画像にエッジフィルタをかけたものも観察した。

使用プログラミング言語

C言語、Java

メディアンフィルタ

メディアンフィルタとは画像のあるドットの色をその周囲のドットから割り出される中央値にするというフィルタである。
これにより、画像全体がぼんやりとし、まるで水彩画で描いたような雰囲気になる。

元画像
lena_noise.jpg
メディアンフィルタの特性を生かすためにあえてノイズを入れてある。

これにFFTを用いて周波数を取り出すと次のようになる。
noise_freq.jpg



次に3×3のメディアンフィルタを画像にかけた。
lena_noise_median_3.jpg

すると周波数は次のようになった。
noise_m3_freq.jpg



さらに次は5×5のメディアンフィルタをかけた。
lena_noise_median_5.jpg

周波数は次のようになった。
noise_m5_freq.jpg



今度は思い切って25×25のメディアンフィルタをかけた。
lena_noise_median_25.jpg

すると周波数は次のようになった。
noise_25_freq.jpg

考察(メディアンフィルタ)

メディアンフィルタに関してはその範囲が大きくなるほど周波数画像の青い十字架のような模様がはっきりするのが見て取れた。
これは元画像の周波数画像と25×25の周波数画像を比較すれば明らかである。
これが元画像の周波数画像。
noise_freq.jpg
こっちが25×25の周波数画像。
noise_25_freq.jpg

メディアンフィルタをかけると画像全体がぼんやりとして、画像に急激な色の変化が見られなくなることが大きな原因だろう。

エッジフィルタ

画像にエッジフィルタを適用すると、以下のようになる。
lena_edge.jpg

エッジフィルタの仕組みは、隣り合う画素値の差分をとる、微分のような処理をすることで、画素値の変化の傾きを計算し、その傾きを出力画像での画素値にすることでエッジが見えるようになるものである。

上記の画像をFFTを用いて画像の周波数成分の可視化すると以下のようになる。
edge_freq.jpg

結果は、様々な周波数が含まれているということになった。

考察(エッジフィルタ)

結果によれば、今回のエッジフィルタをかけた出力画像には、様々な周波数が含まれていることがわかる。
これは、今回使用したエッジフィルタの仕組みによるものであると考えられる。
エッジフィルタは、隣り合う画素値の差をその座標の画素値にするものだからその値はあまり規則性がないと考えられる。
一方、もとの画像は、自然な画像であり、画素値の変化は比較的なだらかであるため少ない周波数の種類だけで表せたのではないだろうか。

一見するとエッジが抽出された画像は情報が少なそうに思えるが、今回用いたエッジフィルタではむしろ状況が複雑になったように考えられる。
ある一定値以下の変化(つまり画像ではほとんど黒な)画素を全て0にしてしまえば、情報は減らせるかもしれない。今後試してみようと思う。

ソースコード

FFTは15C2から引用した。

c言語によるメディアンフィルタのソースコード。

#include <gd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void array_sort(int array[],int num){
int i,j,tmp;
 for(i=0;i<num;i++){
   for(j=i+1;j<num;j++){
     if(array[i]>array[j]){
   tmp=array[i];
   array[i]=array[j];
   array[j]=tmp;
     }
   }
 }
}

int main(const int argc,const char *argv[]){

FILE *out,*in,*fp;
 gdImagePtr im,im_new;
 int width,height,i,j,color,r[10000],g[10000],b[10000],pixel,k,l,rgb_index,width_new,height_new,r_new,g_new,b_new,pixel_new,y_new,color_new,median_size;

if(argv[1]==NULL| |argv[2]==NULL| |!strcmp(argv[1],argv[2])){
   printf("argument error\n");
   exit(-1);
 }

//第一引数で指定されたファイルを読み出し用にオープン
 if((in=fopen(argv[1],"r"))==NULL){
   printf("file open error for %s\n",argv[1]);
   exit(-1);
 }
 //第二引数で指定されたファイルを書き出し用にオープン
 if((out=fopen(argv[2],"wb"))==NULL){
   printf("file open error for %s\n",argv[2]);
   exit(-1);
 }

if((fp=fopen(argv[3],"wb"))==NULL){
   printf("file open error for %s\n",argv[3]);
   exit(-1);
 }
 
 median_size=atoi(argv[4]);
 if(median_size%2==0){
   printf("median_size ha kisuu ni sitene!");
   exit(-1);
 }
 if(median_size>100){
   printf("size ga ookisugiru yo!");
   exit(-1);
 }
 
 //im に画像を読み込み
 im = gdImageCreateFromJpeg(in);

//入力画像のサイズを取得
 width=gdImageSX(im);
 height=gdImageSY(im);

//新しい画像を用意
 im_new= gdImageCreateTrueColor(width,height);

for(i=0;i<width;i++){
   for(j=0;j<height;j++){
     rgb_index=0;
     for(k=i-median_size/2;k<=i+median_size/2;k++){
   for(l=j-median_size/2;l<=j+median_size/2;l++){
     pixel=gdImageGetPixel(im,k,l);
     r[rgb_index]=gdImageRed(im,pixel);
     g[rgb_index]=gdImageGreen(im,pixel);
     b[rgb_index]=gdImageBlue(im,pixel);
     rgb_index++;
   }
     }
     array_sort(r,median_size*median_size);
     array_sort(g,median_size*median_size);
     array_sort(b,median_size*median_size);
     color=gdImageColorExact(im_new,r[median_size/2],g[median_size/2],b[median_size/2]);
     gdImageSetPixel(im_new,i,j,color);
   }
 }

gdImageJpeg(im_new,out,-1);

width_new=gdImageSX(im_new);
 height_new=gdImageSY(im_new);

fprintf(fp,"P2\n%d\n%d\n%d\n",width_new,height_new,255);

for(j=0;j<height_new;j++){
   for(i=0;i<width_new;i++){
     pixel_new=gdImageGetPixel(im_new,i,j);
     r_new=gdImageRed(im_new,pixel_new);
     g_new=gdImageGreen(im_new,pixel_new);
     b_new=gdImageBlue(im_new,pixel_new);
     y_new=(299*r_new+587*g_new+114*b_new)/1000;
     fprintf(fp,"%4d",y_new);
   }
   fprintf(fp,"\n");
 }
 

fclose(in);
 fclose(out);

return 0;
 
}



エッジフィルタのソースコード。

#include <gd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void array_sort(int array[],int num){
int i,j,tmp;
 for(i=0;i<num;i++){
   for(j=i+1;j<num;j++){
     if(array[i]>array[j]){
   tmp=array[i];
   array[i]=array[j];
   array[j]=tmp;
     }
   }
 }
}

int main(const int argc,const char *argv[]){

FILE *out,*in,*fp;
 gdImagePtr im,im_new;
 int width,height,i,j,color,r[9],g[9],b[9],pixel,k,l,rgb_index,red,green,blue,powerful,width_new,height_new,r_new,g_new,b_new,pixel_new,y_new,color_new;

if(argv[1]==NULL| |argv[2]==NULL| |!strcmp(argv[1],argv[2])){
   printf("argument error\n");
   exit(-1);
 }

//第一引数で指定されたファイルを読み出し用にオープン
 if((in=fopen(argv[1],"r"))==NULL){
   printf("file open error for %s\n",argv[1]);
   exit(-1);
 }
 //第二引数で指定されたファイルを書き出し用にオープン
 if((out=fopen(argv[2],"wb"))==NULL){
   printf("file open error for %s\n",argv[2]);
   exit(-1);
 }

if((fp=fopen(argv[3],"wb"))==NULL){
   printf("file open error for %s\n",argv[3]);
   exit(-1);
 }  

//im に画像を読み込み
 im = gdImageCreateFromJpeg(in);

//入力画像のサイズを取得
 width=gdImageSX(im);
 height=gdImageSY(im);

//新しい画像を用意
 im_new= gdImageCreateTrueColor(width,height);

for(i=0;i<width;i++){
   for(j=0;j<height;j++){
     rgb_index=0;
     for(k=i-1;k<=i+1;k++){
   for(l=j-1;l<=j+1;l++){
     pixel=gdImageGetPixel(im,k,l);
     r[rgb_index]=gdImageRed(im,pixel);
     g[rgb_index]=gdImageGreen(im,pixel);
     b[rgb_index]=gdImageBlue(im,pixel);
     rgb_index++;
   }
     }
     red=r[1]+r[3]-4*r[4]+r[5]+r[7];
     green=g[1]+g[3]-4*g[4]+g[5]+g[7];
     blue=b[1]+b[3]-4*b[4]+b[5]+b[7];
     powerful=red;
     if(powerful<green){
   powerful=green;
     }
     if(powerful<blue){
   powerful=blue;
     }
     color=gdImageColorExact(im_new,powerful,powerful,powerful);
     gdImageSetPixel(im_new,i,j,color);
   }
 }

gdImageJpeg(im_new,out,-1);

fprintf(fp,"P2\n%d\n%d\n%d\n",width_new,height_new,255);

for(j=0;j<height_new;j++){
   for(i=0;i<width_new;i++){
     pixel_new=gdImageGetPixel(im_new,i,j);
     r_new=gdImageRed(im_new,pixel_new);
     g_new=gdImageGreen(im_new,pixel_new);
     b_new=gdImageBlue(im_new,pixel_new);
     y_new=(299*r_new+587*g_new+114*b_new)/1000;
     fprintf(fp,"%4d",y_new);
   }
   fprintf(fp,"\n");
 }
 
 fclose(in);
 fclose(out);
 fclose(fp);

return 0;
 
}

  • 最終更新:2020-06-28 19:46:50

このWIKIを編集するにはパスワード入力が必要です

認証パスワード