

/* Copyright (c) 1991, 1992 Cornell University.  All Rights Reserved.
 *
 * Use, reproduction and preparation of derivative works of this software is
 * permitted.  Any copy of this software or of any derivative work must
 * include both the above copyright notices of Cornell University and this
 * paragraph.  This software is made available AS IS, and Cornell University
 * disclaims all warranties, express or implied.
 */



/*  Greg Klanderman

    Canny Edge Detector
      written  5/18/90
      modified 9/10/91 to add command line arguments
                       and use PFM and PBM file formats
      modified 12/3/92 to add two threshold hysteresis described by Canny
*/

#include <stdio.h>
#include <math.h>

#include "clarg.h"
#include "canny.h"
#include "string-support.h"


static char *USAGE =
  "\n%s:  Canny Edge Detector\n"
  "\n"
  "Arguments are:\n"
  "   -input  file:        Specify the input file name (PFM)\n"
  "   -output file:        Specify the output file name (PBM or PFM)\n"
  "   -threshold t1 [t2]:  Specify the thresholds (may be real)\n"
  "   -relative:           Thresholds should be scaled by an estimate of the\n"
  "                        noise in the magnitude of the gradient.\n"
  "                        ** This is not recommended for sigma > 2.5 or < .7.\n"
  "   -magnitude:          Output the edges scaled by the gradient magnitude (PFM)\n"
  "                        instead of a simple binary edge map.\n"
  "\n"
  "If no input file is specified, input is from stdin, and if no output file\n"
  "is specified, output is to stdout.  If no threshold is specified, a\n"
  "threshold of zero is used.  Using two thresholds gives a hysteresis effect:\n"
  "On a ridge pixel, if the gradient magnitude is over the high threshold, then\n"
  "it is definitely an edge pixel.  If the gradient magnitude is less than the\n"
  "low threshold, then it is not an edge pixel.  Otherwise, the pixel is an edge\n"
  "if it is adjacent to another edge pixel.  Note that this is recursive.  This\n"
  "usually takes abt .2 to .5 sec more.  Argument names may be abreviated.\n\n";

#define INPUT    "i.nput"
#define OUTPUT   "o.utput"
#define THRESH   "t.hreshold"
#define RELATIVE "r.elative"
#define MAG      "m.agnitude"


static CLINIT clinit[] = {{INPUT,    1, 1, NULL,    0},
			  {OUTPUT,   1, 1, NULL,    0},
			  {THRESH,   1, 2, cl_real, 0},
			  {RELATIVE, 0, 0, NULL,    0},
			  {MAG,      0, 0, NULL,    0},
			  {NULL,     1, 1, NULL,    0}};

static char *depend[] = {"!(UNNAMED && "INPUT")", NULL};


int main(int argc, char **argv, char **envp)
{
  char *infile, *outfile;
  FloatImage  image;
  BinaryImage edges;
  float thresh1, thresh2;
  FloatImage  mag = (FloatImage) NULL;
  boolean want_mag, rel;
  AnyImage out;
  String msg = NULLSTRING;
  int imno;
  

  if (cl_init(argc, argv, envp, clinit, depend, USAGE, CL_NORESTRICT))
    return 0;

  infile   = (cl_opt(INPUT)
	      ? cl_arg1(INPUT)
	      : cl_opt(CL_UNNAMED) ? cl_arg1(CL_UNNAMED) : NULL);
  outfile  = cl_opt(OUTPUT) ? cl_arg1(OUTPUT) : NULL;
  thresh1  = cl_opt(THRESH) ? atof(cl_arg1(THRESH)) : 0.0;
  thresh2  = (cl_numarg(THRESH)==2) ? atof(cl_arg2(THRESH)) : -10.0;
  want_mag = cl_opt(MAG);
  rel      = cl_opt(RELATIVE);
  

  imno = 0;                                  /* read in image(s) */
  while ((imno == 0 || infile == NULL) &&
         (image = imLoad(IMAGE_FLOAT, infile))) {
    imno++;

    edges = cannyEdges(image, thresh1, thresh2,
                       mutate: want_mag,
                       relative: rel,
                       mag: want_mag ? &mag : NULL);

    if (edges == (BinaryImage) NULL) {
      fprintf(stderr, "CANNY: Error computing edges\n");
      return 0;
    }

    out = (want_mag) ? (AnyImage) mag : (AnyImage) edges;
  
    imDocString(out) = strNewComment(argc, argv, envp, imDocString(image), NULLSTRING);

    msg = strPrintF(NULL, "\n >>\n >>     Threshold One:  %12.5f", CannyThreshold1);
    strCat(imDocString(out), msg);
  
    if (cl_numarg(THRESH)==2) {
      msg = strPrintF(NULL, "\n >>     Threshold Two:  %12.5f", CannyThreshold2);
      strCat(imDocString(out), msg);
    }

    if (rel) {
      strPrintF(msg, "\n >>     Noise Estimate: %12.5f", CannyNoiseEstimate);
      strCat(imDocString(out), msg);
    }

    strFree(msg);

    if (imSave(out, outfile)) {
      fprintf(stderr, "CANNY: Unable to save edges\n");
    }

    imFree(image);
    imFree(edges);
    if (want_mag) 
      imFree(mag);
    mag = (FloatImage) NULL;
  }  

  if (imno == 0) {                           /* read input */
    fprintf(stderr, "CANNY: Error reading input file\n");
    return 0;
  }

  return 0;
}


