 /*
  * Khoros: $Id: lvqmed.c,v 1.2 1992/03/20 23:07:21 dkhoros Exp $
  */

#if !defined(lint) && !defined(SABER)
static char rcsid[] = "Khoros: $Id: lvqmed.c,v 1.2 1992/03/20 23:07:21 dkhoros Exp $";
#endif

 /*
  * $Log: lvqmed.c,v $
 * Revision 1.2  1992/03/20  23:07:21  dkhoros
 * VirtualPatch5
 *
  */

/*
 *----------------------------------------------------------------------
 *
 * Copyright 1992, 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 to 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 1992 by UNM */

/*>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>  <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 >>>>
 >>>>         File Name: lvqmed.c
 >>>>
 >>>>      Program Name: vqmed
 >>>>
 >>>> Date Last Updated: Fri Feb 21 12:03:39 1992 
 >>>>
 >>>>          Routines: lvqmed - the library call for vqmed
 >>>>
 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>   <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/


#include "vinclude.h"


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


/****************************************************************
*
* Routine Name: lvqmed - library call for vqmed
*
* Purpose:
*    
*    Perform a median filter on an image using quicksort to  find
*    the median value.
*    
*    

* Input:
*    
*         1. img1 -- first input xvimage structure
*         2. w    -- the width of the median filter
*         3. h    -- the height of the median filter
*    
*    

* Output:
*    
*         1. img1 -- output xvimage structure
*    
*         The result data type depends on the inputs. The result image
*         size is the same as img1.
*    
*         img1 is used  for  both  the  input  image  and  the  output
*         image.This  is  done  to save space, but you must be careful
*         not to overwrite important data.
*    
*         It is still possible  to  have  overflow  when  using  large
*         images.
*    
*         lvqmed returns a one upon success and a zero on failure.
*    
*    

*
* Written By: Richard Krukar
*    
*    Rasure  fixed  bug  on  2/21/92.   Sort  array  was  indexed
*    incorreclty to get median value.  See code for more details.
*    
*    

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


/* -library_def */
int
lvqmed(img1,w,h)
struct xvimage *img1;
int w,h;
/* -library_def_end */

/* -library_code */
{

        switch( (int) img1->data_storage_type )
        {
            case VFF_TYP_1_BYTE :
                (void) char_median(img1,w,h);
                break;
            case VFF_TYP_2_BYTE :
                (void) short_median(img1,w,h);
                break;
            case VFF_TYP_4_BYTE :
                (void) int_median(img1,w,h);
                break;
            case VFF_TYP_FLOAT :
                (void) float_median(img1,w,h);
                break;
            case VFF_TYP_COMPLEX :
            default :
                fprintf(stderr,"Wrong data storage type for vqmed\n");
                return(0);
        }

        return(1);
}

char_median(img,width,height)
struct xvimage  *img;
int width,height;
{
        unsigned char    *result, *image, *sort_arr;
        int     xoff,yoff,xend,yend,icols, char_compare();
        int     i,j,k,l;

/* make room for the resulting image */
        result = (unsigned char *)malloc(img->row_size*img->col_size*sizeof(char));
        if(result == NULL) {
            (void) fprintf(stderr,"lvqmed: insufficient memory available\n");
            return(0); }

/* make room for the sort_arr */
        sort_arr = (unsigned char *)malloc(width*height*sizeof(char));
        if(sort_arr == NULL) {
            (void) fprintf(stderr,"lvqmed: insufficient memory available\n");
            return(0); }

        image = (unsigned char *)img->imagedata;

        xend = img->row_size - width;
        yend = img->col_size - height;

        xoff = (width >> 1 ) + (width & 1);
        yoff = (height >> 1 ) + (height & 1);

        icols = img->row_size ;

/* Set the entire result array to 0 */
        for(i=0;i<img->row_size*img->col_size;i++)
                result[i] = 0;

/* calculate the convolution of the image with the kernel and place the
   resulting image in the output image array --- result  */

        for(i=0;i<=yend;i++) /* step through image rows */
            for(j=0;j<=xend;j++) /* step through image cols */
            {
                for(k=0;k<width;k++) /* step through image cols */
                    for(l=0;l<height;l++) /* step through image rows */
                        sort_arr[l*width+k] = image[(i+l)*icols+k+j];
                qsort(sort_arr,width*height,sizeof(char),char_compare);
         /* Bug fixed 2/21/92 by Rasure:
        result[(i+yoff-1)*icols+j+xoff-1]=sort_arr[(width*height+1)>>1]; 
        replaced by following line: indexed into odd kernels wrong */
                result[(i+yoff-1)*icols+j+xoff-1]=sort_arr[(width*height)>>1];
            }

        free(image);
        img->imagedata = (char *)result;
        return(1);
}

int char_compare(arg1,arg2)
unsigned char *arg1,*arg2;
{
        if(*arg1 < *arg2)
                return(-1);
        if(*arg1 > *arg2)
                return(1);
        return(0);
}

short_median(img,width,height)
struct xvimage  *img;
int width,height;
{
        short   *result, *image, *sort_arr;
        int     xoff,yoff,xend,yend,icols, short_compare();
        int     i,j,k,l;

/* make room for the resulting image */
        result = (short *)malloc(img->row_size*img->col_size*sizeof(short));
        if(result == NULL) {
            (void) fprintf(stderr,"lvqmed: insufficient memory available\n");
            return(0); }

/* make room for the sort_arr */
        sort_arr = (short *)malloc(width*height*sizeof(short));
        if(sort_arr == NULL) {
            (void) fprintf(stderr,"lvqmed: insufficient memory available\n");
            return(0); }

        image = (short *)img->imagedata;

        xend = img->row_size - width;
        yend = img->col_size - height;

        xoff = (width >> 1 ) + (width & 1);
        yoff = (height >> 1 ) + (height & 1);

        icols = img->row_size ;

/* Set the entire result array to 0 */
        for(i=0;i<img->row_size*img->col_size;i++)
                result[i] = 0;

/* calculate the convolution of the image with the kernel and place the
   resulting image in the output image array --- result  */

        for(i=0;i<=yend;i++) /* step through image rows */
            for(j=0;j<=xend;j++) /* step through image cols */
            {
                for(k=0;k<width;k++) /* step through image cols */
                    for(l=0;l<height;l++) /* step through image rows */
                        sort_arr[l*width+k] = image[(i+l)*icols+k+j];
                qsort(sort_arr,width*height,sizeof(short),short_compare);
                result[(i+yoff-1)*icols+j+xoff-1]=sort_arr[(width*height)>>1];
            }

        free(image);
        img->imagedata = (char *)result;
        return(1);
}

int short_compare(arg1,arg2)
short *arg1,*arg2;
{
        if(*arg1 < *arg2)
                return(-1);
        if(*arg1 > *arg2)
                return(1);
        return(0);
}

int_median(img,width,height)
struct xvimage  *img;
int width,height;
{
        int     *result, *image, *sort_arr, int_compare();
        int     xoff,yoff,xend,yend,icols;
        int     i,j,k,l;

/* make room for the resulting image */
        result = (int *)malloc(img->row_size*img->col_size*sizeof(int));
        if(result == NULL) {
            (void) fprintf(stderr,"lvqmed: insufficient memory available\n");
            return(0); }

/* make room for the sort_arr */
        sort_arr = (int *)malloc(width*height*sizeof(int));
        if(sort_arr == NULL) {
            (void) fprintf(stderr,"lvqmed: insufficient memory available\n");
            return(0); }

        image = (int *)img->imagedata;

        xend = img->row_size - width;
        yend = img->col_size - height;

        xoff = (width >> 1 ) + (width & 1);
        yoff = (height >> 1 ) + (height & 1);

        icols = img->row_size ;

/* Set the entire result array to 0 */
        for(i=0;i<img->row_size*img->col_size;i++)
                result[i] = 0;

/* calculate the convolution of the image with the kernel and place the
   resulting image in the output image array --- result  */

        for(i=0;i<=yend;i++) /* step through image rows */
            for(j=0;j<=xend;j++) /* step through image cols */
            {
                for(k=0;k<width;k++) /* step through image cols */
                    for(l=0;l<height;l++) /* step through image rows */
                        sort_arr[l*width+k] = image[(i+l)*icols+k+j];
                qsort(sort_arr,width*height,sizeof(int),int_compare);
                result[(i+yoff-1)*icols+j+xoff-1]=sort_arr[(width*height)>>1];
            }

        free(image);
        img->imagedata = (char *)result;
        return(1);
}

int int_compare(arg1,arg2)
int *arg1,*arg2;
{
        if(*arg1 < *arg2)
                return(-1);
        if(*arg1 > *arg2)
                return(1);
        return(0);
}

float_median(img,width,height)
struct xvimage  *img;
int width,height;
{
        float   *result, *image, *sort_arr;
        int     xoff,yoff,xend,yend,icols, float_compare();
        int     i,j,k,l;

/* make room for the resulting image */
        result = (float *)malloc(img->row_size*img->col_size*sizeof(float));
        if(result == NULL) {
            (void) fprintf(stderr,"lvqmed: insufficient memory available\n");
            return(0); }

/* make room for the sort_arr */
        sort_arr = (float *)malloc(width*height*sizeof(float));
        if(sort_arr == NULL) {
            (void) fprintf(stderr,"lvqmed: insufficient memory available\n");
            return(0); }

        image = (float *)img->imagedata;

        xend = img->row_size - width;
        yend = img->col_size - height;

        xoff = (width >> 1 ) + (width & 1);
        yoff = (height >> 1 ) + (height & 1);

        icols = img->row_size ;

/* Set the entire result array to 0 */
        for(i=0;i<img->row_size*img->col_size;i++)
                result[i] = 0;

/* calculate the convolution of the image with the kernel and place the
   resulting image in the output image array --- result  */

        for(i=0;i<=yend;i++) /* step through image rows */
            for(j=0;j<=xend;j++) /* step through image cols */
            {
                for(k=0;k<width;k++) /* step through image cols */
                    for(l=0;l<height;l++) /* step through image rows */
                        sort_arr[l*width+k] = image[(i+l)*icols+k+j];
                qsort(sort_arr,width*height,sizeof(float),float_compare);
                result[(i+yoff-1)*icols+j+xoff-1]=sort_arr[(width*height)>>1];
            }

        free(image);
        img->imagedata = (char *)result;
        return(1);
}

int float_compare(arg1,arg2)
float *arg1,*arg2;
{
        if(*arg1 < *arg2)
                return(-1);
        if(*arg1 > *arg2)
                return(1);
        return(0);
}
/* -library_code_end */
