Program 1
このページを見るときは固定等幅フォントを使用してください
/****************************************************************/
/* ファジールールに基づくメジアンフィルタ */
/* A Vol.J78-A No.2 pp.123-131 1995 */
/****************************************************************/
/* @001 Initial 1998/01/16 TK */
/* @002 Membership 関数の修正 1998/01/23 TK */
/* @003 雑音部,信号部各々の MSE の算出 1998/01/23 TK */
/****************************************************************/
#include "stdio.h"
#include "stdlib.h"
#include "math.h"
#include "gf_file.h" // BMP File 書き出し
#define VER "1.03a" // Version Number
#define DEBUG 0
#define DEBUGF 0
#define INNAME 0 // ファイル名を入力するようにする
#define WRITE 1 // 画像出力をファイルに記録する
#if WRITE
#define BMPFILE 0 // BMP でのファイルの書き出し
#endif
//-------- 画像の選択 ---------
#define IMG_LENA 1 // Lena
#define IMG_BOAT 0 // Boat
#define IMG_LIGHTHOUSE 0 // LIGHTHOUSE
/* 各種定義 */
#define xsize 256 // 画像の横のサイズ
#define ysize 256 // 画像の縦のサイズ
#define winsize 5 // 局所情報窓サイズ
//--- プロトタイプ宣言 ---//
int file_read( char * , double * ) ; // File read function
void fmedian( int, int ) ; // Fuzzy UM Process
double mse( void ) ; // MSE Caliculation
void mapmse( void ) ; // 雑音部と信号部の MSE を別々に算出
//--- 各種配列宣言 --//
double org[ysize][xsize] ; // 理想画像配列
double id[ysize][xsize] ; // 原画像配列and入力画像配列
double od[ysize][xsize] ; // 出力画像配列
/* FIle Name */
#if IMG_LENA
char ogname[] = "lena" ; // 原信号ファイル名
char iname[] = "lena_i5.fob" ; // 入力(劣化)信号ファイル名
#if BMPFILE
char oname[] = "lena_i5r.bmp" ; // 出力信号ファイル名
#else
char oname[] = "lena_i5r.fob" ; // 出力信号ファイル名
#endif
#endif
void main(void)
{
FILE *ofp , *fp ; // 画像書込用 , 関数最適結果用
char dummy[100]; // Dummy 変数
int x, y ; // Counter
double minbl , maxbl ; // 局所情報の分散値の最小と最大値
double dv , bv , msed ; // DV / BV 用変数 , MSE 用変数
char ver[] = VER ; // Version Number
#if WRITE
int wdat ; // ファイル書込用変数
#endif
/******************************************
* 画像処理プログラム *
******************************************/
printf("ファジールールに基づくメジアンフィルタ V%s [1998.01.15]\n" , &ver[0] );
printf(" Copyright MIT [Tomoaki Kimura] 1997\n");
//--- 入力配列 id[y][x] に輝度値が入る ---//
#if INNAME
printf("劣化画像") ;
#endif
if ( file_read( &iname[0] , &id[0][0]) ) exit(1) ; // 劣化画像読み込み
#if INNAME
printf("理想画像名") ;
#endif
if ( file_read( &ogname[0] , &org[0][0] ) ) exit(1) ; // 理想画像読み込み
//-- 配列の初期化 --//
printf("配列の初期化\n") ;
for(y=0 ; y<ysize ; y++) for(x=0 ; x<xsize ; x++) od[y][x] = 0.0 ;
//-- use FUZZY --//
printf("ファージメジアンフィルタの計算\n") ;
for( y=2 ; y<ysize-2 ; y++ ){
for( x=2 ; x<xsize-2 ; x++ ){
#if DEBUG
printf("od[%d][%d]", y, x ) ;
#endif
fmedian( y, x ) ; // FUZZY による Median 処理
#if DEBUG
printf("od[%d][%d](%lf) , id(%lf) : ", y, x, od[y][x] , id[y][x] ) ;
#endif
} // X
} // Y
//********************************//
// MSE の算出 //
//********************************//
printf("MSE の計算\n") ;
msed = mse() ; // MSE
mapmse() ; // 雑音部と信号部各々の MSE
//******************************************//
// 出力ファイル //
//******************************************//
#if WRITE
printf("算出後のデータをファイルに出力しています\n") ;
#if BMPFILE
Gf_write_bmp( &oname[0] , &od[0][0] ) ;
#else // (BMPFILE)
printf("算出後のデータをファイルに出力しています\n") ;
ofp=fopen(oname,"wb");
for( y=0 ; y<ysize ; y++ ){
for( x=0 ; x<xsize ; x++ ){
if ( od[y][x] > 255 ) od[y][x] = 255 ;
if ( od[y][x] < 0 ) od[y][x] = 0 ;
wdat = (int)od[y][x] ; // データを変換する
putc( wdat, ofp ) ;
putc( (wdat>>8), ofp ) ;
}
}
fclose(ofp);
#endif // (BMPFILE)
#endif // (WRITE)
return;
} //-- end of main() --//
//////////////////////////////////////////////////////////////////////////
// SUB Routine //
//////////////////////////////////////////////////////////////////////////
/****************************/
/* File Read Function */
/****************************/
int file_read( char *fname , double *inp )
{
int x , y ; // 単なるカウンタ
int dat ; // データ用一時変数
#if INNAME
int sw=0 ; // File name 用 SW
#endif
FILE *fp ;
#if INNAME
do {
printf ( "ファイル名を入力してください:" ) ;
gets(fname);
if((fp=fopen( fname,"rb"))==NULL) printf("入力ファイルが見つかりません。") ;
else sw = 1 ;
} while ( !sw ) ;
#else
if((fp=fopen( fname,"rb"))==NULL){
printf("入力ファイルが見つかりません。");
return(1) ; // 異常終了
}
#endif
//--- input memory from file data ---//
for( y=0 ; y<ysize ; y++ ){
for( x=0 ; x<xsize ; x++){
dat = (double)getc(fp);
dat += (int )(getc(fp)<<8);
*inp = (double)dat ;
inp ++ ;
}
}
fclose(fp);
return(0) ; // 正常終了
}
//======================================================================//
// Fuzzy による メジアンフィルタ 処理 //
// //
// 入力変数 //
// int y, x 画像の縦横 //
// //
// 外部変数として以下の配列を指定する //
// id[][] : 入力画像 //
// od[][] : 出力画像 //
//======================================================================//
void fmedian( int y , int x )
{
//-- use FUZZY UM --//
double f[25] , g[9] ; // 一時的に局所情報に使用する変数
double m , p ; // 各種情報用変数
double ssort , med ; // ソート及びメジアン用変数
double tkim , tkip ; // 各情報のメンバーシップ適合度
double u[4] , uw[4] ; // 各メンバーシップの適合度
double sumu , sumuw , yr ;
int i , j , k ; // カウンタ変数
//==============================//
// FUZZY による Median 処理 //
//==============================//
/* 局所情報の各値をとってくる */
for ( i=-2 , k=0 ; i<=2 ; i++ ) {
for ( j=-2 ; j<=2 ; j++ , k++ ) f[k] = id[y+i][x+j] ; // 5x5
}
for ( i=-1 , k=0 ; i<=1 ; i++ ) {
for ( j=-1 ; j<=1 ; j++ , k++ ) g[k] = id[y+i][x+j] ; // 3x3
}
/*** メジアン値を求める ***/
for( j=0 ; j<(25-1) ; j++ ){
for( i=j+1 ; i<25 ; i++ ){
if( f[j] > f[i]){
ssort = f[j] ; // 小さい方を前に持ってくる
f[j] = f[i] ;
f[i] = ssort ;
}
}
}
med = f[12] ; // Median 値の保存
#if DEBUG
printf(" median:[%lf] " , med ) ;
#endif
/*** 入力とメジアンの差に関するルール m ***/
m = fabs( id[y][x] - med ) ;
#if DEBUG
printf(" m:[%lf]\n " , m ) ;
#endif
/*** 入力の孤立に関するルール p ***/
#if DEBUG & DEBUGF
printf("\n 3x3 の情報 : ") ;
for ( i=0 ; i<9 ; i++ ) printf("[%d]" , (int)g[i] ) ;
#endif
for ( i=0 ; i<9 ; i++ ) g[i] = fabs( g[i] - id[y][x] ) ;
for( j=0 ; j<(9-1) ; j++ ){
for( i=j+1 ; i<9 ; i++ ){
if( g[j] > g[i]){
ssort = g[j] ; // 小さい方を前に持ってくる
g[j] = g[i] ;
g[i] = ssort ;
}
}
}
p = ( (g[1]+g[2]) / 2 ) ;
#if DEBUG
printf("\n Sort 後の 3x3 の情報 id[x][y][%d] p[%lf]: " , (int)id[y][x], p ) ;
#if DEBUGF
for ( i=0 ; i<9 ; i++ ) printf("[%d]" , (int)g[i] ) ;
#endif
#endif
//----------------------//
// メンバーシップ関数 //
//----------------------//
//--- m における適合度の設定 ---//
if ( m <= 20.0 ) tkim = 1.0 ;
else if ( m <= 60.0 ) tkim = 0.9 ;
else if ( m <= 80.0 ) tkim = 0.8 ;
else if ( m <= 100.0 ) tkim = 0.2 ;
else tkim = 0.1 ;
//--- p における適合度の設定 ---//
if ( p <= 10.0 ) tkip = 1.0 ;
else if ( p <= 20.0 ) tkip = 0.7 ;
else if ( p <= 30.0 ) tkip = 0.3 ;
else if ( p <= 50.0 ) tkip = 0.2 ;
else tkip = 0.1 ;
#if DEBUG
printf("m()=%lf : %lf p()=%lf :%lf \n", m, tkim, p, tkips );
#endif
//------------------------//
// ファジイルールの設定 //
//------------------------//
yr = tkim * tkip ; // 処理係数の設定
#if DEBUG
printf("%lf %lf %lf %lf \n",u[0], u[1], u[2], u[3] ) ;
#endif
od[y][x] = ( med + yr*(id[y][x]-med) ) ; // 最終的な画像の値
#if DEBUG
printf("uw[%lf] u[%lf] yr[%lf] id[%d] med[%lf] od[%d]\n", sumuw, sumu, yr, (int)id[y][x], med, (int)od[y][x] ) ;
getch() ;
#endif
return ;
}
//======================================================================//
// MSE の算出 //
// //
// 外部変数として以下の配列を指定する //
// org[][] : オリジナル画像 //
// od[][] : DV/BV を算出する画像 //
//======================================================================//
double mse( void )
{
int x, y ; // Counter
double mse , tmse ; // MSE 計算用
tmse = 0.0 ;
for( y=2 ; y<ysize-2 ; y++ ){
for( x=2 ; x<xsize-2 ; x++ ){
mse = ( od[y][x] - org[y][x] ) ;
tmse += ( mse * mse ) ;
}
}
tmse /= ( (double)(ysize-2) * (double)(xsize-2) ) ;
printf(" MSE = %f \n" , tmse ) ;
return ( tmse ) ;
}
//======================================================================//
// 雑音部と信号部それぞれにおけるMSE の算出 //
// //
// 外部変数として以下の配列を指定する //
// org[][] : オリジナル画像 //
// od[][] : MSE を算出する画像 //
// map[][] : 雑音部と信号部を分ける MAP //
//======================================================================//
int map[ysize][xsize] ; // 雑音部と信号部を分ける Map 用配列
void mapmse( void )
{
int x, y ; // Counter
double mse , tmsen , tmses ; // MSE 計算用
double nsize ; // 画像におけるノイズの数
//--- MAP 作成 (雑音部と信号部を分ける) ---//
for( y=0 ; y<ysize ; y++ ){
for( x=0 ; x<xsize ; x++ ){
if ( id[y][x] == org[y][x] ) map[y][x] = 0 ;
else map[y][x] = 1 ;
}
}
tmses = tmsen = nsize = 0.0 ;
for( y=2 ; y<ysize-2 ; y++ ){
for( x=2 ; x<xsize-2 ; x++ ){
if ( map[y][x] ) { // 雑音部分の MSE
mse = ( od[y][x] - org[y][x] ) ;
tmsen += ( mse * mse ) ;
nsize ++ ; // 雑音部のカウント
}
else { // 信号部分の MSE
mse = ( od[y][x] - org[y][x] ) ;
tmses += ( mse * mse ) ;
}
}
}
tmsen /= nsize ;
tmses /= ( (double)(ysize-2) * (double)(xsize-2) - nsize ) ;
printf(" MSE(Noise)[%f] = %f , MSE(Signal) = %f \n" , nsize , tmsen , tmses ) ;
return ;
}
/************************************************************************/
/* << BMP画像ファイル書き込みルーチン ( 8 bit save only) >> */
/* 対象: 256x256x65536 は 256x256x256 のデータに変換する */
/* */
/* input *fn 出力ファイル名ポインタ */
/* *rdat 計算後のデータポインタ */
/* */
/* return none */
/* */
/************************************************************************/
void Gf_write_bmp( char *fn , double *rdat )
{
char out_fn[14] ;
char *inp_fn = Inp_fn ;
unsigned long i ;
int j ;
BYTE fdat[256] ; // 一時画像エリアの確保
FILE *fp ;
unsigned long cv ;
printf(" BMPファイルの書き込み\n") ;
//--- 書出ファイルを 8ビットに変換する ---//
gf_write_to8chg( rdat ) ;
//--- ファイルのOPEN --//
strcpy( Out_fn , fn ) ; // 入力ファイル名の設定
if ( Out_fn[0] == '\0' ) { // ファイル名の確認
printf("\nPlase Input OutputFile Name :") ; //
scanf("%s", &Out_fn[0] ) ; // ファイル名の入力
} //
printf(" Output File Name : [%s]\n" , Out_fn ) ; //
fp = fopen( Out_fn,"wb" ) ; // ファイルの OPEN
//--- ファイルの書き込み状態バーの表示等 --//
cv = 256.0 / 20.0 ;
printf("0%% 50%% 100%%\n") ;
printf("|--------+----------|\n") ;
//--- ヘッダファイルの書き込み ---//
put_header_bmp( fp , 0x100 , 0x100 ) ;
put_palette_bmp( fp ) ;
//--- ファイルの書き込み --//
for ( i=0 ; i<Memsize ; i++ ) rdat ++ ; // 画像右下を始値にする
for ( i=0 ; i<256 ; i++ ) {
for ( j=255 ; j>=0 ; j-- ) {
rdat -- ;
fdat[j] = ( (BYTE)*rdat & 0xff ) ;
}
fwrite( fdat, 256, 1, fp) ; // 下位8ビットを書き出す
//--- ファイル書込状態の表示 ---//
if ( cv < i ) {
printf("o") ;
cv += ( 256.0 / 20.0 ) ;
}
}
printf("\n") ;
fclose(fp) ;
return ;
}
/************************************************************************/
/* << 書き出し用画像ファイルを 8 bit に変換するルーチン >> */
/* */
/* input *rdat 取込用データエリア */
/* */
/************************************************************************/
void gf_write_to8chg( double *wdat )
{
double max , cn, tmp ;
double *rdat = wdat ;
long i ;
printf("書出画像を8ビットに変換\n") ;
//--- 最高値の検出 ---//
for ( i=0 ; i<Memsize ; i++ ) {
if ( max < *rdat ) max = *rdat ;
rdat ++ ;
}
printf("書き出しファイルの最高値:[%f]", max ) ;
#if DEBUG
getch() ; // 一時停止
#endif
rdat = wdat ; // ポインタを最初の位置へ
if ( max > 255.0 ) {
printf("..変換中\n") ;
cn = max / 255.0 ; // 正規化係数の算出
for ( i=0 ; i<Memsize ; i++ , rdat++ ) {
tmp = ( *rdat / cn ) ;
*rdat = tmp ; // データの保存
#if DEBUG
printf("(%lf)", *rdat) ;
#endif
}
}
else printf("..無変換..\n") ;
#if DEBUG
getch() ; // 一時停止
#endif
return ;
}
/************************************************************************/
/* Bit Map File 変換用 関数 */
/************************************************************************/
/************************************************************************/
/* << BMP ヘッダ書出関数 (8 bit only) >> */
/* 色ビット数[bit/dot]は (1,4,8,24) のうち 8 bit のみ */
/* */
/* input *sput ファイルポインタ */
/* rx 画像Xサイズ [dot](1〜) */
/* ry 画像Yサイズ [dot](1〜) */
/* */
/* return 0 nomalend */
/* 1 画面サイズエラー */
/* 2 ファイル書出エラー */
/* */
/************************************************************************/
int put_header_bmp( FILE *sput , int rx , int ry )
{
int i , // ループ変数
color = 256 ; // 色数 [ 8 bit なので色数は 256 ]
unsigned long headsize , // ヘッダサイズ [byte]
imagesize ; // 画面サイズ
if ( (rx<=0) || (ry<=0) ) return(1) ; // 画面サイズの確認
if ( (sput==NULL) || ferror(sput) ) return(2) ; // ファイル書出の確認
headsize = 14 + 40 + 4*color ; // BMP File headre + BMP 情報 header + 色数
imagesize = (unsigned long)rx * (unsigned long)ry ;
//-- ビットマップ・ファイル・ヘッダの書出 --//
fputs("BM", sput) ; // 識別文字列
fputc4lh( headsize+imagesize , sput) ; // ファイルサイズ[byte]
fputc2lh( 0 , sput ) ; // 予約領域[byte]
fputc2lh( 0 , sput ) ; // 予約領域[byte]
fputc4lh( headsize , sput ) ; // ヘッダサイズ[byte]
if ( ferror(sput) ) return(2) ; // ファイル書出の確認
//-- ビットマップ情報ヘッダの書出 --//
fputc4lh( 40 , sput ) ; // 情報サイズ[byte]
fputc4lh( rx , sput ) ; // 画像Xサイズ [dot]
fputc4lh( ry , sput ) ; // 画像Yサイズ [dot]
fputc2lh( 1 , sput ) ; // 面数
fputc2lh( 8 , sput ) ; // 色ビット数[bit/dot] (8 bit)
fputc4lh( 0 , sput ) ; // 圧縮方式
fputc4lh( imagesize , sput ) ; // 圧縮サイズ [byte]
fputc4lh( 0 , sput ) ; // 水平解像度
fputc4lh( 0 , sput ) ; // 垂直解像度
fputc4lh( color , sput ) ; // 色数
fputc4lh( color , sput ) ; // 重要色数
if ( ferror(sput) ) return(2) ; // ファイル書出の確認
return(0) ;
}
/************************************************************************/
/* << BMP パレット書出関数 (白黒256階調) >> */
/* */
/* input *sput ファイルポインタ */
/* */
/* return 0 nomalend */
/* 2 ファイル書出エラー */
/* */
/************************************************************************/
int put_palette_bmp( FILE *sput )
{
int i ;
for ( i=0 ; i<256 ; i++ ) {
putc( i , sput ) ; // 青
putc( i , sput ) ; // 緑
putc( i , sput ) ; // 赤
putc( 0 , sput ) ; // α
}
if ( ferror(sput) ) return(2) ; // ファイル書出の確認
return(0) ;
}
/************************************************************************/
/* << ファイル2バイト低高書出関数 >> */
/* */
/* input rdat 取込用データエリア */
/* *sput ファイルポインタ */
/* */
/************************************************************************/
int fputc2lh( WORD d , FILE *sput )
{
putc( d & 0xff , sput ) ;
return( putc( d >> CHAR_BIT, sput ) ) ;
}
/************************************************************************/
/* << ファイル4バイト低高書出関数 >> */
/* */
/* input rdat 取込用データエリア */
/* *sput ファイルポインタ */
/* */
/************************************************************************/
int fputc4lh( unsigned long d , FILE *sput )
{
putc( d & 0xff , sput ) ;
putc( (d >> CHAR_BIT) & 0xff , sput ) ;
putc( (d >> CHAR_BIT*2) & 0xff , sput ) ;
return
putc( (d >> CHAR_BIT*3) & 0xff , sput ) ;
}
/*****************************************************************************/
/* EEEEEEEE NN NN DDDDD */
/* EE NNN NN DD DD */
/* EEEEEE NN N NN DD DD */
/* EE NN NNN DD DD */
/* EEEEEEEE NN NN DDDDDDDD */
/*****************************************************************************/