 /*
  * Khoros: $Id: llrfclass.c,v 1.1 1991/05/10 15:41:54 khoros Exp $
  */

#if !defined(lint) && !defined(SABER)
static char rcsid[] = "Khoros: $Id: llrfclass.c,v 1.1 1991/05/10 15:41:54 khoros Exp $";
#endif

 /*
  * $Log: llrfclass.c,v $
 * Revision 1.1  1991/05/10  15:41:54  khoros
 * Initial revision
 *
  */ 

/*
 *----------------------------------------------------------------------
 *
 * Copyright 1991, University of New Mexico.  All rights reserved.
 * Permission to copy and modify this software and its documen-
 * tation only for internal use in your organization is hereby
 * granted, provided that this notice is retained thereon and
 * on all copies.  UNM makes no representations as too the sui-
 * tability and operability of this software for any purpose.
 * It is provided "as is" without express or implied warranty.
 * 
 * UNM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT-
 * NESS.  IN NO EVENT SHALL UNM BE LIABLE FOR ANY SPECIAL,
 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY OTHER DAMAGES WHAT-
 * SOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PER-
 * FORMANCE OF THIS SOFTWARE.
 * 
 * No other rights, including for example, the right to redis-
 * tribute this software and its documentation or the right to
 * prepare derivative works, are granted unless specifically
 * provided in a separate license agreement.
 *---------------------------------------------------------------------
 */

#include "unmcopyright.h"        /* Copyright 1991 by UNM */

/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>  <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 >>>>
 >>>>         File Name: llrfclass.c
 >>>>
 >>>>      Program Name: lrfclass
 >>>>
 >>>> Date Last Updated: Tue Apr  9 08:35:40 1991 
 >>>>
 >>>>          Routines: llrfclass - the library call for lrfclass
 >>>>
 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>   <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/


#include "vinclude.h"


/* -library_includes */
/* -library_includes_end */


/****************************************************************
*
* Routine Name: llrfclass - library call for lrfclass
*
* Purpose:
*    
*    Classify  an  image  using  the  Localized  Receptive  Field
*    classifier.
*    
*    
* Input:
*    
*    image          the input image to be classified.
*    
*    cc_img         the cluster center image from training phase.
*    
*    var_img        the cluster variance image from training phase.
*    
*    wt_img         the resulting weight image from training phase.
*    
*    border         the border width in pixels of the input image.
*    
*    
* Output:
*    
*    class_img      the resulting classified image.
*    
*    This routine was written with the help of and ideas from Dr.  Don
*    Hush, University of New Mexico, Dept. of EECE.
*    
*    
*
* Written By: Tom Sauer and Charlie Gage
*    
*    
****************************************************************/


/* -library_def */
int
llrfclass (image, cc_img, var_img, wt_img, class_img, border)
struct  xvimage  *image,       /* input image */
                 *cc_img,      /* cluster center image */
                 *var_img,     /* cluster variance image */
                 *wt_img,      /* lrftrain weight image */
                 **class_img;  /* output classified image */

int border;
/* -library_def_end */

/* -library_code */
{
   struct  xvimage  *class_image, *createimage();
   int nodes,                    /* number of nodes in the LRF layer */
       rfc_nvects,               /* number of receptive field centers */
       rfc_dim,                  /* dimension of receptive field centers */
       var_nvects,               /* variance vectors */
       var_dim,                  /* dimension of variance vectors */
       class_nvects,             /* number of class vectors */
       class_dim,                /* dimension of class vectors */
       input_nvects,             /* number of input vectors */
       input_dim,                /* dimension of input vectors */
       num_classes,              /* number of desired output classes */
       which_class,              /* current class for input vector */
       *cls_ptr,
       nr, nc, i, j, k, x, z, class, node, patrn;
   float **rf_centers,           /* pointer to receptive field centers */ 
         **cc_var,               /* pointer to cluster center variances */
         **input_data,           /* pointer to input image data */ 
         *class_ptr,             /* pointer to the class that corresponds */
                                 /*  to the associated cluster center */
         *image_ptr,             /* pointer to the input image data */ 
         **R,                    /* pointer to Receptive Field values */ 
         **W,                    /* pointer to the Weights */ 
         *Y;                     /* pointer to the output node equations */
   float a, q, dis, biggest;
   char **load_vector(), *unload_vector();
 
    nr = image->col_size;
    nc = image->row_size;

   /*---------------------------------------------------------------------*
    * INITIALIZE the number of NODES in the LRF, this is simply the number
    * of cluster centers previously determined 
    *---------------------------------------------------------------------*/
   nodes = cc_img->row_size;

   /*---------------------------------------------------------------------*
    * determine the number of output classes from the cluster center image
    *---------------------------------------------------------------------*/
   image_ptr = (float *) cc_img->imagedata;
   class_ptr = (float *) &image_ptr[cc_img->row_size * cc_img->col_size 
                                      * (cc_img->num_data_bands-1)];
   num_classes = *class_ptr; 
   for (i = 1; i < cc_img->row_size * cc_img->col_size; i++)
   {
      if (class_ptr[i] > num_classes) 
        num_classes = (int) class_ptr[i];
   }
   num_classes++;     /* add 1, since we start with zero */

   /*---------------------------------------------------------------------*
    * CHECK for proper NUMBER OF BANDS in the WEIGHT IMAGE, based on the
    * number of receptive field nodes and number of output classes.
    *---------------------------------------------------------------------*/
    if ( wt_img->num_data_bands != (nodes + 1)) {
      fprintf(stderr, "lrfclass: The weight image does not contain the correct\n");
      fprintf(stderr, "number of data_bands\n");
      fprintf(stderr, "Should have %d bands, but contains %d bands\n", (nodes + 1), wt_img->num_data_bands);
      return(0);
     }

   /*---------------------------------------------------------------------*
    * LOAD the RECEPTIVE FIELD CENTERS from the cluster center image,
    * but trick load_vector so that it does not see the class data
    * band attached to the end of the cluster center image
    *---------------------------------------------------------------------*/
   cc_img->num_data_bands -= 1;
   rf_centers = (float **) load_vector(cc_img, 0, &rfc_nvects, &rfc_dim);
   cc_img->num_data_bands += 1;

   /*---------------------------------------------------------------------*
    * LOAD the cluster center VARIANCES from the variance image.
    *---------------------------------------------------------------------*/
   cc_var = (float **) load_vector(var_img, 0, &var_nvects, &var_dim);

   /*---------------------------------------------------------------------*
    * LOAD the INPUT DATA into a VECTOR FORMAT
    *---------------------------------------------------------------------*/
   input_data = (float **)load_vector(image, border, &input_nvects, &input_dim);

   /*---------------------------------------------------------------------*
    * ALLOCATE SPACE for the response functions.
    * There are N * K response functions, where N is the number of nodes
    * and K is the number of input patterns
    *---------------------------------------------------------------------*/
   R = (float **) malloc (sizeof (float *) * nodes);
   if (R == NULL)
   {
      (void) fprintf (stderr,
                "lrfclass: insufficient memory available\n");
        return (0);
   }
   for (i = 0; i < nodes; i++) 
   {
      R[i] = (float *) malloc (sizeof (float) * input_nvects);
      if (R[i] == NULL) 
      {
          (void) fprintf (stderr,
                  "lrfclass: insufficient memory available\n");
          return (0);
       }
    }

   /*---------------------------------------------------------------------*
    * COMPUTE the RESPONSE FUNCTIONS for each node and data input
    * pattern. This is based on using the ratio of the Euclidean distance 
    * of an input data vector to a receptive field center to each 
    * diagonal element of the covariance matrix.
    *---------------------------------------------------------------------*/
   for (i = 0; i < input_nvects; i++) 
   {
       for (j = 0; j < nodes; j++) 
       {
                  /* COMPUTE the DISTANCE along each axis */
   
           dis = 0.0;
           for (k = 0; k < input_dim; k++) {
               a = *(input_data[i] + k) - *(rf_centers[j] + k);
               q = a * a;
               dis += q/(*(cc_var[j] +k));
           }
           *(R[j] + i) = exp(-dis);
       }
   }

   /*---------------------------------------------------------------------*
    * ASSIGN WEIGHTS to the SINGLE LAYER PERCEPTRON for running LMS
    * first alloc space for the number of weights
    * number of weights = number of desired output classes * # of nodes + 1
    * the +1 is for the bias weight.
    *---------------------------------------------------------------------*/

       /* START OF DATA ALLOCATION */

   W = (float **) malloc (sizeof (float *) * num_classes);
   if (W == NULL)
   {
      (void) fprintf (stderr,
                "lrfclass: insufficient memory available\n");
        return (0);
   }
   for (i = 0; i < num_classes; i++) 
   {
      W[i] = (float *) malloc (sizeof (float) * nodes + 1);
      if (W[i] == NULL) 
      {
          (void) fprintf (stderr,
                  "lrfclass: insufficient memory available\n");
          return (0);
       }
    }

        /* ALLOCATE space for the OUPUT NODE EQUATIONS, Y. 
         */

   Y = (float *) malloc (sizeof (float *) * num_classes);
   if (Y == NULL)
   {
      (void) fprintf (stderr,
                "lrfclass: insufficient memory available\n");
        return (0);
   }

      /* CREATE the class image */
  class_image = createimage((unsigned long) nr,            /* number of rows */
                        (unsigned long) nc,             /* number of columns */
                        (unsigned long) VFF_TYP_4_BYTE,  /* data_storage_type */
                        (unsigned long) 1,                /* num_of_images */
                        (unsigned long) 1,                /* num_data_bands */
                        "class image created by lrfclass", /* comment */
                        (unsigned long) 0,                /* map_row_size */
                        (unsigned long) 0,                /* map_col_size */
                        (unsigned long) VFF_MS_NONE,      /* map_scheme */
                        (unsigned long) VFF_MAPTYP_NONE, /* map_storage_type */
                        (unsigned long) VFF_LOC_IMPLICIT, /* location_type */
                        (unsigned long) 0);               /* location_dim */

    if (class_image == NULL)
    {
       (void)fprintf(stderr,"lrftrain: Unable to allocate class image!\n");
       return(0);
    }
      /* END OF DATA ALLOCATION */

   /*---------------------------------------------------------------------*
    * INITIALIZE the WEIGHTS from the weight image (wt_img)
    * by calling load_vector.
    *---------------------------------------------------------------------*/
    W = (float **) load_vector(wt_img, 0, &class_nvects, &class_dim);
        
    bzero(class_image->imagedata, sizeof(int) * nr * nc);

   /*---------------------------------------------------------------------*
    * RUN the LRF to CLASSIFY the input image
    *---------------------------------------------------------------------*/
       cls_ptr = (int *) class_image->imagedata;
       patrn = 0;
       for (x = border; x < nr - border; x++) 
       {
          for (z = border; z < nc - border; z++) 
          {
               /*
                *   compute the output layer node equations, Y 
                */
             bzero(Y, sizeof(float) * num_classes);
             for (class = 0; class < num_classes; class++)
             {
                for (node = 1; node < nodes + 1; node++)
                {
                   Y[class] += R[node-1][patrn] * W[class][node];
                }
                Y[class] += W[class][0];
             }
               /*---------------------------------------------------------*
                *   Determine which class the current input pattern
                *    belongs to.  (ie. classify the data).
                *   Use "Biggest Picker" algorithm.
                *   Initialize variable, "biggest" to the smallest
                *    possible value, then find the largest value
                *    of the output nodes.
                *---------------------------------------------------------*/
             biggest = -1.0;  /* initialize to smallest possible output */
             which_class = 0;
             for (class = 0; class < num_classes; class++)
             {
                if (Y[class] >= biggest)
                {
                   biggest = Y[class];
                   which_class = class;
                }
             }
             cls_ptr[x * nc + z] = which_class;
             patrn++;
          }
       }

   *class_img = class_image;

   return(TRUE);
}
/* -library_code_end */
