Listing 3 (edge.c)

      /***********************************************
      *
      *    file d:\cips\edge.c
      *
      *    Functions: This file contains
      *       detect_edges
      *       setup_masks
      *       get_edge_options
      *       perform_convolution
      *       quick_edge
      *       fix_edges
      *
      *    Purpose:
      *       These functions implement several
      *       types of basic edge detection.
      *
      *    External Calls:
      *       wtiff.c - does_not_exist
      *                 round_off_image_size
      *                 create_allocate_tiff_file
      *                 write_array_into_tiff_image
      *       tiff.c - read_tiff_header
      *       rtiff.c - read_tiff_image
      *       numcvrt.c - get_integer
      *
      *
      *    Modifications:
      *    27 January 1991 - created
      *
      ***********************************************/

#include "d:\cips\cips.h"


short quick_mask[3] [3] = {
      {-1,  0,  -1},
      { 0,  4,   0},
      (-1,  0,  -1} };


   /***************************
   *
   * Directions for the masks
   * 3 2 1
   * 4 x 0
   * 5 6 7
   *
   ****************************/

   /* masks for kirsch operator */
short kirsch_mask_0[3] [3] = {
   { 5,   5,   5},
   {-3,   0,  -3},
   {-3,  -3,  -3} };

short kirsch_mask_1[3] [3] = {
      {-3,   5,   5},
      {-3,   0,   5},
      {-3,  -3,  -3} };

short kirsch_mask_2[3] [3] = {
      {-3,  -3,  5},
      {-3,   0,  5},
      {-3,  -3,  5} };

short kirsch_mask_3[3] [3] = {
      {-3,  -3,  -3},
      {-3,   0,   5},
      {-3,   5,   5} };

short kirsch_mask_4[3] [3] = {
      {-3,  -3,  -3},
      {-3,   0,  -3},
      { 5,   5,   5} };


short kirsch_mask_5[3] [3] = {
      {-3,  -3,  -3},
      { 5,   0,  -3},
      { 5,   5,  -3) };

short kirsch_mask_6[3] [3] = {
      { 5,  -3,  -3},
      { 5,   0,  -3},
      { 3,  -3,  -3} };

short kirsch_mask_7[3][3] = {
      { 5,   5,  -3},
      { 5,   0,  -3},
      {-3,  -3,  -3} };

   /*  masks for prewitt operator */
short prewitt_mask_0[3] [3] = {
      { 1,   1,   1},
      { 1,  -2,   1},
      {-1,  -1,  -1} };

short prewitt_mask_1[3] [3] = {
      { 1,   1,   1},
      { 1,  -2,  -1},
      {-1,  -1,  -1} };

short prewitt_mask_2[3] [3] = {
      { 1,   1,  -1},
      { 1,  -2,  -1},
      { 1,   1,  -1} };

short prewitt_mask_3[3] [3] = {
      { 1,  -1,  -1},
      { 1,  -2,  -1},
      { 1,   1,   1} };

short prewitt_mask_4[3] [3] = {
      {-1,  -1,  -1},
      { 1,  -2,   1},
      { 1,   1,   1} };

short prewitt_mask_5[3] [3] = {
      {-1,  -1,  1},
      {-1,  -2,  1},
      { 1,   1,  1} };

short prewitt_mask_6[3] [3] = {
      {-1,   1,  1},
      {-1,  -2,  1},
      {-1,   1,  1} };

short prewitt_mask_7[3] [3] = {
      { 1,   1,  1},
      {-1,  -2,  1},
      {-1,  -1,  1} };

   /* masks for sobel operator */
short sobel_mask_0[3] [3] = {
      {  1,   2,   1},
      {  0,   0,   0},
      { -1,  -2,  -1} };

short sobel_mask_1[3][3] = {
      { 2,   1,   0},
      { 1,   0,  -1},
      { 0,  -1,  -2} };

short sobel_mask_2[3] [3] = {
      { 1,  0,  -1},
      { 2,  0,  -2},
      { 1,  0,  -1} };

short sobel_mask_3[3] [3] = {
      { 0,  -1,  -2},
      { 1,   0,  -1},
      { 2,   1,   0}};

short sobel_mask_4[3] [3] = {
      {-1,  -2,  -1},
      { 0,   0,   0},
      { 1,   2,   1} };

short sobel_mask_5[3] [3] = {
      {-2,  -1,  0},
      {-1,   0,  1},
      { 0,   1,  2} };

short sobel_mask_6[3] [3] = {
      { -1,  0,  1},
      { -2,  0,  2),
      { -1,  0,  1} };

short sobel_mask_7[3] [3] = {
      { 0,   1,  2),
      {-1,   0,  1},
      {-2,  -1,  0} };

  /**************************************************
  *
  *  detect_edges(...
  *
  *  This function detects edges in an area of one
  *  image and sends the result to another image
  *  on disk. It reads the input image from disk,
  *  calls a convolution function, and then writes
  *  the result out to disk. If needed, it
  *  allocates space on disk for the output image.
  *
  **************************************************/


detect_edges(in_name, out_name, the_image, out_image,
           il, ie, ll, le, detect_type, threshold,
           high)
   char in_name[], out_name[];
   int detect_type, high, il, ie,
       ll, le, threshold;
   short the_image[ROWS] [COLS], out_image[ROWS][COLS];
{
   int i, j, k, length, width;
   struct tiff_header_struct image_header;


   if(does_not_exist(out_name)){
      read_tiff_header(in_name, &image_header);
      round_off_image_size(&image_header,
                        &length, &width);
      image_header.image_length = length*ROWS;
      image_header.image_width - width*COLS;
      create_allocate_tiff_file(out_name, &image_header,
                            out_image);
   } /*  ends if does_not_exist */

   read_tiff_image(in_name, the_image, il, ie, ll, le);

   read_tiff_header(in_name, &image_header);

   perform_convolution(the_image, out_image,
                    detect_type, threshold,
                    &image_header, high);

   fix_edges(out_image, 1);

   write_array_into_tiff_image(out_name, out_image,
                           il, ie, ll, le);
/*  ends detect_edges */


     /**********************************************************
     *
     *  perform_convolution(...
     *
     *  This function performs convolution between the input
     *  image and 8 3x3 masks. The result is placed in
     *  the out_image.
     *
     **********************************************************/


perform_convolution(image, out_image,
                 detect_type, threshold,
                 image_header, high)
   short image[ROWS] [COLS],
        out_image[ROWS] [COLS];
   int detect_type, high, threshold;
   struct tiff_header_struct *image_header;
{
   int a,
      b,
      i,
      is_present,
      j,
      sum;

   short mask_0[3][3],
      mask_1[3][3],
      mask_2[3][3],
      mask_3[3][3],
      mask_4[3][3],
      mask_5[3][3],
      mask_6[3][3],
      mask_7[3][3],
      max,
      min,
      new_hi,
      new_low;

   setup_masks(detect_type, mask_0, mask_1,
             mask_2, mask_3, mask_4, mask_5,
             mask_6, mask 7);

   new_hi = 250;
   new_low = 16;
   if(image_header->bits_per_pixel == 4){
      new_hi = 10;
      new_low = 3;
   }

   min = 0;
   max = 255;
   if (image_header->bits_per_pixel == 4)
      max = 16;

      /*  clear output image array */
   for(i=0; i<ROWS; i++)
      for(j=0; j<COLS; j++)
         out_image[i][j] = 0;

   printf("\n ");

   for(i=1; i<ROWS-1; i++){
      if((i%10) == 0) printf("%3d", i);
      for(j=1; j<COLS-1; j++){


         /*  Convolve for all 8 directions */

         /*  0 direction */

      sum = 0;
      for(a=-1; a<2; a++){
         for(b=-1; b<2; b++){
            sum = sum + image[i+a] [j+b] *
                 mask_0[a+1] [b+1];
         }
      }
         if(sum > max) sum = max;
         if(sum < 0) sum = 0;
      out_image[i][j] = sum;


         /* 1 direction */

      sum = 0;

      for(a=-1; a<2; a++){
         for(b=-1; b<2; b++){
            sum = sum + image[i+a][j+b] * mask_1[a+1][b+1];
         }
      }
         if(sum > max) sum = max;
         if(sum < 0) sum = 0;
      out_image[i][j] = sum;

         /*  2 direction */

      sum = 0;
      for(a=-1; a<2; a++){
         for(b=-1; b<2; b++){
            sum = sum + image[i+a] [j+b] * mask_2[a+1] [b+1];
         }
      }
         if(sum > max) sum = max;
         if(sum < 0) sum = 0;
      out_image[i][j] = sum;

         /* 3 direction */

      sum = 0;
      for(a=-1; a<2; a++){
         for(b=-1; b<2; b++){
            sum = sum + image[i+a] [j+b] * mask_3[a+1] [b+1];
         }
      }
         if(sum > max) sum = max;
         if(sum < 0) sum = 0;
      out_image[i][j] = sum;

         /*  4 direction */

      sum = 0;
      for(a=-1; a<2; a++){
         for(b=-1; b<2; b++){
            sum = sum + image[i+a] [j+b] * mask_4[a+1] [b+1];
         }
      }
         if(sum > max) sum = max;
         if(sum < 0) sum = 0;
      out_image[i] [j] = sum;

         /*  5 direction */

      sum = 0;
      for(a=-1; a<2; a++){
         for(b=-1; b<2; b++){
            sum = sum + image[i+a] [j+b] * mask_5[a+1] [b+1];
         }
      }
         if(sum > max) sum = max;
         if(sum < 0) sum = 0;
      out_image[i] [j] = sum;

         /*  6 direction */

      sum= 0;
      for(a=-1; a<2; a++){
         for(b=-1; b<2; b++){
            sum = sum + image[i+a] [j+b] * mask_6[a+1] [b+1];
         }
      }
         if(sum > max) sum = max;
         if(sum < 0) sum = 0;
      out_image[i][j] = sum;

         /*  7 direction */

      sum = 0;
      for(a=-1; a<2; a++){
         for(b=-1; b<2; b++){
            sum = sum + image[i+a][j+b] * mask_7[a+1][b+1];
         }
      }
         if(sum > max) sum = max;
         if(sum < 0) sum = 0;
      out_image[i][j] = sum;


      } /*  ends loop over j */
   } /*  ends loop over i */


     /* if desired, threshold the output image */
   if(threshold == 1){
      for(i=0; i<ROWS; i++){
         for(j=0; j<COLS; j++){
            if(out_image[i][j] > high){
                out_image[i][j] = new_hi;
            }
            else{
                out_image[i][j] = new_low;
            }
         }
      }
   } /*  ends if threshold == 1 */

} /*  ends perform_convolution */
    /*************************************
    *
    *quick_edge(...
    *
    *This function finds edges by using
    *a single 3x3 mask.
    *
    *************************************/

quick_edge(in_name, out_name, the_image, out image,
           il, ie, ll, le, threshold, high)
   char   in_name[], out_name[];
   int    high, il, ie, ll, le, threshold;
   short  the_image[ROWS][COLS], out_image[ROWS] [COLS];

{
   int    a, b, i, j, k,
         length, max, new_hi, new_low,
         sum, width;
   struct tiff_header_struct image_header;


   if(does_not_exist(out_name)){
      printf("\n\n output file does not exist %s", out_name);
      read_tiff_header(in_name, &image_header);
      round_off_image_size(&image_header,
                        &length, &width);
      image_header.image_length = length*ROWS;
      image_header.image_width = width*COLS;
      create_allocate_tiff_file(out_name, &image_header,
                            out_image);
   } /*  ends if does_not_exist */

   read_tiff_header(in_name, &image_header);
   new_hi  = 250;
   new_low = 16;
   if(image_header.bits_per_pixel == 4){
      new_hi  = 10;
      new_low = 3;
   }

   max = 255;
   if(image_header.bits_per_pixel == 4)
      max = 16;


   read_tiff_image(in_name, the_image, il, ie, ll, le);

      /*  Do convolution over image array */
   printf("\n");
   for(i=1; i<ROWS-1; i++){
      if((i%10) == 0) printf("%d ", i);
      for(j=1; j<COLS-1; j++){
         sum = 0;
         for(a=-1; a<2; a++){
            for(b=-1; b<2; b++){
               sum= sum +
                    the_image[i+a][j+b] *
                    quick_mask [a+1][b+1];
            }
         }
         if(sum < 0)   sum = 0;
         if(sum > max) sum = max;
         out_image[i][j]   = sum;

      } /*  ends loop over j */
   } /*  ends loop over i */

      /*  if desired, threshold the output image */
   if(threshold == 1) {
      for(i=0; i<ROWS; i++){
         for(j=0; j<COLS; j++){
            if(out_image[i][j] > high){
                out_image[i][j] = new_hi;
            }
            else{
                out_image[i][j] = new_low;
            }
         }
      }
   } /*  ends if threshold == 1 */

   fix_edges (out_image, 1);

   write_array_into_tiff_image (out_name, out_image,
                           il, ie, ll, le);

} /* endsquick_edge */


  /*************************************************
  *
  *  set up_masks (...
  *
  *  This function copies the mask values defined
  *  at the top of this file into the mask
  *  arrays mask_0 through mask_7.
  *************************************************/

setup_masks(detect_type, mask_0, mask_1, mask_2, mask_3,
          mask_4, mask_5, mask_6, mask_7) 
   int   detect_type;
   short mask_0[3][3],
        mask_0[3][3],
        mask_2[3][3],
        mask_3[3][3],
        mask_4[3][3],
        mask_5[3][3],
        mask_6[3][3],
        mask_7[3][3];
{
   int i, j;

   if(detect_type == KIRSCH){
      for(i=0; i<3; i++){
         for(j=0; j<3; j++){
           mask_0[i][j] = kirsch_mask_0[i][j];
           mask_1[i][j] = kirsch-mask_1[i][j];
           mask_2[i][j] = kirsch_mask_2[i][j];
           mask_3[i][j] = kirsch_mask_3[i][j];
           mask_4[i][j] = kirsch_mask_4[i][j];
           mask_5[i][j] = kirsch_mask_5[i][j];
           mask_6[i][j] = kirsch_mask_6[i][j];
           mask_7[i][j] = kirsch_mask_7[i][j];
         }
      }
   } /*  ends if detect_type == KIRSCH */


   if(detect_type == PREWITT) {
      for(i=0; i<3; i++){
         for(j=0; j<3; j++){
           mask_0[i][j] = prewitt_mask_0[i][j];
           mask_1[i][j] = prewitt_mask_1[i][j];
           mask_2[i][j] = prewitt_mask_2[i][j];
           mask_3[i][j] = prewitt_mask_3[i][j];
           mask_4[i][j] = prewitt_mask_4[i][j];
           mask_5[i][j] = prewitt_mask_5[i][j];
           mask_6[i][j] = prewitt_mask_6[i][j];
           mask_7[i][j] = prewitt_mask_7[i][j];
         }
      }
   } /*  ends if detect_type == PREWITT */

   if(detect_type == SOBEL){
      for(i=0; i<3; i++){
         for(j=0; j<3; j++){
           mask_0[i][j] = sobel_mask_0[i][j];
           mask_1[i][j] = sobel_mask_1[i][j];
           mask_2[i][j] = sobel_mask_2[i][j];
           mask_3[i][j] = sobel_mask_3[i][j];
           mask 4[i][j] = sobel_mask_4[i][j];
           mask_5[i][j] = sobel_mask_5[i][j];
           mask_6[i][j] = sobel_mask_6[i][j];
           mask_7[i][j] = sobel_mask_7[i][j];
         }
      }
   } /*  ends if detect_type == SOBEL */



} /*  ends setup_masks */


  /**********************************************
  *
  *  get_edge_options(...
  *
  *  This function queries the user for the
  *  parameters need to perform edge
  *  detection.
  *
  ***********************************************\


get_edge_options(detect_type, threshold, high)
   int *detect_type, *high, *threshold;
{
   int not_finished, response;
   not_finished = 1;
   while(not_finished){

    printf("\nThe Edge Detector options are:\n");
    printf("\n\t1.  Type of edge detector is %d", *detect_type);
    printf("\n\t      (recall 1=Prewitt 2=Kirsch 3=Sobel
4=quick)");
    printf("\n\t2.  Threshold output is %d (0=off 1=on)",
*threshold);
    printf("\n\t3.  High threshold is %d", *high);
    printf("\n\nEnter choice (0 = no change) _\b");


    get_integer(&response);

    if(response == 0){
      not_finished = 0;
    }


    if(response == 1){
      printf("\n\nEnter type of edge detector");
      printf("\n   (recall 1=Prewitt 2=Kirsch 3=Sobel 4=quick)");
      printf("\n  _\b");
      get_integer(detect_type);
    }

    if(response == 2){
      printf("\n\nEnter threshold output (0=off 1=on)");
      printf("\n _\b");
      get_integer(threshold);
    }

    if(response == 3){
      printf("\n\nEnter high threshold");
      printf("\n \b");
      get_integer(high);
    }

   } /*  ends while not_finished */

} /*  ends get_edge_options */


  /*********************************************
  *
  *  fix_edges(...
  *
  *  This function fixes the edges of an image
  *  array after convolution was performed.
  *  It copies the points near the edge of the
  *  array out to the edge of the array.
  *
  *********************************************/


fix_edges(im, w)
     int w;
     short im[ROWS] [COLS];
{
   int i, j;
   
   /*  four corners */
  for(i=w; i>0; i--){
   im[i-1] [i-1] = im[i] [i];
   im[i-1] [COLS-(i-1)] = im[i] [COLS-1-(i-1)];
   im[ROWS-(i-1)] [i-1] = im[ROWS-1-(i-1)] [i];
   im[ROWS-(i-1)] [COLS-(i-1)] = im[ROWS-1-(i-1)] [COLS-1-(i-1)];
  }  /* ends four corners loop */
  
  for(i=0; i<ROWS; i++){
     for(j=w; j>0; j--){
      im[i][j-1] = im[i][j];
      im[i] [COLS-j] = im[i] [COLS-j-1];
     }
  }
  
  for(j=0; j<COLS; j++){
     for(i=w; i>0; i--){
      im[i-1][j] = im[i][j];
      im[ROWS-i] [j] = im[ROWS-i-1] [j];
     }
  }
}  /*  ends fix_edges */

/*  End of File */