Back to index

radiance  4R0+20100331
neuclrtab.c
Go to the documentation of this file.
00001 #ifndef lint
00002 static const char    RCSid[] = "$Id: neuclrtab.c,v 2.13 2007/09/08 19:17:52 greg Exp $";
00003 #endif
00004 /*
00005  * Neural-Net quantization algorithm based on work of Anthony Dekker
00006  */
00007 
00008 #include "copyright.h"
00009 
00010 #include <string.h>
00011 
00012 #include "standard.h"
00013 #include "color.h"
00014 #include "random.h"
00015 #include "clrtab.h"
00016 
00017 #ifdef COMPAT_MODE
00018 #define neu_init     new_histo
00019 #define neu_pixel    cnt_pixel
00020 #define neu_colrs    cnt_colrs
00021 #define neu_clrtab   new_clrtab
00022 #define neu_map_pixel       map_pixel
00023 #define neu_map_colrs       map_colrs
00024 #define neu_dith_colrs      dith_colrs
00025 #endif
00026                             /* our color table (global) */
00027 extern BYTE   clrtab[256][3];
00028 static int    clrtabsiz;
00029 
00030 #ifndef DEFSMPFAC
00031 #define DEFSMPFAC    3
00032 #endif
00033 
00034 int    samplefac = DEFSMPFAC;      /* sampling factor */
00035 
00036               /* Samples array starts off holding spacing between adjacent
00037                * samples, and ends up holding actual BGR sample values.
00038                */
00039 static BYTE   *thesamples;
00040 static int    nsamples;
00041 static BYTE   *cursamp;
00042 static long   skipcount;
00043 
00044 #define MAXSKIP             (1<<24-1)
00045 
00046 #define nskip(sp)    ((long)(sp)[0]<<16|(long)(sp)[1]<<8|(long)(sp)[2])
00047 
00048 #define setskip(sp,n)       ((sp)[0]=(n)>>16,(sp)[1]=((n)>>8)&255,(sp)[2]=(n)&255)
00049 
00050 static void initnet(void);
00051 static void inxbuild(void);
00052 static int inxsearch(int b, int g, int r);
00053 static int contest(int b, int g, int r);
00054 static void altersingle(int alpha, int i, int b, int g, int r);
00055 static void alterneigh(int rad, int i, int b, int g, int r);
00056 static void learn(void);
00057 static void unbiasnet(void);
00058 static void cpyclrtab(void);
00059 
00060 
00061 extern int
00062 neu_init(            /* initialize our sample array */
00063        long   npixels
00064 )
00065 {
00066        register int  nsleft;
00067        register long sv;
00068        double rval, cumprob;
00069        long   npleft;
00070 
00071        nsamples = npixels/samplefac;
00072        if (nsamples < 600)
00073               return(-1);
00074        thesamples = (BYTE *)malloc(nsamples*3);
00075        if (thesamples == NULL)
00076               return(-1);
00077        cursamp = thesamples;
00078        npleft = npixels;
00079        nsleft = nsamples;
00080        while (nsleft) {
00081               rval = frandom();    /* random distance to next sample */
00082               sv = 0;
00083               cumprob = 0.;
00084               while ((cumprob += (1.-cumprob)*nsleft/(npleft-sv)) < rval)
00085                      sv++;
00086               if (nsleft == nsamples)
00087                      skipcount = sv;
00088               else {
00089                      setskip(cursamp, sv);
00090                      cursamp += 3;
00091               }
00092               npleft -= sv+1;
00093               nsleft--;
00094        }
00095        setskip(cursamp, npleft);   /* tag on end to skip the rest */
00096        cursamp = thesamples;
00097        return(0);
00098 }
00099 
00100 
00101 extern void
00102 neu_pixel(                  /* add pixel to our samples */
00103        register BYTE col[]
00104 )
00105 {
00106        if (!skipcount--) {
00107               skipcount = nskip(cursamp);
00108               cursamp[0] = col[BLU];
00109               cursamp[1] = col[GRN];
00110               cursamp[2] = col[RED];
00111               cursamp += 3;
00112        }
00113 }
00114 
00115 
00116 extern void
00117 neu_colrs(           /* add a scanline to our samples */
00118        register COLR *cs,
00119        register int  n
00120 )
00121 {
00122        while (n > skipcount) {
00123               cs += skipcount;
00124               n -= skipcount+1;
00125               skipcount = nskip(cursamp);
00126               cursamp[0] = cs[0][BLU];
00127               cursamp[1] = cs[0][GRN];
00128               cursamp[2] = cs[0][RED];
00129               cs++;
00130               cursamp += 3;
00131        }
00132        skipcount -= n;
00133 }
00134 
00135 
00136 extern int
00137 neu_clrtab(          /* make new color table using ncolors */
00138        int    ncolors
00139 )
00140 {
00141        clrtabsiz = ncolors;
00142        if (clrtabsiz > 256) clrtabsiz = 256;
00143        initnet();
00144        learn();
00145        unbiasnet();
00146        cpyclrtab();
00147        inxbuild();
00148                             /* we're done with our samples */
00149        free((void *)thesamples);
00150                             /* reset dithering function */
00151        neu_dith_colrs((BYTE *)NULL, (COLR *)NULL, 0);
00152                             /* return new color table size */
00153        return(clrtabsiz);
00154 }
00155 
00156 
00157 extern int
00158 neu_map_pixel(              /* get pixel for color */
00159        register BYTE col[]
00160 )
00161 {
00162        return(inxsearch(col[BLU],col[GRN],col[RED]));
00163 }
00164 
00165 
00166 extern void
00167 neu_map_colrs(       /* convert a scanline to color index values */
00168        register BYTE *bs,
00169        register COLR *cs,
00170        register int  n
00171 )
00172 {
00173        while (n-- > 0) {
00174               *bs++ = inxsearch(cs[0][BLU],cs[0][GRN],cs[0][RED]);
00175               cs++;
00176        }
00177 }
00178 
00179 
00180 extern void
00181 neu_dith_colrs(      /* convert scanline to dithered index values */
00182        register BYTE *bs,
00183        register COLR *cs,
00184        int    n
00185 )
00186 {
00187        static short  (*cerr)[3] = NULL;
00188        static int    N = 0;
00189        int    err[3], errp[3];
00190        register int  x, i;
00191 
00192        if (n != N) {        /* get error propogation array */
00193               if (N) {
00194                      free((void *)cerr);
00195                      cerr = NULL;
00196               }
00197               if (n)
00198                      cerr = (short (*)[3])malloc(3*n*sizeof(short));
00199               if (cerr == NULL) {
00200                      N = 0;
00201                      map_colrs(bs, cs, n);
00202                      return;
00203               }
00204               N = n;
00205               memset((char *)cerr, '\0', 3*N*sizeof(short));
00206        }
00207        err[0] = err[1] = err[2] = 0;
00208        for (x = 0; x < n; x++) {
00209               for (i = 0; i < 3; i++) {   /* dither value */
00210                      errp[i] = err[i];
00211                      err[i] += cerr[x][i];
00212 #ifdef MAXERR
00213                      if (err[i] > MAXERR) err[i] = MAXERR;
00214                      else if (err[i] < -MAXERR) err[i] = -MAXERR;
00215 #endif
00216                      err[i] += cs[x][i];
00217                      if (err[i] < 0) err[i] = 0;
00218                      else if (err[i] > 255) err[i] = 255;
00219               }
00220               bs[x] = inxsearch(err[BLU],err[GRN],err[RED]);
00221               for (i = 0; i < 3; i++) {   /* propagate error */
00222                      err[i] -= clrtab[bs[x]][i];
00223                      err[i] /= 3;
00224                      cerr[x][i] = err[i] + errp[i];
00225               }
00226        }
00227 }
00228 
00229 /* The following was adapted and modified from the original (GW)        */
00230 
00231 /* cheater definitions (GW) */
00232 #define thepicture   thesamples
00233 #define lengthcount  (nsamples*3)
00234 #define samplefac    1
00235 
00236 /* NeuQuant Neural-Net Quantization Algorithm Interface
00237  * ----------------------------------------------------
00238  *
00239  * Copyright (c) 1994 Anthony Dekker
00240  *
00241  * NEUQUANT Neural-Net quantization algorithm by Anthony Dekker, 1994.
00242  * See "Kohonen neural networks for optimal colour quantization"
00243  * in "Network: Computation in Neural Systems" Vol. 5 (1994) pp 351-367.
00244  * for a discussion of the algorithm.
00245  * See also  http://members.ozemail.com.au/~dekker/NEUQUANT.HTML
00246  *
00247  * Any party obtaining a copy of these files from the author, directly or
00248  * indirectly, is granted, free of charge, a full and unrestricted irrevocable,
00249  * world-wide, paid up, royalty-free, nonexclusive right and license to deal
00250  * in this software and documentation files (the "Software"), including without
00251  * limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
00252  * and/or sell copies of the Software, and to permit persons who receive
00253  * copies from any such party to do so, with the only requirement being
00254  * that this copyright notice remain intact.
00255  */
00256 
00257 #define bool         int
00258 #define false        0
00259 #define true         1
00260 
00261 /* network defs */
00262 #define netsize             clrtabsiz            /* number of colours - can change this */
00263 #define maxnetpos    (netsize-1)
00264 #define netbiasshift 4                    /* bias for colour values */
00265 #define ncycles             100                  /* no. of learning cycles */
00266 
00267 /* defs for freq and bias */
00268 #define intbiasshift    16                /* bias for fractions */
00269 #define intbias             (((int) 1)<<intbiasshift)
00270 #define gammashift   10                   /* gamma = 1024 */
00271 #define gamma        (((int) 1)<<gammashift)
00272 #define betashift    10
00273 #define beta         (intbias>>betashift) /* beta = 1/1024 */
00274 #define betagamma    (intbias<<(gammashift-betashift))
00275 
00276 /* defs for decreasing radius factor */
00277 #define initrad             (256>>3)             /* for 256 cols, radius starts */
00278 #define radiusbiasshift     6                    /* at 32.0 biased by 6 bits */
00279 #define radiusbias   (((int) 1)<<radiusbiasshift)
00280 #define initradius   (initrad*radiusbias) /* and decreases by a */
00281 #define radiusdec    30                   /* factor of 1/30 each cycle */ 
00282 
00283 /* defs for decreasing alpha factor */
00284 #define alphabiasshift      10                   /* alpha starts at 1.0 */
00285 #define initalpha    (((int) 1)<<alphabiasshift)
00286 int alphadec;                             /* biased by 10 bits */
00287 
00288 /* radbias and alpharadbias used for radpower calculation */
00289 #define radbiasshift 8
00290 #define radbias             (((int) 1)<<radbiasshift)
00291 #define alpharadbshift  (alphabiasshift+radbiasshift)
00292 #define alpharadbias    (((int) 1)<<alpharadbshift)
00293 
00294 /* four primes near 500 - assume no image has a length so large */
00295 /* that it is divisible by all four primes */
00296 #define prime1              499
00297 #define prime2              491
00298 #define prime3              487
00299 #define prime4              503
00300 
00301 typedef int pixel[4];  /* BGRc */
00302 pixel network[256];
00303 
00304 int netindex[256];   /* for network lookup - really 256 */
00305 
00306 int bias [256];             /* bias and freq arrays for learning */
00307 int freq [256];
00308 int radpower[initrad];      /* radpower for precomputation */
00309 
00310 
00311 /* initialise network in range (0,0,0) to (255,255,255) */
00312 
00313 static void
00314 initnet(void) 
00315 {
00316        register int i;
00317        register int *p;
00318        
00319        for (i=0; i<netsize; i++) {
00320               p = network[i];
00321               p[0] = p[1] = p[2] = (i << (netbiasshift+8))/netsize;
00322               freq[i] = intbias/netsize;  /* 1/netsize */
00323               bias[i] = 0;
00324        }
00325 }
00326 
00327 
00328 /* do after unbias - insertion sort of network and build netindex[0..255] */
00329 
00330 static void
00331 inxbuild(void)
00332 {
00333        register int i,j,smallpos,smallval;
00334        register int *p,*q;
00335        int previouscol,startpos;
00336 
00337        previouscol = 0;
00338        startpos = 0;
00339        for (i=0; i<netsize; i++) {
00340               p = network[i];
00341               smallpos = i;
00342               smallval = p[1];     /* index on g */
00343               /* find smallest in i..netsize-1 */
00344               for (j=i+1; j<netsize; j++) {
00345                      q = network[j];
00346                      if (q[1] < smallval) {      /* index on g */
00347                             smallpos = j;
00348                             smallval = q[1]; /* index on g */
00349                      }
00350               }
00351               q = network[smallpos];
00352               /* swap p (i) and q (smallpos) entries */
00353               if (i != smallpos) {
00354                      j = q[0];   q[0] = p[0];   p[0] = j;
00355                      j = q[1];   q[1] = p[1];   p[1] = j;
00356                      j = q[2];   q[2] = p[2];   p[2] = j;
00357                      j = q[3];   q[3] = p[3];   p[3] = j;
00358               }
00359               /* smallval entry is now in position i */
00360               if (smallval != previouscol) {
00361                      netindex[previouscol] = (startpos+i)>>1;
00362                      for (j=previouscol+1; j<smallval; j++) netindex[j] = i;
00363                      previouscol = smallval;
00364                      startpos = i;
00365               }
00366        }
00367        netindex[previouscol] = (startpos+maxnetpos)>>1;
00368        for (j=previouscol+1; j<256; j++) netindex[j] = maxnetpos; /* really 256 */
00369 }
00370 
00371 
00372 static int
00373 inxsearch(  /* accepts real BGR values after net is unbiased */
00374        register int b,
00375        register int g,
00376        register int r
00377 )
00378 {
00379        register int i,j,dist,a,bestd;
00380        register int *p;
00381        int best;
00382 
00383        bestd = 1000; /* biggest possible dist is 256*3 */
00384        best = -1;
00385        i = netindex[g]; /* index on g */
00386        j = i-1;       /* start at netindex[g] and work outwards */
00387 
00388        while ((i<netsize) || (j>=0)) {
00389               if (i<netsize) {
00390                      p = network[i];
00391                      dist = p[1] - g;     /* inx key */
00392                      if (dist >= bestd) i = netsize; /* stop iter */
00393                      else {
00394                             i++;
00395                             if (dist<0) dist = -dist;
00396                             a = p[0] - b;   if (a<0) a = -a;
00397                             dist += a;
00398                             if (dist<bestd) {
00399                                    a = p[2] - r;   if (a<0) a = -a;
00400                                    dist += a;
00401                                    if (dist<bestd) {bestd=dist; best=p[3];}
00402                             }
00403                      }
00404               }
00405               if (j>=0) {
00406                      p = network[j];
00407                      dist = g - p[1]; /* inx key - reverse dif */
00408                      if (dist >= bestd) j = -1; /* stop iter */
00409                      else {
00410                             j--;
00411                             if (dist<0) dist = -dist;
00412                             a = p[0] - b;   if (a<0) a = -a;
00413                             dist += a;
00414                             if (dist<bestd) {
00415                                    a = p[2] - r;   if (a<0) a = -a;
00416                                    dist += a;
00417                                    if (dist<bestd) {bestd=dist; best=p[3];}
00418                             }
00419                      }
00420               }
00421        }
00422        return(best);
00423 }
00424 
00425 
00426 /* finds closest neuron (min dist) and updates freq */
00427 /* finds best neuron (min dist-bias) and returns position */
00428 /* for frequently chosen neurons, freq[i] is high and bias[i] is negative */
00429 /* bias[i] = gamma*((1/netsize)-freq[i]) */
00430 
00431 static int
00432 contest(      /* accepts biased BGR values */
00433        register int b,
00434        register int g,
00435        register int r
00436 )
00437 {
00438        register int i,dist,a,biasdist,betafreq;
00439        int bestpos,bestbiaspos,bestd,bestbiasd;
00440        register int *p,*f, *n;
00441 
00442        bestd = ~(((int) 1)<<31);
00443        bestbiasd = bestd;
00444        bestpos = -1;
00445        bestbiaspos = bestpos;
00446        p = bias;
00447        f = freq;
00448 
00449        for (i=0; i<netsize; i++) {
00450               n = network[i];
00451               dist = n[0] - b;   if (dist<0) dist = -dist;
00452               a = n[1] - g;   if (a<0) a = -a;
00453               dist += a;
00454               a = n[2] - r;   if (a<0) a = -a;
00455               dist += a;
00456               if (dist<bestd) {bestd=dist; bestpos=i;}
00457               biasdist = dist - ((*p)>>(intbiasshift-netbiasshift));
00458               if (biasdist<bestbiasd) {bestbiasd=biasdist; bestbiaspos=i;}
00459               betafreq = (*f >> betashift);
00460               *f++ -= betafreq;
00461               *p++ += (betafreq<<gammashift);
00462        }
00463        freq[bestpos] += beta;
00464        bias[bestpos] -= betagamma;
00465        return(bestbiaspos);
00466 }
00467 
00468 
00469 /* move neuron i towards (b,g,r) by factor alpha */
00470 
00471 static void
00472 altersingle(  /* accepts biased BGR values */
00473        register int alpha,
00474        register int i,
00475        register int b,
00476        register int g,
00477        register int r
00478 )
00479 {
00480        register int *n;
00481 
00482        n = network[i];             /* alter hit neuron */
00483        *n -= (alpha*(*n - b)) / initalpha;
00484        n++;
00485        *n -= (alpha*(*n - g)) / initalpha;
00486        n++;
00487        *n -= (alpha*(*n - r)) / initalpha;
00488 }
00489 
00490 
00491 /* move neurons adjacent to i towards (b,g,r) by factor */
00492 /* alpha*(1-((i-j)^2/[r]^2)) precomputed as radpower[|i-j|]*/
00493 
00494 static void
00495 alterneigh(   /* accents biased BGR values */
00496        int rad,
00497        int i,
00498        register int b,
00499        register int g,
00500        register int r
00501 )
00502 {
00503        register int j,k,lo,hi,a;
00504        register int *p, *q;
00505 
00506        lo = i-rad;   if (lo<-1) lo= -1;
00507        hi = i+rad;   if (hi>netsize) hi=netsize;
00508 
00509        j = i+1;
00510        k = i-1;
00511        q = radpower;
00512        while ((j<hi) || (k>lo)) {
00513               a = (*(++q));
00514               if (j<hi) {
00515                      p = network[j];
00516                      *p -= (a*(*p - b)) / alpharadbias;
00517                      p++;
00518                      *p -= (a*(*p - g)) / alpharadbias;
00519                      p++;
00520                      *p -= (a*(*p - r)) / alpharadbias;
00521                      j++;
00522               }
00523               if (k>lo) {
00524                      p = network[k];
00525                      *p -= (a*(*p - b)) / alpharadbias;
00526                      p++;
00527                      *p -= (a*(*p - g)) / alpharadbias;
00528                      p++;
00529                      *p -= (a*(*p - r)) / alpharadbias;
00530                      k--;
00531               }
00532        }
00533 }
00534 
00535 
00536 static void
00537 learn(void)
00538 {
00539        register int i,j,b,g,r;
00540        int radius,rad,alpha,step,delta,samplepixels;
00541        register unsigned char *p;
00542        unsigned char *lim;
00543 
00544        alphadec = 30 + ((samplefac-1)/3);
00545        p = thepicture;
00546        lim = thepicture + lengthcount;
00547        samplepixels = lengthcount/(3*samplefac);
00548        delta = samplepixels/ncycles;
00549        alpha = initalpha;
00550        radius = initradius;
00551        
00552        rad = radius >> radiusbiasshift;
00553        if (rad <= 1) rad = 0;
00554        for (i=0; i<rad; i++) 
00555               radpower[i] = alpha*(((rad*rad - i*i)*radbias)/(rad*rad));
00556        
00557        if ((lengthcount%prime1) != 0) step = 3*prime1;
00558        else {
00559               if ((lengthcount%prime2) !=0) step = 3*prime2;
00560               else {
00561                      if ((lengthcount%prime3) !=0) step = 3*prime3;
00562                      else step = 3*prime4;
00563               }
00564        }
00565        
00566        i = 0;
00567        while (i < samplepixels) {
00568               b = p[0] << netbiasshift;
00569               g = p[1] << netbiasshift;
00570               r = p[2] << netbiasshift;
00571               j = contest(b,g,r);
00572 
00573               altersingle(alpha,j,b,g,r);
00574               if (rad) alterneigh(rad,j,b,g,r);   /* alter neighbours */
00575 
00576               p += step;
00577               if (p >= lim) p -= lengthcount;
00578        
00579               i++;
00580               if (i%delta == 0) {  
00581                      alpha -= alpha / alphadec;
00582                      radius -= radius / radiusdec;
00583                      rad = radius >> radiusbiasshift;
00584                      if (rad <= 1) rad = 0;
00585                      for (j=0; j<rad; j++) 
00586                             radpower[j] = alpha*(((rad*rad - j*j)*radbias)/(rad*rad));
00587               }
00588        }
00589 }
00590        
00591 /* unbias network to give 0..255 entries */
00592 /* which can then be used for colour map */
00593 /* and record position i to prepare for sort */
00594 
00595 static void
00596 unbiasnet(void)
00597 {
00598        int i,j;
00599 
00600        for (i=0; i<netsize; i++) {
00601               for (j=0; j<3; j++)
00602                      network[i][j] >>= netbiasshift;
00603               network[i][3] = i; /* record colour no */
00604        }
00605 }
00606 
00607 
00608 /* Don't do this until the network has been unbiased (GW) */
00609               
00610 static void
00611 cpyclrtab(void)
00612 {
00613        register int i,j,k;
00614        
00615        for (j=0; j<netsize; j++) {
00616               k = network[j][3];
00617               for (i = 0; i < 3; i++)
00618                      clrtab[k][i] = network[j][2-i];
00619        }
00620 }