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

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

 /*
  * $Log: lvwmdd.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: lvwmdd.c
 >>>>
 >>>>      Program Name: vwmdd
 >>>>
 >>>> Date Last Updated: Tue Apr  9 08:36:57 1991 
 >>>>
 >>>>          Routines: lvwmdd - the library call for vwmdd
 >>>>
 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>   <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/


#include "vinclude.h"


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


/****************************************************************
*
* Routine Name: lvwmdd - library call for vwmdd
*
* Purpose:
*    
*    Weighted minimum distance detector
*    
*    
* Input:
*    
*    img            the input image that is to be classified.
*    
*    center         the image containing the center values (or  proto-
*                   type  vectors)  with  the last data band being the
*                   class image. This image must have n + 1 data bands
*                   where n is the number of data bands in img.
*    
*    varimg         the image containing the variance values  for  the
*                   clusters.   Should  have  the  same number of data
*                   bands as the input image (img).
*    
*    border         the  border  width  on  the  image.   The   border
*                   corresponds  to  a  no class assignment.  i.e. the
*                   border region is ignored during the classification
*                   process.
*    
*    k_factor       scalar, fudge factor.
*    
*    use_avg        1 - use summing method 0 - use non-summing method
*    
*    
* Output:
*    
*    img            a single band 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
*    
*    
****************************************************************/


/* -library_def */
lvwmdd (img, center, varimg,  border, k_factor, use_avg )
struct xvimage *img,            /* input image */
               *varimg,
               *center;         /* cluster center image */
int     border;
int     use_avg;                /* if set use the average method */
float   k_factor;
/* -library_def_end */

/* -library_code */
{
    int     nc,                 /* column size of image */
            nr,                 /* row size of image */
            cc_nc,              /* column size of image */
            cc_nr,              /* row size of image */
            var_nc,             /* column size of varimg image */
            var_nr,             /* row size of varimg image */
            vect,               /* number of vectors in image */
            dimension,          /* size of vector - num_bands */
            n_centers,
            num_centers,
            i,                  /* loop indices */
            j, m, k,x , z, c;

    float  d, a, q, dmin;
    float  *ptr,                /* pointer to the image data char */
           *varptr,
          **input_vectors,      /* pointer to image data reorganized */
           *new_class,          /* pointer to result image */
           *class,              /* pointer to class data that corresponds */
           *class_valid,
                                /* to the cluster centers */
          **c_center,           /* cluster centers */
          **var_vector;         /* square distance values */

    nr = img -> col_size;                /* number of rows in image */
    nc = img -> row_size;                /* number of columns in image */
    var_nr = cc_nr = center->col_size;   /* number of rows in center image */
    var_nc = cc_nc = center->row_size;   /* number of columns in center image */

    dimension = img -> num_data_bands;
    vect = (nr - (border * 2)) * (nc - (border * 2)); /* number of vectors */
    n_centers = cc_nr * cc_nc;

 /* Assign class to the last band of the center image */

    ptr = (float *) center -> imagedata;
    class = (float *) (&ptr[cc_nr * cc_nc * dimension]);
    num_centers = 0;
    for (i =0 ; i< n_centers; i++)
    {
        if (class[i] != 0.0)
           num_centers++;
    }

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

    ptr = class_valid;
    for (i =0 ; i< n_centers; i++)
    {
       if (class[i] != 0.0)
       {
         *ptr = class[i];
         ptr++;
       }
    }

    /* Allocate space for input_vectors image */
    /* reorganize the data because it is not organized in an efficient */
    /* manner for the computational complexity of the routine */

    input_vectors = (float **) malloc ((unsigned int) vect * sizeof (float));
    if (input_vectors == NULL) {
        (void) fprintf (stderr, "lvwmdd: insufficient memory available\n");
        return (0);
    }

    for (i = 0; i < vect; i++) {
        input_vectors[i] = (float *) malloc (dimension * sizeof (float));
        if (input_vectors[i] == NULL) {
            (void) fprintf (stderr,
                    "lvwmdd: insufficient memory available\n");
            return (0);
        }
    }

/* Allocate space for cluster centers */

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

    for (i = 0; i < num_centers; i++) {
        c_center[i] = (float *) malloc (sizeof (float) * dimension);
        if (c_center[i] == NULL) {
            (void) fprintf (stderr,
                    "lvwmdd: insufficient memory available\n");
            return (0);
        }
    }

/* Allocate space for variance values */

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

    for (i = 0; i < num_centers; i++) {
        var_vector[i] = (float *) malloc (sizeof (float) * dimension);
        if (var_vector[i] == NULL) {
            (void) fprintf (stderr,
                    "lvwmdd: insufficient memory available\n");
            return (0);
        }
    }


    /* Allocate space for output image data */

    new_class = (float *) malloc ((unsigned int) nr * nc* sizeof (float));
    if (new_class == NULL) {
        (void) fprintf (stderr, "lvwmdd: insufficient memory available\n");
        return (0);
    }

    /* Zero out output imagedata */

    bzero (new_class, (unsigned int) nr * nc * sizeof (float));


    /* Assign image data address to ptr */

    ptr = (float *) img -> imagedata;

    /* Assign ptr to input vectors minus the border */
    m = 0;
    for (i = border; i < nr - border; i++) {
        for (j = border; j < nc - border; j++) {
            for (k = 0; k < dimension; k++) {
                input_vectors[m][k] = ptr[(i * nc + j) + (k * nc * nr)];
            }
            m++;
        }
    }

 /* Assign cluster center image data to c_center */
 /* Assign variance values to var_vector */


   ptr = (float *) center -> imagedata;
   varptr = (float *) varimg -> imagedata;
   k = 0;
   for (i = 0; i < cc_nr * cc_nc; i++) 
   {
      if (class[i] != 0.0)
      {
         for (j = 0; j < dimension; j++) 
         {
            c_center[k][j] = ptr[i + (cc_nc * cc_nr * j)];
            var_vector[k][j] = varptr[i + (cc_nc * cc_nr * j)];
         }
         k++;
      }
   }



/*  run the classifier */

      /* two methods: (1) use_avg = FALSE => sum the sqaure distance
                                             divided by the variance along each
                                             axis for every point.
                      (2) use_avg = TRUE => 1. sum the variance along each
                                               axis for every cluster center.
                                            2. sum the sqaure distance 
                                               divided by the (sum of the 
                                               variance along each axis) 
                                               for every point.
     */
    if (use_avg == FALSE) 
    {
       i = 0;
       for (x = border; x < nr - border; x++) {
          for (z = border; z < nc - border; z++) {
        
              dmin = XV_MAXFLOAT;
   
              for (j = 0; j < num_centers; j++) {
   
                      /* compute the distance along each axis */
   
                  d = 0.0;
                  for (k = 0; k < dimension; k++) {
                      a = input_vectors[i][k] - c_center[j][k];
                      q = a * a;
                      d = d + (q / var_vector[j][k]);
                  }
                  d = d / (k_factor * dimension);
   
                  if (d < dmin) {
                     dmin = d;
                     c = j;
                  }
              }
                 /* assign the classified vector */
                 new_class[x * nc + z] = class_valid[c];
              i++;
          }
       }
    }

      /* use_avg == TRUE => use the average method */

    else
    {
       for (j = 0; j < num_centers; j++) 
       {
          a = 0;
          for (k = 0; k < dimension; k++) 
          {
             a += var_vector[j][k];
          }
          var_vector[j][0] = a; 
       }

       i = 0;
       for (x = border; x < nr - border; x++) {
          for (z = border; z < nc - border; z++) {
        
   
              dmin = XV_MAXFLOAT;
              for (j = 0; j < num_centers; j++) {
   
                      /* compute the distance along each axis */
   
                  d = 0.0;
                  for (k = 0; k < dimension; k++) 
                  {
                      a = input_vectors[i][k] - c_center[j][k];
                      d = d + (a * a);
                  }
                  d = d / (dimension * k_factor * var_vector[j][0]);

                  if (d < dmin) 
                  {
                     dmin = d;
                     c = j;
                  }
              }
                 /* assign the classified vector */
   
                 new_class[x * nc + z] = class_valid[c];
              i++;
          }
       }
    }

    /* release memory from input image */

    (void) free (img->imagedata);
    (void) free (img->maps);

       /* adjust header in the output image */
    img->imagedata = (char *) new_class;
    img->num_data_bands = 1;
    img->map_scheme = VFF_MS_NONE;
    img->map_row_size = 0;
    img->map_col_size = 0;
    img->map_subrow_size = 0;
    img->color_space_model = VFF_CM_NONE;

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