 /*
  * Khoros: $Id: lvcluv.c,v 1.2 1992/03/20 23:04:53 dkhoros Exp $
  */

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

 /*
  * $Log: lvcluv.c,v $
 * Revision 1.2  1992/03/20  23:04:53  dkhoros
 * VirtualPatch5
 *
  */ 

/*
 *----------------------------------------------------------------------
 *
 * 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: lvcluv.c
 >>>>
 >>>>      Program Name: vcluv
 >>>>
 >>>> Date Last Updated: Tue Mar  5 22:21:51 1991 
 >>>>
 >>>>          Routines: lvcluv - the library call for vcluv
 >>>>
 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>   <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<*/


#include "vinclude.h"


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


/****************************************************************
*
* Routine Name: lvcluv - library call for vcluv
*
* Purpose:
*    
*    Conversion from a linear Color Space to the Luv color space.
*    
*    
* Input:
*    
*    img1           input multispectral image  of  color  space  model
*                   ntscRGB,  ntscYIQ,  ntscCMY,  genericRGB,  cieXYZ,
*                   cieUVW or GENERIC.
*    
*    norm           normalization factor
*    
*    
* Output:
*    
*    img1           converted image of type FLOAT normalized between 0
*                   and 1.
*    
*    
*
* Written By: Tom Sauer
*    
*    
****************************************************************/


/* -library_def */
int
lvcluv(img1, norm)
struct xvimage *img1;
float norm;
/* -library_def_end */

/* -library_code */
{
    int     i,
            nc,
            nr;
    float  *xptr,
           *yptr,
           *zptr;

    float  *Lptr,
           *uptr,
           *vptr;

    float  *ptr,
           *Luv;

    float   uv_dom,
            X0,
            Y0,
            Z0,
            u0,
            v0,
            u_prime,
            v_prime;

    double  tmp, one_third_power;

    char   *program = "lcluv";

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

    if (img1 -> data_storage_type != VFF_TYP_FLOAT) {
        (void) fprintf (stderr,
                "lvcluv: image must be of type float/n");
        return (0);
    }

    if (!(proper_num_images (program, img1, 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, img1, 3, FALSE))) {
        (void) fprintf (stderr, "\n\n%s:   ", program);
        (void) fprintf (stderr, "Can only work on images with 3 data bands\n\n");
        return (0);
    }

    if (!(proper_map_enable (program, img1, VFF_MAP_OPTIONAL, FALSE))) {
        (void) fprintf (stderr,
                "lvcluv: ERROR image map enable must be optional./n");
        (void) fprintf (stderr,
                "Use vmapdata to map the data through the map\n");
        return (0);
    }

    if (!(proper_color_model (program, img1, VFF_CM_ntscRGB, FALSE)) &&
            (!(proper_color_model (program, img1, VFF_CM_genericRGB, FALSE))) &&
            (!(proper_color_model (program, img1, VFF_CM_ntscYIQ, FALSE))) &&
            (!(proper_color_model (program, img1, VFF_CM_ntscCMY, FALSE))) &&
            (!(proper_color_model (program, img1, VFF_CM_GENERIC, FALSE))) &&
            (!(proper_color_model (program, img1, VFF_CM_cieXYZ, FALSE))) &&
            (!(proper_color_model (program, img1, VFF_CM_cieUVW, FALSE)))) {
        (void) fprintf (stderr, "vcluv: input image must be ");
        (void) fprintf (stderr, "either genericRGB, ntscRGB\n");
        (void) fprintf (stderr, "ntscYIQ, ntscCMY");
        (void) fprintf (stderr, "cieUVW, or GENERIC\n");
        return (0);
    }


    ptr = (float *) (img1 -> imagedata);

    xptr = (float *) (&ptr[0]);
    yptr = (float *) (&ptr[nr * nc]);
    zptr = (float *) (&ptr[2 * nr * nc]);

    /* create the HSV image */
    Luv = (float *) malloc (3 * nc * nr * sizeof (float));
    if (Luv == NULL) {
        (void) fprintf (stderr, "lvcluv: insufficient ");
        (void) fprintf (stderr, "memory available\n");
        return (0);
    }

    Lptr = (float *) & Luv[0];
    uptr = (float *) & Luv[nr * nc];
    vptr = (float *) & Luv[2 * nr * nc];

    /* using the NTSC RGB Receiver Primarys R = 1, G = 1, B = 1, This by
       the following transformation matrix X0, Y0, and Z0 are obtained X0
       = { 0.607,  0.174,  0.201} R Y0 = { 0.299,  0.587,  0.114} G Z0 = {
       0.000,  0.066,  1.117} B */

    X0 = 0.982;
    Y0 = 1.0;
    Z0 = 1.183;

    /* calculate u0 and v0 */
    u0 = (4 * X0) / (X0 + (15 * Y0) + (3 * Z0));
    v0 = (9 * Y0) / (X0 + (15 * Y0) + (3 * Z0));

    one_third_power = 1.0 / 3.0;

    for (i = 0; i < nr * nc; i++) {

        *xptr = *xptr / norm;
        *yptr = *yptr / norm;
        *zptr = *zptr / norm;

        uv_dom = *xptr + (15 * *yptr) + (3 * *zptr);
        u_prime = (4 * *xptr) / uv_dom;
        v_prime = (9 * *yptr) / uv_dom;

        if (*yptr / Y0 <= 0.008856)
            *Lptr = 903.3 * (*yptr / Y0);
        else {
            tmp = pow ((double) ((100 * *yptr) / Y0), one_third_power);
            *Lptr = (25 * (float) tmp) - 16;
        }

        *uptr = 13 * *Lptr * (u_prime - u0);
        *vptr = 13 * *Lptr * (v_prime - v0);

        xptr++;
        yptr++;
        zptr++;
        Lptr++;
        uptr++;
        vptr++;

    }
    free(img1 -> imagedata);
    img1 -> imagedata = (char *) Luv;
    img1 -> color_space_model = VFF_CM_cieucsLuv;

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