study

画像処理 メディアンフィルタとは?

メディアンフィルタを知る前に空間フィルタリングについてお話ししたいと思います。空間フィルタリング(Spatial filtering)とは、入力画像に注目する画素値だけでなく、周囲にある画素値も利用して、出力画像の画素値を計算する処理のことです。この計算のことを畳み込み演算と言います。

メディアンとは、データを小さい順に並べたときの真ん中の値のことを示しています。つまり、中央値を利用した空間フィルタリングがメディアンフィルタということになります。メディアンフィルタでは画像内の周囲と大きく異なる画像を取り出すことができます。それによって、画像からゴマ塩ノイズを除去することができます。

メディアンフィルタの処理手順

1. 注目画素とその近傍の画素値を取得

    2. 9つの画素値を小さい順にソート
    3. 中央値(3×3なら5番目に大きい値)を注目画素の新しい画素値とする。

つまり、5番目の画素値しか変わらないということです。それ以外は元の画素値です。
サンプルプログラムを下に記します。

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define IMAGESIZE 256
#define MAXGRAY 255
#define MINGRAY 0
void zero_image(float image[IMAGESIZE][IMAGESIZE])
{
  int m,n;
  for(m = 0; m < IMAGESIZE; m++)
  for(n = 0; n < IMAGESIZE; n++)
  image[m][n] = 0.0;
}
int get_image_stdin(float image[IMAGESIZE][IMAGESIZE])
{
  int m,n,pixel;
  for(m = 0; m < IMAGESIZE; m++)
  for(n = 0; n < IMAGESIZE; n++)
  {
    pixel = fgetc(stdin);
    if (pixel == EOF)
    {
      fprintf(stderr,"Find out EOF at the pixel(%d,%d).\n",m,n);
      return(EXIT_FAILURE);
    }
    if (pixel > MAXGRAY)
    pixel = MAXGRAY;
    else if (pixel < MINGRAY)
    pixel = MINGRAY;
    image[m][n] = (float)pixel;
  }
  return(EXIT_SUCCESS);
}
int put_image_stdout(float image[IMAGESIZE][IMAGESIZE])
{
  int m,n,pixel,result;
  for(m = 0; m < IMAGESIZE; m++)
  for(n = 0; n < IMAGESIZE; n++)
  {
    pixel = (int)(image[m][n] + 0.5);
    if (pixel > MAXGRAY)
    pixel = MAXGRAY;
    else if (pixel < MINGRAY)
    pixel = MINGRAY;
    result = fputc(pixel, stdout);
    if (result == EOF)
    {
      fprintf(stderr,"Can’t write image data at the pixel(%d,%d).\n",m,n);
      return(EXIT_FAILURE);
    }
  }
  return(EXIT_SUCCESS);
}
float limit_pixel(float pixel)
{
  float level;
  if (pixel > (float)MAXGRAY)
  level = (float)MAXGRAY;
  else if (pixel < (float)MINGRAY)
  level = (float)MINGRAY;
  else
  level = pixel;
  return(level);
}
void reverse_image(float image[IMAGESIZE][IMAGESIZE])
{
  int m, n;
  for(m = 0; m < IMAGESIZE; m++)
  for(n = 0; n < IMAGESIZE; n++)
  {
    image[m][n] = limit_pixel(image[m][n]);
    image[m][n] = (float)MAXGRAY - image[m][n];
  }
}

int main()
{
  int m, n, i, j;
  int table[8];
  float dx, dy;
  float image[IMAGESIZE][IMAGESIZE], edge[IMAGESIZE][IMAGESIZE];
  
  get_image_stdin(image);
  
  for(m = 1; m < IMAGESIZE-1; m++)
  
  for(n = 1; n < IMAGESIZE-1; n++)
  {
    if ( m== 0 || m == IMAGESIZE-1 || n == 0 || n == IMAGESIZE-1 )
    {
      edge[m][n] = image[m][n];
    }
    else
    {
      table[0] = image[m-1][n-1];
      table[1] = image[m-1][n];
      table[2] = image[m-1][n+1];
      table[3] = image[m][n-1];
      table[4] = image[m][n];
      table[5] = image[m][n+1];
      table[6] = image[m+1][n-1];
      table[7] = image[m+1][n];
      table[8] = image[m+1][n+1];
      for(i=0;i<8;i++)
      {
        for(j=i+1;j<8;j++)
        {
          if(table[i]>table[j])
          {
            int tmp;
            tmp=table[j];
            table[j]=table[i];
            table[i]=tmp;
          }
        }
      }
      edge[m][n]=table[4];
    }
    
  }
put_image_stdout(edge);

}

このソースコードは256×256の白黒画像で実行することができます。画像のサイズを変えたいときは#define IMAGESIZE 256を変えてください。また正方形の画像でないときはIMAGESIZEを縦と横の二つを定義させる必要があります。

コンパイルの方法はgcc median.c -lm

実行方法は./a.out <入力する画像ファイル名.拡張子>  出力する画像ファイル名

入力画像

出力画像