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

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

 /*
  * $Log: lvmskel.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: lvmskel.c
 >>>>
 >>>>      Program Name: vmskel
 >>>>
 >>>> Date Last Updated: Tue Mar  5 22:31:43 1991 
 >>>>
 >>>>          Routines: lvmskel - the library call for vmskel
 >>>>
 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>   <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/


#include "vinclude.h"


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


/****************************************************************
*
* Routine Name: lvmskel - library call for vmskel
*
* Purpose:
*    
*    Computes the skeletonization of a binary byte image
*    
*    
* Input:
*    
*         image _ xvimage structure
*    
*    
* Output:
*    
*         image _ holds the result.
*    
*    
*
* Written By: Pascal ADAM
*    
*    Ghosted by Pascal Adam on june the 1st 1990
*    
*    
****************************************************************/


/* -library_def */
int
lvmskel(image)
struct xvimage *image;
/* -library_def_end */

/* -library_code */
{
int lvmcr_kd();
int lvmerode();
int lvmdilate();


struct xvimage *kd,*kd2, *createimage();

unsigned char *imagecopy, *imagestore, *result;
unsigned char *cptr, *cptrcp, *cptrre, *cptrst, *kern;
int i, j, max_disk, m, nc, nr;
char   *program = "lvmskel";

    /* Check type,... of image */
    if (!(propertype(program, image, VFF_TYP_1_BYTE, FALSE))) {
        (void) fprintf (stderr, "\n\n%s:   ", program);
        (void) fprintf (stderr, "lvmskel: image must be of type byte\n");
        return (0);
    }
    if (!(proper_num_images (program, image, 1, FALSE))) {
        (void) fprintf (stderr, "\n\n%s:   ", program);
        (void) fprintf (stderr, "Can only work on files with one image\n\n");
        return (0);
    }
    if (!(proper_num_bands (program, image, 1, FALSE))) {
        (void) fprintf (stderr,"\n\n%s:   ", program);
        (void) fprintf (stderr,"Can only work on images with 1 data band\n\n");
        return (0);
    }

    nr = image->col_size; 
    nc = image->row_size;


    /* dynamic memory allocation for temporary imagecopy stockage */
    imagecopy = (unsigned char *) malloc( nc * nr *sizeof(unsigned char));
    if (imagecopy == NULL) {
        (void) fprintf (stderr, "\n%s:   ", program);
        (void) fprintf (stderr, "Insufficient Space avaliable\n");
        return(0);
    }

    /* dynamic memory allocation for temporary imagestore stockage */
    imagestore = (unsigned char *) malloc( nc * nr *sizeof(unsigned char));
    if (imagestore == NULL) {
        (void) fprintf (stderr, "\n%s:   ", program);
        (void) fprintf (stderr, "Insufficient Space avaliable\n");
        return(0);
    }

    /* dynamic memory allocation for temporary result stockage */
    result = (unsigned char *) malloc( nc * nr *sizeof(unsigned char));
    if (result == NULL) {
        (void) fprintf (stderr, "\n%s:   ", program);
        (void) fprintf (stderr, "Insufficient Space avaliable\n");
        return(0);
    }

    cptr   = (unsigned char *) image->imagedata;
    cptrst = imagestore;
    cptrre = result;


    /* Store original image in imagestore ..........*/
    /* And initialisation of result to 0   .........*/
    for (i=0; i< nc*nr; i++) 
    {
       *(cptrst++) = *(cptr++);
       *(cptrre++) = 0;
    }
    /* Creates kerneldisk2 .........................*/
    m=2;
    if ( !lvmcr_kd(&kd2,m))
    {
        (void) fprintf(stderr, "vmskel: lvmcr_kd Failed\n");
        return(0);
    }

    /* end of loop test boolean initialisation .....*/

    /* Initialisation of loop variable m ...........*/
    m = 1;
    kd = NULL;
    
    /* BODY OF THE PRINCIPAL LOOP ..................*/
    do 
    {
       if (kd !=NULL) 
       {
          free(kd);
       }
    
       /*  creates max disk m : morphological kernel  */
       if ( !lvmcr_kd(&kd,m))
       {
          (void) fprintf(stderr, "vmskel: lvmcr_kd Failed\n");
          return(0);
       }
       /* Erosion of image by kernel disk(m) ..........*/   
       if ( !lvmerode(image,kd))
       {
          (void) fprintf(stderr, "vmskel: lvmerode Failed\n");
          return(0);
       }
       /* Store erode image in imagecopy ..............*/
       cptr = (unsigned char *) image->imagedata;
       cptrcp = imagecopy;
       for (i=0; i< nc*nr; i++) 
       {
            *(cptrcp++) = *(cptr++);
       }
       /* test if erode = image empty .................*/  
       max_disk = TRUE; 
       cptr = (unsigned char *) image->imagedata;
       for (i=0; i< nc*nr; i++) 
       {
            if (*(cptr++) != 0)
            { 
               max_disk = FALSE;
               break;
            }
       }
       /* computes (dilate(erode(..),kd2),kd2)) ..opening.......*/
       if ( !lvmerode(image,kd2))
       {
          (void) fprintf(stderr, "vmskel: lvmerode Failed\n");
          return(0);
       }
       if ( !lvmdilate(image,kd2))
       {
          (void) fprintf(stderr, "vmskel: lvmdilate Failed\n");
          return(0);
       }
   
       /* Computes the invert of the precedent image ..*/
       cptr = (unsigned char *) image->imagedata;
       for (i=0; i< nc*nr; i++) 
       {
            if ( *cptr== 0) *cptr=255;
            else *cptr=0;
            cptr++;
       }
       
       /* Computes the intersection of image and imagecopy ...*/
       cptr = (unsigned char *) image->imagedata;
       cptrcp = imagecopy;
       for (i=0; i< nc*nr; i++) 
       {
            if (*(cptr+i) == 255) *(cptr+i) = *(cptrcp+i);
       }
       
       /* Computes the union of image and the result .........*/
       cptr = (unsigned char *) image->imagedata;
       cptrre = result;
       for (i=0; i< nc*nr; i++) 
       {
            if (*(cptr+i) == 255) *(cptrre+i) = *(cptr+i);
       }
       

       /* restore original data image in image structure .....*/
       cptr = (unsigned char *) image->imagedata;
       cptrst = imagestore;
       for (i=0; i< nc*nr; i++) 
       {
            *(cptr++) = *(cptrst++);
       }
 
       /* incrementation of loop variable m ..................*/
       m++;

       /* END OF LOOP AND TEST IF STOP OR KEEP ON ............*/
       cptr = (unsigned char *) image->imagedata;
       cptrst = imagestore;
       for (i=0;i< nc*nr; i++) *(cptr++) = *(cptrst++);
 
   } while (max_disk == FALSE);


   /* write result in image->data before return ..............*/
   cptr = (unsigned char *) image->imagedata;
   cptrre = result;
   for (i=0;i< nc*nr; i++)
   {
       *(cptr++) = *(cptrre++);
   }

   free(result);free(imagecopy);free(imagestore);

   return(1);
}

/* INITIALISATION OF DISK KERNEL FOR SKELETONISATION */
int
lvmcr_kd (kd,m)
struct xvimage **kd;
int m;
{
        int     i, j;
  
        int k;

        int type = VFF_TYP_1_BYTE;

        struct xvimage *kern, *createimage();

        unsigned char *cptr;


        /* Initialisation of rows and columns size, etc...............*/
        kern = createimage((unsigned long) m,    /* number of rows    */
                        (unsigned long) m,       /* number of columns */
                        (unsigned long) type,    /* data_storage_type */
                        (unsigned long) 1,       /* num_of_images     */ 
                        (unsigned long) 1,       /* num_data_bands    */ 
                        "created by vmcustom",   /* 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 (kern == NULL)
        {
           (void)fprintf(stderr,"lvmcr_kd: Unable to allocate new image\n");
           *kd = NULL;
           return(0);
        }
        cptr = (unsigned char *) kern->imagedata;

        for (i = 0; i < m*m; i++) 
        {
           *cptr++ = (char)255;
        }

        /* this disk is center has followed, because of digitalisation */
        /* the center can't be right in the middle of the disk ....... */
        kern->ispare1=kern->ispare2= (unsigned long)( -1*(char)((m-1)/2) );


        *kd = kern;
        
        return(1);
}
/* -library_code_end */
