Back to index

radiance  4R0+20100331
tmapluv.c
Go to the documentation of this file.
00001 #ifndef lint
00002 static const char    RCSid[] = "$Id: tmapluv.c,v 3.14 2009/02/09 20:48:08 greg Exp $";
00003 #endif
00004 /*
00005  * Routines for tone-mapping LogLuv encoded pixels.
00006  *
00007  * Externals declared in tmaptiff.h
00008  */
00009 
00010 #include "copyright.h"
00011 
00012 #define LOGLUV_PUBLIC              1
00013 
00014 #include <stdio.h>
00015 #include <stdlib.h>
00016 #include <string.h>
00017 #include <math.h>
00018 #include "tmprivat.h"
00019 #include "tiffio.h"
00020 #include "tmaptiff.h"
00021 
00022 #define uvflgop(p,uv,op)    ((p)->rgbflg[(uv)>>5] op (1L<<((uv)&0x1f)))
00023 #define isuvset(p,uv)              uvflgop(p,uv,&)
00024 #define setuv(p,uv)         uvflgop(p,uv,|=)
00025 #define clruv(p,uv)         uvflgop(p,uv,&=~)
00026 #define clruvall(p)         memset((MEM_PTR)(p)->rgbflg,'\0',sizeof((p)->rgbflg))
00027 
00028 #ifdef NOPROTO
00029 static MEM_PTR       luv32Init();
00030 static void   luv32NewSpace();
00031 static MEM_PTR       luv24Init();
00032 static void   luv24NewSpace();
00033 #else
00034 static MEM_PTR       luv32Init(TMstruct *);
00035 static void   luv32NewSpace(TMstruct *);
00036 static MEM_PTR       luv24Init(TMstruct *);
00037 static void   luv24NewSpace(TMstruct *);
00038 #endif
00039 
00040 typedef struct {
00041        int    offset;                     /* computed luminance offset */
00042        BYTE   rgbval[1<<16][3];    /* computed RGB value for given uv */
00043        uint32 rgbflg[1<<(16-5)];   /* flags for computed values */
00044 } LUV32DATA;                /* LogLuv 32-bit conversion data */
00045 
00046 #define UVNEU               ((int)(UVSCALE*U_NEU)<<8 \
00047                                    | (int)(UVSCALE*V_NEU))
00048 
00049 static struct tmPackage  luv32Pkg = {     /* 32-bit package functions */
00050        luv32Init, luv32NewSpace, free
00051 };
00052 static int    luv32Reg = -1;              /* 32-bit package reg. number */
00053 
00054 typedef struct {
00055        int    offset;                     /* computed luminance offset */
00056        BYTE   rgbval[1<<14][3];    /* computed rgb value for uv index */
00057        uint32 rgbflg[1<<(14-5)];   /* flags for computed values */
00058 } LUV24DATA;                /* LogLuv 24-bit conversion data */
00059 
00060 static struct tmPackage  luv24Pkg = {     /* 24-bit package functions */
00061        luv24Init, luv24NewSpace, free
00062 };
00063 static int    luv24Reg = -1;              /* 24-bit package reg. number */
00064 
00065 static int    uv14neu = -1;        /* neutral index for 14-bit (u',v') */
00066 
00067 
00068 static void
00069 uv2rgb(rgb, tms, uvp)                     /* compute RGB from uv coordinate */
00070 BYTE   rgb[3];
00071 register TMstruct    *tms;
00072 double uvp[2];
00073 {      /* Should check that tms->inppri==TM_XYZPRIM beforehand... */
00074        double d, x, y;
00075        COLOR  XYZ, RGB;
00076                                    /* convert to XYZ */
00077        d = 1./(6.*uvp[0] - 16.*uvp[1] + 12.);
00078        x = 9.*uvp[0] * d;
00079        y = 4.*uvp[1] * d;
00080        XYZ[CIEY] = 1./tms->inpsf;
00081        XYZ[CIEX] = x/y * XYZ[CIEY];
00082        XYZ[CIEZ] = (1.-x-y)/y * XYZ[CIEY];
00083                                    /* convert to RGB and clip */
00084        colortrans(RGB, tms->cmat, XYZ);
00085        clipgamut(RGB, 1., CGAMUT_LOWER, cblack, cwhite);
00086                                    /* perform final scaling & gamma */
00087        d = tms->clf[RED] * RGB[RED];
00088        rgb[RED] = d>=.999 ? 255 : (int)(256.*pow(d, 1./tms->mongam));
00089        d = tms->clf[GRN] * RGB[GRN];
00090        rgb[GRN] = d>=.999 ? 255 : (int)(256.*pow(d, 1./tms->mongam));
00091        d = tms->clf[BLU] * RGB[BLU];
00092        rgb[BLU] = d>=.999 ? 255 : (int)(256.*pow(d, 1./tms->mongam));
00093 }
00094 
00095 
00096 static TMbright
00097 compmeshift(li, uvp)               /* compute mesopic color shift */
00098 TMbright      li;           /* encoded world luminance */
00099 double uvp[2];                     /* world (u',v') -> returned desaturated */
00100 {
00101        double scotrat;
00102        register double      d;
00103 
00104        if (li >= BMESUPPER)
00105               return(li);
00106        scotrat = (.767676768 - 1.02356902*uvp[1])/uvp[0] - .343434343;
00107        if (li <= BMESLOWER) {
00108               d = 0.;
00109               uvp[0] = U_NEU; uvp[1] = V_NEU;
00110        } else {
00111               d = (tmMesofact[li-BMESLOWER] + .5) * (1./256.);
00112               uvp[0] = d*uvp[0] + (1.-d)*U_NEU;
00113               uvp[1] = d*uvp[1] + (1.-d)*V_NEU;
00114        }
00115        /*
00116        d = li + (double)TM_BRTSCALE*log(d + (1.-d)*scotrat);
00117        */
00118        d = d + (1.-d)*scotrat;
00119        d -= 1.;                    /* Taylor expansion of log(x) about 1 */
00120        d = d*(1. + d*(-.5 + d*(1./3. + d*-.125)));
00121        d = li + (double)TM_BRTSCALE*d;
00122        return((TMbright)(d>0. ? d+.5 : d-.5));
00123 }
00124 
00125 
00126 int
00127 tmCvLuv32(                         /* convert raw 32-bit LogLuv values */
00128 TMstruct      *tms,
00129 TMbright      *ls,
00130 BYTE   *cs,
00131 uint32 *luvs,
00132 int    len
00133 )
00134 {
00135        static const char    funcName[] = "tmCvLuv32";
00136        double uvp[2];
00137        register LUV32DATA   *ld;
00138        register int  i, j;
00139                                    /* check arguments */
00140        if (tms == NULL)
00141               returnErr(TM_E_TMINVAL);
00142        if ((ls == NULL) | (luvs == NULL) | (len < 0))
00143               returnErr(TM_E_ILLEGAL);
00144                                    /* check package registration */
00145        if (luv32Reg < 0) {
00146               if ((luv32Reg = tmRegPkg(&luv32Pkg)) < 0)
00147                      returnErr(TM_E_CODERR1);
00148               tmMkMesofact();
00149        }
00150                                    /* get package data */
00151        if ((ld = (LUV32DATA *)tmPkgData(tms,luv32Reg)) == NULL)
00152               returnErr(TM_E_NOMEM);
00153                                    /* convert each pixel */
00154        for (i = len; i--; ) {
00155               j = luvs[i] >> 16;          /* get luminance */
00156               if (j & 0x8000)                    /* negative luminance */
00157                      ls[i] = TM_NOBRT;    /* assign bogus value */
00158               else                        /* else convert to lnL */
00159                      ls[i] = (BRT2SCALE(j) >> 8) - ld->offset;
00160               if (cs == TM_NOCHROM)              /* no color? */
00161                      continue;
00162                                           /* get chrominance */
00163               if (tms->flags & TM_F_MESOPIC && ls[i] < BMESUPPER) {
00164                      uvp[0] = 1./UVSCALE*((luvs[i]>>8 & 0xff) + .5);
00165                      uvp[1] = 1./UVSCALE*((luvs[i] & 0xff) + .5);
00166                      ls[i] = compmeshift(ls[i], uvp);
00167                      j = tms->flags&TM_F_BW || ls[i]<BMESLOWER
00168                                    ? UVNEU
00169                                    : (int)(uvp[0]*UVSCALE)<<8
00170                                           | (int)(uvp[1]*UVSCALE);
00171               } else {
00172                      j = tms->flags&TM_F_BW ? UVNEU : luvs[i]&0xffff;
00173               }
00174               if (!isuvset(ld, j)) {
00175                      uvp[0] = 1./UVSCALE*((j>>8) + .5);
00176                      uvp[1] = 1./UVSCALE*((j & 0xff) + .5);
00177                      uv2rgb(ld->rgbval[j], tms, uvp);
00178                      setuv(ld, j);
00179               }
00180               cs[3*i  ] = ld->rgbval[j][RED];
00181               cs[3*i+1] = ld->rgbval[j][GRN];
00182               cs[3*i+2] = ld->rgbval[j][BLU];
00183        }
00184        returnOK;
00185 }
00186 
00187 
00188 int
00189 tmCvLuv24(                  /* convert raw 24-bit LogLuv values */
00190 TMstruct      *tms,
00191 TMbright      *ls,
00192 BYTE   *cs,
00193 uint32 *luvs,
00194 int    len
00195 )
00196 {
00197        char   funcName[] = "tmCvLuv24";
00198        double uvp[2];
00199        register LUV24DATA   *ld;
00200        register int  i, j;
00201                                    /* check arguments */
00202        if (tms == NULL)
00203               returnErr(TM_E_TMINVAL);
00204        if ((ls == NULL) | (luvs == NULL) | (len < 0))
00205               returnErr(TM_E_ILLEGAL);
00206                                    /* check package registration */
00207        if (luv24Reg < 0) {
00208               if ((luv24Reg = tmRegPkg(&luv24Pkg)) < 0)
00209                      returnErr(TM_E_CODERR1);
00210               tmMkMesofact();
00211        }
00212                                    /* get package data */
00213        if ((ld = (LUV24DATA *)tmPkgData(tms,luv24Reg)) == NULL)
00214               returnErr(TM_E_NOMEM);
00215                                    /* convert each pixel */
00216        for (i = len; i--; ) {
00217               j = luvs[i] >> 14;          /* get luminance */
00218               ls[i] = (BRT2SCALE(j) >> 6) - ld->offset;
00219               if (cs == TM_NOCHROM)              /* no color? */
00220                      continue;
00221                                           /* get chrominance */
00222               if (tms->flags & TM_F_MESOPIC && ls[i] < BMESUPPER) {
00223                      if (uv_decode(&uvp[0], &uvp[1], luvs[i]&0x3fff) < 0) {
00224                             uvp[0] = U_NEU;             /* should barf? */
00225                             uvp[1] = V_NEU;
00226                      }
00227                      ls[i] = compmeshift(ls[i], uvp);
00228                      if (tms->flags&TM_F_BW || ls[i]<BMESLOWER
00229                                    || (j = uv_encode(uvp[0], uvp[1],
00230                                           SGILOGENCODE_NODITHER)) < 0)
00231                             j = uv14neu;
00232               } else {
00233                      j = tms->flags&TM_F_BW ? uv14neu :
00234                                    (int)(luvs[i]&0x3fff);
00235               }
00236               if (!isuvset(ld, j)) {
00237                      if (uv_decode(&uvp[0], &uvp[1], j) < 0) {
00238                             uvp[0] = U_NEU; uvp[1] = V_NEU;
00239                      }
00240                      uv2rgb(ld->rgbval[j], tms, uvp);
00241                      setuv(ld, j);
00242               }
00243               cs[3*i  ] = ld->rgbval[j][RED];
00244               cs[3*i+1] = ld->rgbval[j][GRN];
00245               cs[3*i+2] = ld->rgbval[j][BLU];
00246        }
00247        returnOK;
00248 }
00249 
00250 
00251 int
00252 tmCvL16(                           /* convert 16-bit LogL values */
00253 TMstruct      *tms,
00254 TMbright      *ls,
00255 uint16 *l16s,
00256 int    len
00257 )
00258 {
00259        static const char    funcName[] = "tmCvL16";
00260        static double lastsf;
00261        static int    offset;
00262        register int  i;
00263                                    /* check arguments */
00264        if (tms == NULL)
00265               returnErr(TM_E_TMINVAL);
00266        if ((ls == NULL) | (l16s == NULL) | (len < 0))
00267               returnErr(TM_E_ILLEGAL);
00268                                    /* check scaling offset */
00269        if (!FEQ(tms->inpsf, lastsf)) {
00270               offset = BRT2SCALE(64) - tmCvLuminance(tms->inpsf);
00271               lastsf = tms->inpsf;
00272        }
00273                                    /* convert each pixel */
00274        for (i = len; i--; ) {
00275               if (l16s[i] & 0x8000)              /* negative luminance */
00276                      ls[i] = TM_NOBRT;    /* assign bogus value */
00277               else                        /* else convert to lnL */
00278                      ls[i] = (BRT2SCALE(l16s[i]) >> 8) - offset;
00279        }
00280        returnOK;
00281 }
00282 
00283 
00284 static void
00285 luv32NewSpace(tms)          /* initialize 32-bit LogLuv color space */
00286 TMstruct      *tms;
00287 {
00288        register LUV32DATA   *ld;
00289 
00290        if (tms->inppri != TM_XYZPRIM) {          /* panic time! */
00291               fputs("Improper input color space in luv32NewSpace!\n", stderr);
00292               exit(1);
00293        }
00294        ld = (LUV32DATA *)tms->pd[luv32Reg];
00295        ld->offset = BRT2SCALE(64) - tmCvLuminance(tms->inpsf);
00296        clruvall(ld);
00297 }
00298 
00299 
00300 static MEM_PTR
00301 luv32Init(tms)                     /* allocate data for 32-bit LogLuv decoder */
00302 TMstruct      *tms;
00303 {
00304        register LUV32DATA   *ld;
00305 
00306        ld = (LUV32DATA *)malloc(sizeof(LUV32DATA));
00307        if (ld == NULL)
00308               return(NULL);
00309        tms->pd[luv32Reg] = (MEM_PTR)ld;
00310        luv32NewSpace(tms);
00311        return((MEM_PTR)ld);
00312 }
00313 
00314 
00315 static void
00316 luv24NewSpace(tms)          /* initialize 24-bit LogLuv color space */
00317 TMstruct *tms;
00318 {
00319        register LUV24DATA   *ld;
00320 
00321        if (tms->inppri != TM_XYZPRIM) {          /* panic time! */
00322               fputs("Improper input color space in luv24NewSpace!\n", stderr);
00323               exit(1);
00324        }
00325        ld = (LUV24DATA *)tms->pd[luv24Reg];
00326        ld->offset = BRT2SCALE(12) - tmCvLuminance(tms->inpsf);
00327        clruvall(ld);
00328 }
00329 
00330 
00331 static MEM_PTR
00332 luv24Init(tms)                     /* allocate data for 24-bit LogLuv decoder */
00333 TMstruct      *tms;
00334 {
00335        register LUV24DATA   *ld;
00336 
00337        ld = (LUV24DATA *)malloc(sizeof(LUV24DATA));
00338        if (ld == NULL)
00339               return(NULL);
00340        tms->pd[luv24Reg] = (MEM_PTR)ld;
00341        if (uv14neu < 0)            /* initialize neutral color index */
00342               uv14neu = uv_encode(U_NEU, V_NEU, SGILOGENCODE_NODITHER);
00343        luv24NewSpace(tms);
00344        return((MEM_PTR)ld);
00345 }