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

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

 /*
  * $Log: lvconvolve.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: lvconvolve.c
 >>>>
 >>>>      Program Name: vconvolve
 >>>>
 >>>> Date Last Updated: Tue Mar  5 22:28:40 1991 
 >>>>
 >>>>          Routines: lvconvolve - the library call for vconvolve
 >>>>
 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>   <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/


#include "vinclude.h"


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


/****************************************************************
*
* Routine Name: lvconvolve - library call for vconvolve
*
* Purpose:
*    
*    Compute two-dimensional convolution of a pair of images
*    
*    
* Input:
*    
*    
* Output:
*    
*    
*
* Written By: Richard Krukar
*    
*    Scott Wilson
*    
*    
****************************************************************/


/* -library_def */
int
lvconvolve(img1,img2)
struct xvimage *img1,*img2;
/* -library_def_end */

/* -library_code */
{
        float one;
        int t,f;
        one = 1.0; 
        t = 1;
        f = 0;
        /* checking for proper type inputs */

        if ( propertype("lvconvolve",img1,VFF_TYP_COMPLEX,FALSE) || 
           propertype("lvconvolve",img2,VFF_TYP_COMPLEX,FALSE) )
        {
           (void) fprintf(stderr, "lvconvolve does not operate on VFF_TYP_COMPLEX.\n");
           return(0);
        }

        /* Call convolution routine based on image and kernel data types */

        if((img1->data_storage_type == VFF_TYP_FLOAT) ||       /* Convert to float */
                (img2->data_storage_type == VFF_TYP_FLOAT)) {
            if (img1->data_storage_type != VFF_TYP_FLOAT)
               (void) lvconvert(img1,VFF_TYP_FLOAT,f,t,one,one,f);
            if (img2->data_storage_type != VFF_TYP_FLOAT)
               (void) lvconvert(img2,VFF_TYP_FLOAT,f,t,one,one,f);
            (void) float_convolve(img2,img1);}
        else {                                          /* Convert to int */
            if (img1->data_storage_type != VFF_TYP_4_BYTE)
               (void) lvconvert(img1,VFF_TYP_4_BYTE,f,t,one,one,f);
            if (img2->data_storage_type != VFF_TYP_4_BYTE)
               (void) lvconvert(img2,VFF_TYP_4_BYTE,f,t,one,one,f);
            (void) int_convolve(img2,img1);}

        return(1);
}

int_convolve(kern,img)
struct xvimage  *kern, *img;
{
        int     a;
        int     *result;
        int     *image, *kernel, *revkern;
        int     rows,cols,krows,kcols;
        int     i,j,k,l,x,y;

        rows = img->col_size;
        cols = img->row_size;
        krows = kern->col_size;
        kcols = kern->row_size;

        /* Make room for the resulting image */
        result = (int *)malloc(cols*rows*sizeof(int));
        if(result == NULL) {
            (void) fprintf(stderr,"lvconvolve: insufficient memory available\n");
            return(0); }

        image = (int *)img->imagedata;
        kernel = (int *)kern->imagedata;

        /* Build an X- and Y-reversed kernel */
        revkern = (int *)malloc(krows*kcols*sizeof(int));
        for (i=0; i<kcols; i++)
          for (j=0; j<krows; j++)
            revkern[(krows-1-j)*kcols+(kcols-1-i)] = kernel[j*kcols+i];

        /* Set the entire result array to 0 */
        bzero((char *)result,rows*cols*sizeof(int));

        /* Compute convolution of kernel with image and place in result.
           Edges are handled by truncating the kernel */
        for(i=0;i<cols;i++)
          {
            for(j=0;j<rows;j++)
              {
                a = 0;
                for(k=0;k<kcols;k++)
                  {
                    for(l=0;l<krows;l++)
                      {
                        /* X,Y is location of pixel in image under the
                           convolution mask */
                        x = i-kcols+k+1;
                        y = j-krows+l+1;
                        if (x >= 0 &&     /* Left edge */
                            x < cols &&   /* Right edge */
                            y >= 0 &&     /* Top edge */
                            y < rows )    /* Bottom edge */
                           a += revkern[l*kcols+k]*image[y*cols+x];
                      }
                  }
                result[j*cols+i] = a;
              }
          }

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

float_convolve(kern,img)
struct xvimage  *kern, *img;
{
        float   a;
        float   *result;
        float   *image, *kernel, *revkern;
        int     rows,cols,krows,kcols;
        int     i,j,k,l,x,y;

        rows = img->col_size;
        cols = img->row_size;
        krows = kern->col_size;
        kcols = kern->row_size;

        /* Make room for the resulting image */
        result = (float *)malloc(cols*rows*sizeof(float));
        if(result == NULL) {
            (void) fprintf(stderr,"lvconvolve: insufficient memory available\n");
            return(0); }

        image = (float *)img->imagedata;
        kernel = (float *)kern->imagedata;

        /* Build an X- and Y-reversed kernel */
        revkern = (float *)malloc(krows*kcols*sizeof(float));
        if(revkern == NULL) {
            (void) fprintf(stderr,"lvconvolve: insufficient memory available\n");
            return(0); }

        for (i=0; i<kcols; i++)
          for (j=0; j<krows; j++)
            revkern[(krows-1-j)*kcols+(kcols-1-i)] = kernel[j*kcols+i];

        /* Set the entire result array to 0 */
        bzero((char *)result,rows*cols*sizeof(float));

        /* Compute convolution of kernel with image and place in result.
           Edges are handled by truncating the kernel */
        for(i=0;i<cols;i++)
          {
            for(j=0;j<rows;j++)
              {
                a = 0.0;
                for(k=0;k<kcols;k++)
                  {
                    for(l=0;l<krows;l++)
                      {
                        /* X,Y is location of pixel in image under the
                           convolution mask */
                        x = i-kcols+k+1;
                        y = j-krows+l+1;
                        if (x >= 0 &&     /* Left edge */
                            x < cols &&   /* Right edge */
                            y >= 0 &&     /* Top edge */
                            y < rows )    /* Bottom edge */
                            a += revkern[l*kcols+k]*image[y*cols+x];
                      }
                  }
                result[j*cols+i] = a;
              }
          }

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