/*****************************************************************
 * fledge.c: FBM Release 1.0 25-Feb-90 Michael Mauldin
 *
 * Copyright (C) 1989,1990 by Gary Sherwin & Michael Mauldin.
 * Permission is granted to use this file in whole or in part for
 * any purpose, educational, recreational or commercial, provided
 * that this copyright notice is retained unchanged.  This software
 * is available to all free of charge by anonymous FTP and in the
 * UUNET archives.
 *
 * fledge.c:
 *
 * CONTENTS
 *	findedge_fbm (&image, beta)
 *
 * EDITLOG
 *	LastEditDate = Mon Jun 25 00:05:13 1990 - Michael Mauldin
 *	LastFileName = /usr2/mlm/src/misc/fbm/fledge.c
 *
 * HISTORY
 * 25-Jun-90  Michael Mauldin (mlm@cs.cmu.edu) Carnegie Mellon
 *	Package for Release 1.0
 *
 * 07-Mar-89  Michael Mauldin (mlm) at Carnegie Mellon University
 *	Beta release (version 0.9) mlm@cs.cmu.edu
 *
 * 21-Aug-88  Michael Mauldin (mlm) at Carnegie-Mellon University
 *	Created with help from Gary Sherwin of Westinghouse Elec.
 *****************************************************************/

# include <stdio.h>
# include <math.h>
# include <ctype.h>
# include "fbm.h"

/****************************************************************
 * findedge_fbm: determine whether image is in color, and call the
 *	        appropriate edge detection routine.
 ****************************************************************/

#ifndef lint
static char *fbmid =
"$FBM fledge.c <1.0> 25-Jun-90  (C) 1989,1990 by Michael Mauldin, source \
code available free from MLM@CS.CMU.EDU and from UUNET archives$";
#endif

findedge_fbm (input, output, beta)
FBM *input, *output;
int beta;
{
  if (input->hdr.planes == 1)
  { return (findedge_bw (input, output, beta)); }
  else
  { return (findedge_bw (input, output, beta)); }
}

/****************************************************************
 * findedge_bw: use a digital Laplacian filter to edge detect a BW image
 ****************************************************************/

findedge_bw (input, output, beta)
FBM *input, *output;
int beta;
{ register unsigned char *bmp, *obm;
  register int i, j, rowlen, w, h;
  int new, sum;
  int bf, wf, tf; /* white and black pixel counters */

/* Filter Chip
*
*
* UL, UC, UR
* CL, CC, CR
* BL, BC, BR
*
*/

  if (input->hdr.planes != 1)
  { fprintf (stderr, "findedge_bw: can't process color images\n");
    return (0);
  }

  fprintf (stderr, "Edge detect BW, beta %d\n", beta);

  /* Allocate output */
  output->hdr = input->hdr;
  alloc_fbm (output);

  w = input->hdr.cols;
  h = input->hdr.rows;
  rowlen = input->hdr.rowlen;

  /* Set pixel counters for image statistics */
  bf = wf = tf = 0;

  /* Compute outer border of pixels */
    /* Compute Top Line U of Pixels */
      /* Compute ULPixel */
   
  j=0;
  { bmp = &(input->bm[j*rowlen]);
    obm = &(output->bm[j*rowlen]);
    
    i=0;
    { sum = 0;
      sum = sum + (bmp[i]*(-3)     + bmp[i+1]       );
      sum = sum + (bmp[i+rowlen]   + bmp[i+rowlen+1]);
      sum = (sum * 8) / 3;

      if (sum > beta) { new = BLACK; bf++; }
      else { new = WHITE; wf++; }

      tf++;

      obm[i] = new;

    }

    /* Compute URPixel */
   
    i=w;
    { sum = 0;
      sum = sum + (bmp[i-1]*(-3)     + bmp[i]         ) ;
      sum = sum + (bmp[i+rowlen-1]   + bmp[i+rowlen]  ) ;
      sum = (sum * 8) / 3;

      if (sum > beta) { new = BLACK; bf++; }
      else { new = WHITE; wf++; }

      tf++;

      obm[i] = new;

    }

   /* Compute Rest of U1 Line */
  
    for (i=1; i < w-1; i++)
    { sum = 0;
      sum = sum + (bmp[i-1]*(-5)   + bmp[i]        + bmp[i+1]       ) ;
      sum = sum + (bmp[i+rowlen-1] + bmp[i+rowlen] + bmp[i+rowlen+1]) ;
      sum = (sum * 8) / 5;

      if (sum > beta) { new = BLACK; bf++; }
        else { new = WHITE; wf++; }

      tf++;

      obm[i] = new;

    }
  }

  /* Compute Left and Right borders */
  
  for (j=1; j < h-1; j++)
  { bmp = &(input->bm[j*rowlen]);
    obm = &(output->bm[j*rowlen]);

    /* Compute L Pixel */   
    i=0;
    { sum = 0;
      sum = sum + (bmp[i-rowlen]   + bmp[i-rowlen+1]) ;
      sum = sum + (bmp[i]*(-5)     + bmp[i+1]       ) ;
      sum = sum + (bmp[i+rowlen]   + bmp[i+rowlen+1]) ;
      sum = (sum * 8) / 5;

      if (sum > beta) { new = BLACK; bf++; }
      else { new = WHITE; wf++; }

      tf++;

      obm[i] = new;

    }


    /* Compute R1Pixel */
    i=w;
    { sum = 0;
      sum = sum + (bmp[i-rowlen-1]   + bmp[i-rowlen]  ) ;
      sum = sum + (bmp[i-1]          + bmp[i]*(-5)    ) ;
      sum = sum + (bmp[i+rowlen-1]   + bmp[i+rowlen]  ) ;
      sum = (sum * 8) / 5;

      if (sum > beta) { new = BLACK; bf++; }
      else { new = WHITE; wf++; }
 
      tf++;

      obm[i] = new;

    }
  }

    /* Compute Bottom Line B of Pixels */
    /* Compute BL Pixel */ 
  j=h;
  { bmp = &(input->bm[j*rowlen]);
    obm = &(output->bm[j*rowlen]);
    
    i=0;
    { sum = 0;
      sum = sum + (bmp[i-rowlen]   + bmp[i-rowlen+1]) ;
      sum = sum + (bmp[i]*(-3)     + bmp[i+1]       ) ;
      sum = (sum * 8) / 3;

      if (sum > beta) { new = BLACK; bf++; }
      else { new = WHITE; wf++; }
 
      tf++;

      obm[i] = new;

    }

       /* Compute BR Pixel */

    i=w;
    { sum = 0;
      sum = sum + (bmp[i-rowlen-1]   + bmp[i-rowlen]  ) ;
      sum = sum + (bmp[i-1]          + bmp[i]*(-3)    ) ;
      sum = (sum * 8) / 3;

      if (sum > beta) { new = BLACK; bf++; }
      else { new = WHITE; wf++; }

      tf++;

      obm[i] = new;

    }

      /* Compute Rest of B1 Line */

    for (i=1; i < w-1; i++)
    { sum = 0;
      sum = sum + (bmp[i-rowlen-1]   + bmp[i-rowlen]   + bmp[i-rowlen+1]) ;
      sum = sum + (bmp[i-1]          + bmp[i]*(-5)     + bmp[i+1]       ) ;
      sum = (sum * 8) / 5;

      if (sum > beta) { new = BLACK; bf++; }
      else { new = WHITE; wf++; }

      tf++;

      obm[i] = new;

    }
  }

  /* Compute Main Image Body */

  for (j=1; j < h-1; j++)
  { bmp = &(input->bm[j*rowlen]);
    obm = &(output->bm[j*rowlen]);
    
    for (i=1; i < w-1; i++)
    { sum = 0;
      sum = sum + (bmp[i-rowlen-1]   + bmp[i-rowlen]   + bmp[i-rowlen+1]) ;
      sum = sum + (bmp[i-1]          + bmp[i]*(-8)     + bmp[i+1]       ) ;
      sum = sum + (bmp[i+rowlen-1]   + bmp[i+rowlen]   + bmp[i+rowlen+1]) ;

      if (sum > beta) { new = BLACK; bf++; }
      else { new = WHITE; wf++; }

      tf++;

      obm[i] = new;

    }
  }

  fprintf (stderr, "Edge detection complete for slope of %2d for %d pixels.\n", beta, tf);
  fprintf (stderr, "Detected %d white pixels and %d black pixels.\n", bf, wf);

  return (1);
}

/****************************************************************
 * findedge_clr: use a digital Laplacian filter to edge detect a CLR image
 ****************************************************************/

findedge_clr (input, output, beta)
FBM *input, *output;
double beta;
{ register unsigned char *bmp, *obm, *avg;
  register int i, j, k, rowlen, plnlen, w, h, p, sum;
  int new, delta, beta100 = beta * 100;
  unsigned char *gray;

  fprintf (stderr, "Sharpen color, beta %lg\n", beta);

  /* Allocate output */
  output->hdr = input->hdr;
  alloc_fbm (output);

  w = input->hdr.cols;
  h = input->hdr.rows;
  p = input->hdr.planes;
  rowlen = input->hdr.rowlen;
  plnlen = input->hdr.plnlen;
  
  /* Calculate the intensity plane */
  gray = (unsigned char *) malloc (plnlen);

  for (j=0; j<h; j++)  
  { bmp = &(input->bm[j*rowlen]);
    avg = &(gray[j*rowlen]);    

    for (i=0; i<w; i++)
    { sum = 0;
      for (k=0; k<p; k++)
      { sum += bmp[i+k*plnlen]; }
      avg[i] = sum/p;
    }
  }
  
  /* Copy edges directly */
  for (k=0; k<p; k++)
  {  for (j=0; j<h; j++)
    { output->bm[k*plnlen + j*rowlen] =
	input->bm[k*plnlen + j*rowlen];
      output->bm[k*plnlen + j*rowlen + w-1] =
	input->bm[k*plnlen + j*rowlen + w-1];
    }
  
    for (i=0; i<w; i++)
    { output->bm[k*plnlen + i] =
	input->bm[k*plnlen + i];
      output->bm[k*plnlen + (h-1)*rowlen + i] =
	input->bm[k*plnlen + (h-1)*rowlen + i];
    }
  }

  for (j=1; j < h-1; j++)
  { avg = &(gray[j*rowlen]);
    
    for (i=1; i < w-1; i++)
    { sum = avg[i-rowlen-1] +     avg[i-rowlen] + avg[i-rowlen+1] +
	    avg[i-1]        - 8 * avg[i]        + avg[i+1]        +
	    avg[i+rowlen-1] +     avg[i+rowlen] + avg[i+rowlen+1];

      for (k=0; k<p; k++)
      { bmp =  &(input->bm[k*plnlen + j*rowlen + i]);
        obm = &(output->bm[k*plnlen + j*rowlen + i]);
        
	if (sum < 0)
	{ delta = - (beta100 * *bmp * -sum / (8*100)); }
	else
	{ delta = beta100 * *bmp * sum / (8*100); }
  
	new = *bmp - delta;
  
	if (new < BLACK) new = BLACK;
	else if (new > WHITE) new = WHITE;
	
	*obm = new;
      }
    }
  }
}
