
/************************************************************************/
#define OP_NAME      "pgmmedian"
#define VERSION      "1.03"
#define DATE         "30.01.98"
#define AUTHOR       "Stefan Diener"
/************************************************************************/

#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>

#include <STIMP/pgm.c>

struct PGM_Info source, desti;
static int m, n;
static int edge=1, edgex, edgey;
static int form=1;

unsigned char median(unsigned char *feld, int anzahl)
/* Bucket-Sort und mittleres Element zurueckgeben */
{
  int i, mitte=anzahl/2, summe=0;
  static unsigned char bucket[256];

  /* Buckets leeren */
  for (i=0; i<256;) bucket[i++]=0;

  /* Buckets fuellen */
  for (i=0; i<anzahl;) bucket[feld[i++]]++;

  /* Mitte suchen */
  for (i=0; i<256; i++)
  {
    if (bucket[i])
    {
      summe+=bucket[i];
      if (summe>mitte) return (unsigned char) i;
    }
  }

  /* durchgelaufen ??? */
  return 255;
}

void Do_It_normal(void)
{
  int i, x, y, k, l, index;
  unsigned char array[81];
  unsigned char *src, *dst;

  /* Zeiger auf Bilddaten holen */
  src=source.Data;
  dst=desti.Data;
  desti.maxval=source.maxval;

  /* fuer jeden Punkt ausser Rand */
  for (y=edgey; y<m-edgey; y++)
    for (x=edgex; x<n-edgex; x++)
    {
      /* Position berechnen */
      index=y*n+x;
      i=0;

      /* Feld fuellen */
      for (l=-edgey; l<=edgey; l++)
        for (k=-edgex; k<=edgex; k++)
          array[i++]=src[index+l*n+k];

      /* Median des Feldes bestimmen */
      dst[(y-edgey)*(n-2*edgex)+x-edgex]=median(array, i);
    }
}

void Do_It_plus(void)
{
  int i, x, y, k, l, index;
  unsigned char array[18];
  unsigned char *src, *dst;

  /* Zeiger auf Bilddaten holen */
  src=source.Data;
  dst=desti.Data;
  desti.maxval=source.maxval;

  /* fuer jeden Punkt ausser Rand */
  for (y=edgey; y<m-edgey; y++)
    for (x=edgex; x<n-edgex; x++)
    {
      /* Position berechnen */
      index=y*n+x;
      i=0;

      /* Feld fuellen */
      for (l=-edgey; l<=edgey; l++) array[i++]=src[index+l*n];

      for (k=-edgex; k<=edgex; k++)
        if (k!=0) array[i++]=src[index+k];

      /* Median des Feldes bestimmen */
      dst[(y-edgey)*(n-2*edgex)+x-edgex]=median(array, i);
    }
}

int main(int argc,char **argv)
/* main program */
{
  int i;

  /* say hello */
  PrintOpening(argc,argv);

  /* read the parameters */
  for (i=1; i<argc; i++)
  {
    if ((argv[i][0]=='-') && argv[i][1])
    {
      switch (argv[i][1])
      {
        case '3': edge=1;
                      break;

        case '5': edge=2;
                      break;

        case '7': edge=3;
                      break;

        case '9': edge=4;
                      break;

        case 'e': form=3;
                      break;

        case 'h': form=2;
                      break;

        case 'q': form=0;
                      break;

        case 'p': form=1;
                      break;

        case 'v': beVerbose=FALSE;
                      break;

        default: PrintMessage("Unknown parameter: %s", argv[i]);
                     Hilfe();
                     exit(-1);
                     break;
      }
    }

    if (argv[i][0]=='+')
    {
      switch (argv[i][1])
      {
        case 'v': beVerbose=TRUE;
                      break;

        default: PrintMessage("Unknown parameter: %s", argv[i]);
                     Hilfe();
                     exit(-1);
                     break;
      }
    }
  }

  /* check minimal number of arguments */
  if (argc<3)
  {
    PrintMessage("Not enough arguments !");
    Hilfe();
    exit(-1);
  }

  /* check number of file names */
  if (FilenameCount(argc, argv)!=2)
  {
    PrintMessage("Wrong number of file names !");
    Hilfe();
    exit(-1);
  }

  if (ReadPGMFile(GetFilename(1,argc,argv),&source)==0)
  {
    m=source.height;
    n=source.width;

    /* Aussenraender festlegen */
    edgex=(form==3) ? 0 : edge;
    edgey=(form==2) ? 0 : edge;

    if (CreatePGMArray(m-2*edgey, n-2*edgex, &desti)==0)
    {
      PrintMessage("Working ...");

      if (form==1) Do_It_plus();
      else Do_It_normal();

      WritePGMFile(GetFilename(2,argc,argv),&desti);
      FreePGMArray(&desti);
    }

    FreePGMArray(&source);
  }

  PrintClosing();
  exit(0);
}

