
/************************************************************************/
#define OP_NAME      "pgmpseudomedian"
#define VERSION      "1.01"
#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;
static int form=1;

void seqauswertung(unsigned char *feld, unsigned char *maxi, unsigned char *mini)
/* bestimmt MAXIMIN und MINIMAX aller Teilsequenzen */
{
  unsigned char mami=0, mima=255, ma, mi;
  int i, j;

  for (i=0; i<=edge; i++)   /* Zahl der Teilsequenzen */
  {
    ma=feld[i];
    mi=feld[i];

    for (j=i+1; j<=i+edge; j++)   /* Zahl der Elemente einer Teilsequenz */
    {
      /* MAX und MIN dieser Teilsequenz suchen */
      if (feld[j]>ma) ma=feld[j];
      else
        if (feld[j]<mi) mi=feld[j];
    }

    /* vorlaeufiges MAXIMIN und MINIMAX merken */
    if (mami<mi) mami=mi;
    if (mima>ma) mima=ma;
  }

  /* Ergebnisse nach aussen uebermitteln */
  *maxi=mami;
  *mini=mima;
}

void Do_It_plus(void)
{
  int i, x, y, k, l, index;
  unsigned char array[9], maximinx, maximiny, minimaxx, minimaxy;
  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=edge; y<m-edge; y++)
    for (x=edge; x<n-edge; x++)
    {
      /* Position berechnen */
      index=y*n+x;

      /* Feld fuellen in x-Richtung */
      i=0;
      for (k=-edge; k<=edge; k++) array[i++]=src[index+k];
      seqauswertung(array, &maximinx, &minimaxx);

      /* Feld fuellen in y-Richtung */
      i=0;
      for (l=-edge; l<=edge; l++) array[i++]=src[index+l*n];
      seqauswertung(array, &maximiny, &minimaxy);

      /* Pseudomedian des Feldes bestimmen */
      if (maximiny>maximinx) maximinx=maximiny;
      if (minimaxy<minimaxx) minimaxx=minimaxy;
      dst[(y-edge)*(n-2*edge)+x-edge]=(maximinx+minimaxx)/2;
    }
}

void Do_It_waage(void)
{
  int i, x, y, k, index;
  unsigned char array[9], maximin, minimax;
  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=0; y<m; y++)
    for (x=edge; x<n-edge; x++)
    {
      /* Position berechnen */
      index=y*n+x;
      i=0;

      /* Feld fuellen in x-Richtung */
      for (k=-edge; k<=edge; k++) array[i++]=src[index+k];
      seqauswertung(array, &maximin, &minimax);

      /* Pseudomedian des Feldes bestimmen */
      dst[y*(n-2*edge)+x-edge]=(maximin+minimax)/2;
    }
}

void Do_It_senk(void)
{
  int i, x, y, l, index;
  unsigned char array[9], maximin, minimax;
  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=edge; y<m-edge; y++)
    for (x=0; x<n; x++)
    {
      /* Position berechnen */
      index=y*n+x;
      i=0;

      /* Feld fuellen in y-Richtung */
      for (l=-edge; l<=edge; l++) array[i++]=src[index+l*n];
      seqauswertung(array, &maximin, &minimax);

      /* Pseudomedian des Feldes bestimmen */
      dst[(y-edge)*n+x]=(maximin+minimax)/2;
    }
}

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

  /* 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 '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 ...");

      /* Pseudomedian-Filterung */
      switch (form)
      {
        case 1: Do_It_plus();  break;

        case 2: Do_It_waage();  break;

        case 3: Do_It_senk();  break;
      }

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

    FreePGMArray(&source);
  }

  PrintClosing();
  exit(0);
}

