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

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

 /*
  * $Log: lvmindis.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: lvmindis.c
 >>>>
 >>>>      Program Name: vmindis
 >>>>
 >>>> Date Last Updated: Tue Mar  5 22:21:04 1991 
 >>>>
 >>>>          Routines: lvmindis - the library call for vmindis
 >>>>
 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>   <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/


#include "vinclude.h"


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


/****************************************************************
*
* Routine Name: lvmindis - library call for vmindis
*
* Purpose:
*    
*    Minimum Distance Classifier
*    
*    
* 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.
*    
*    border         the  border  width  on  the  image.   The   border
*                   corresponds to a no class assignment.
*    
*    
* Output:
*    
*    img            a single band classified image.
*    
*    
*
* Written By: Tom Sauer
*    
*    
****************************************************************/


/* -library_def */
lvmindis (img, center, border)
struct xvimage *img,            /* input image */
               *center;         /* cluster center image */
int     border;
/* -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 */
            vect,               /* number of vectors in image */
            dimension,          /* size of vector - num_bands */
            n_centers,
            i,                  /* loop indices */
            j, m, k,
            x,
            c,
            z;

float       d, dmin,
            dist();

    float  *ptr,                /* pointer to the image data char */
          **input_vectors,      /* pointer to image data reorganized */
           *new_class,          /* pointer to result image */
           *class,              /* pointer to class data that corresponds */
                                /* to the cluster centers */
          **c_center;           /* cluster centers */

    nr = img -> col_size;       /* number of rows in image */
    nc = img -> row_size;       /* number of columns in image */
    cc_nr = center->col_size;    /* number of rows in center image */
    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;

    /* 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, "lvmindis: 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,
                    "lvmindis: insufficient memory available\n");
            return (0);
        }
    }

/* Allocate space for cluster centers */

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

    for (i = 0; i < n_centers; i++) {
        c_center[i] = (float *) malloc (sizeof (float) * dimension);
        if (c_center[i] == NULL) {
            (void) fprintf (stderr,
                    "lvmindis: 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, "lvmindis: 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 */

   ptr = (float *) center -> imagedata;
       for (i = 0; i < cc_nr * cc_nc; i++) {
          for (j = 0; j < dimension; j++) {
             c_center[i][j] = ptr[i + (cc_nc * cc_nr * j)];
          }
       }


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

    class = (float *) (&ptr[cc_nr * cc_nc * dimension]);

/*  run the classifier */

    i = 0;
    for (x = border; x < nr - border; x++) {
       for (z = border; z < nc - border; z++) {
     
           dmin = XV_MAXFLOAT;

           for (j = 0; j < n_centers; j++) {
               d = dist(input_vectors[i], c_center[j], dimension);
               if (d < dmin) {
                  dmin = d;
                  c = j;
               }
           }
              /* assign the classified vector */
           new_class[x * nc + z] = class[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);
}


/******************************************************************

        Compute Distance for k-NN routine

        source filename:                        dist.c

        revision          date                  programmer
        --------          ----                  ----------
           0.0          05/19/88                Don Hush

******************************************************************

        usage :

        float
        dist(x, y, n)

        float *x;
        float *y;
        int n;

        description:

        This routine computes the euclidean distance between
        two n-dimension floating point vectors.

******************************************************************/


float
        dist (x, y, n)
float  *x;
float  *y;
int     n;

{
    int     i;
    float   d,
            a;

    d = 0.0;
    for (i = 0; i < n; i++) {
        a = x[i] - y[i];
        d += a * a;
    }
    d = (float) sqrt ((double) d);

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