ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/px/clrtab.c
Revision: 2.16
Committed: Sun Jul 27 22:12:03 2003 UTC (20 years, 9 months ago) by schorsch
Content type: text/plain
Branch: MAIN
Changes since 2.15: +2 -2 lines
Log Message:
Added grouping parens to reduce ambiguity warnings.

File Contents

# User Rev Content
1 greg 2.1 #ifndef lint
2 schorsch 2.16 static const char RCSid[] = "$Id: clrtab.c,v 2.15 2003/06/30 14:59:12 schorsch Exp $";
3 greg 2.1 #endif
4     /*
5     * Simple median-cut color quantization based on colortab.c
6     */
7    
8 schorsch 2.15 #include "copyright.h"
9    
10     #include <string.h>
11    
12 greg 2.1 #include "standard.h"
13 schorsch 2.15 #include "color.h"
14 greg 2.1
15     /* histogram resolution */
16     #define NRED 36
17     #define NGRN 48
18     #define NBLU 24
19     #define HMAX NGRN
20     /* minimum box count for adaptive partition */
21     #define MINSAMP 7
22     /* color partition */
23     #define set_branch(p,c) ((c)<<2|(p))
24     #define part(cn) ((cn)>>2)
25     #define prim(cn) ((cn)&3)
26     /* our color table (global) */
27 greg 2.10 extern BYTE clrtab[256][3];
28 greg 2.1 /* histogram of colors / color assignments */
29     static unsigned histo[NRED][NGRN][NBLU];
30     #define cndx(c) histo[((c)[RED]*NRED)>>8][((c)[GRN]*NGRN)>>8][((c)[BLU]*NBLU)>>8]
31     /* initial color cube boundary */
32     static int CLRCUBE[3][2] = {0,NRED,0,NGRN,0,NBLU};
33     /* maximum propagated error during dithering */
34     #define MAXERR 20
35 greg 2.2 /* define CLOSEST to get closest colors */
36 greg 2.4 #ifndef CLOSEST
37     #ifdef SPEED
38     #if SPEED > 8
39     #define CLOSEST 1 /* this step takes a little longer */
40     #endif
41     #endif
42     #endif
43 greg 2.1
44 greg 2.11 static cut(), mktabent(), closest(), addneigh(), setclosest();
45     static int split();
46     static unsigned dist();
47    
48 greg 2.1
49 greg 2.10 new_histo(n) /* clear our histogram */
50     int n;
51 greg 2.1 {
52 schorsch 2.15 memset((void *)histo, '\0', sizeof(histo));
53 greg 2.10 return(0);
54 greg 2.1 }
55    
56    
57     cnt_pixel(col) /* add pixel to our histogram */
58     register BYTE col[];
59     {
60     cndx(col)++;
61     }
62    
63    
64     cnt_colrs(cs, n) /* add a scanline to our histogram */
65     register COLR *cs;
66     register int n;
67     {
68     while (n-- > 0) {
69     cndx(cs[0])++;
70     cs++;
71     }
72     }
73    
74    
75     new_clrtab(ncolors) /* make new color table using ncolors */
76     int ncolors;
77     {
78     if (ncolors < 1)
79     return(0);
80     if (ncolors > 256)
81     ncolors = 256;
82     /* partition color space */
83     cut(CLRCUBE, 0, ncolors);
84 greg 2.2 #ifdef CLOSEST
85     closest(ncolors); /* ensure colors picked are closest */
86     #endif
87 greg 2.9 /* reset dithering function */
88     dith_colrs((BYTE *)NULL, (COLR *)NULL, 0);
89 greg 2.1 /* return new color table size */
90     return(ncolors);
91     }
92    
93    
94     int
95     map_pixel(col) /* get pixel for color */
96     register BYTE col[];
97     {
98     return(cndx(col));
99     }
100    
101    
102     map_colrs(bs, cs, n) /* convert a scanline to color index values */
103     register BYTE *bs;
104     register COLR *cs;
105     register int n;
106     {
107     while (n-- > 0) {
108     *bs++ = cndx(cs[0]);
109     cs++;
110     }
111     }
112    
113    
114     dith_colrs(bs, cs, n) /* convert scanline to dithered index values */
115     register BYTE *bs;
116     register COLR *cs;
117     int n;
118     {
119 greg 2.8 static short (*cerr)[3] = NULL;
120 greg 2.1 static int N = 0;
121     int err[3], errp[3];
122     register int x, i;
123    
124     if (n != N) { /* get error propogation array */
125 greg 2.8 if (N) {
126 greg 2.12 free((void *)cerr);
127 greg 2.8 cerr = NULL;
128     }
129     if (n)
130 greg 2.1 cerr = (short (*)[3])malloc(3*n*sizeof(short));
131     if (cerr == NULL) {
132     N = 0;
133     map_colrs(bs, cs, n);
134     return;
135     }
136     N = n;
137 schorsch 2.15 memset((void *)cerr, '\0', 3*N*sizeof(short));
138 greg 2.1 }
139     err[0] = err[1] = err[2] = 0;
140     for (x = 0; x < n; x++) {
141     for (i = 0; i < 3; i++) { /* dither value */
142     errp[i] = err[i];
143     err[i] += cerr[x][i];
144     #ifdef MAXERR
145     if (err[i] > MAXERR) err[i] = MAXERR;
146     else if (err[i] < -MAXERR) err[i] = -MAXERR;
147     #endif
148     err[i] += cs[x][i];
149     if (err[i] < 0) err[i] = 0;
150     else if (err[i] > 255) err[i] = 255;
151     }
152     bs[x] = cndx(err);
153     for (i = 0; i < 3; i++) { /* propagate error */
154     err[i] -= clrtab[bs[x]][i];
155     err[i] /= 3;
156     cerr[x][i] = err[i] + errp[i];
157     }
158     }
159     }
160    
161    
162     static
163     cut(box, c0, c1) /* partition color space */
164     register int box[3][2];
165     int c0, c1;
166     {
167     register int branch;
168     int kb[3][2];
169    
170     if (c1-c0 <= 1) { /* assign pixel */
171     mktabent(c0, box);
172     return;
173     }
174     /* split box */
175     branch = split(box);
176 schorsch 2.15 memcpy((void *)kb, (void *)box, sizeof(kb));
177 greg 2.1 /* do left (lesser) branch */
178     kb[prim(branch)][1] = part(branch);
179     cut(kb, c0, (c0+c1)>>1);
180     /* do right branch */
181     kb[prim(branch)][0] = part(branch);
182     kb[prim(branch)][1] = box[prim(branch)][1];
183     cut(kb, (c0+c1)>>1, c1);
184     }
185    
186    
187     static int
188     split(box) /* find median cut for box */
189     register int box[3][2];
190     {
191     #define c0 r
192     register int r, g, b;
193     int pri;
194 greg 2.6 long t[HMAX], med;
195 greg 2.1 /* find dominant axis */
196     pri = RED;
197     if (box[GRN][1]-box[GRN][0] > box[pri][1]-box[pri][0])
198     pri = GRN;
199     if (box[BLU][1]-box[BLU][0] > box[pri][1]-box[pri][0])
200     pri = BLU;
201     /* sum histogram over box */
202     med = 0;
203     switch (pri) {
204     case RED:
205     for (r = box[RED][0]; r < box[RED][1]; r++) {
206     t[r] = 0;
207     for (g = box[GRN][0]; g < box[GRN][1]; g++)
208     for (b = box[BLU][0]; b < box[BLU][1]; b++)
209     t[r] += histo[r][g][b];
210     med += t[r];
211     }
212     break;
213     case GRN:
214     for (g = box[GRN][0]; g < box[GRN][1]; g++) {
215     t[g] = 0;
216     for (b = box[BLU][0]; b < box[BLU][1]; b++)
217     for (r = box[RED][0]; r < box[RED][1]; r++)
218     t[g] += histo[r][g][b];
219     med += t[g];
220     }
221     break;
222     case BLU:
223     for (b = box[BLU][0]; b < box[BLU][1]; b++) {
224     t[b] = 0;
225     for (r = box[RED][0]; r < box[RED][1]; r++)
226     for (g = box[GRN][0]; g < box[GRN][1]; g++)
227     t[b] += histo[r][g][b];
228     med += t[b];
229     }
230     break;
231     }
232     if (med < MINSAMP) /* if too sparse, split at midpoint */
233     return(set_branch(pri,(box[pri][0]+box[pri][1])>>1));
234     /* find median position */
235     med >>= 1;
236     for (c0 = box[pri][0]; med > 0; c0++)
237     med -= t[c0];
238     if (c0 > (box[pri][0]+box[pri][1])>>1) /* if past the midpoint */
239     c0--; /* part left of median */
240     return(set_branch(pri,c0));
241     #undef c0
242     }
243    
244    
245     static
246     mktabent(p, box) /* compute average color for box and assign */
247     int p;
248     register int box[3][2];
249     {
250 greg 2.5 unsigned long sum[3];
251 greg 2.7 unsigned r, g;
252     unsigned long n;
253 greg 2.5 register unsigned b, c;
254 greg 2.1 /* sum pixels in box */
255     n = 0;
256     sum[RED] = sum[GRN] = sum[BLU] = 0;
257     for (r = box[RED][0]; r < box[RED][1]; r++)
258     for (g = box[GRN][0]; g < box[GRN][1]; g++)
259     for (b = box[BLU][0]; b < box[BLU][1]; b++) {
260 schorsch 2.16 if ( (c = histo[r][g][b]) ) {
261 greg 2.1 n += c;
262     sum[RED] += (long)c*r;
263     sum[GRN] += (long)c*g;
264     sum[BLU] += (long)c*b;
265     }
266     histo[r][g][b] = p; /* assign pixel */
267     }
268 greg 2.7 if (n >= (1L<<23)/HMAX) { /* avoid overflow */
269 greg 2.5 sum[RED] /= n;
270     sum[GRN] /= n;
271     sum[BLU] /= n;
272     n = 1;
273     }
274 greg 2.1 if (n) { /* compute average */
275     clrtab[p][RED] = sum[RED]*256/NRED/n;
276     clrtab[p][GRN] = sum[GRN]*256/NGRN/n;
277     clrtab[p][BLU] = sum[BLU]*256/NBLU/n;
278     } else { /* empty box -- use midpoint */
279     clrtab[p][RED] = (box[RED][0]+box[RED][1])*256/NRED/2;
280     clrtab[p][GRN] = (box[GRN][0]+box[GRN][1])*256/NGRN/2;
281     clrtab[p][BLU] = (box[BLU][0]+box[BLU][1])*256/NBLU/2;
282     }
283     }
284 greg 2.2
285    
286     #ifdef CLOSEST
287     #define NBSIZ 32
288     static
289     closest(n) /* make sure we have the closest colors */
290     int n;
291     {
292     BYTE *neigh[256];
293     register int r, g, b;
294     #define i r
295     /* get space for neighbor lists */
296     for (i = 0; i < n; i++) {
297     if ((neigh[i] = (BYTE *)malloc(NBSIZ)) == NULL) {
298     while (i--)
299     free(neigh[i]);
300     return; /* ENOMEM -- abandon effort */
301     }
302     neigh[i][0] = i; /* identity is terminator */
303     }
304     /* make neighbor lists */
305 greg 2.3 for (r = 0; r < NRED; r++)
306     for (g = 0; g < NGRN; g++)
307     for (b = 0; b < NBLU; b++) {
308     if (r < NRED-1 && histo[r][g][b] != histo[r+1][g][b])
309 greg 2.2 addneigh(neigh, histo[r][g][b], histo[r+1][g][b]);
310 greg 2.3 if (g < NGRN-1 && histo[r][g][b] != histo[r][g+1][b])
311 greg 2.2 addneigh(neigh, histo[r][g][b], histo[r][g+1][b]);
312 greg 2.3 if (b < NBLU-1 && histo[r][g][b] != histo[r][g][b+1])
313 greg 2.2 addneigh(neigh, histo[r][g][b], histo[r][g][b+1]);
314     }
315     /* assign closest values */
316     for (r = 0; r < NRED; r++)
317     for (g = 0; g < NGRN; g++)
318     for (b = 0; b < NBLU; b++)
319     setclosest(neigh, r, g, b);
320     /* free neighbor lists */
321     for (i = 0; i < n; i++)
322     free(neigh[i]);
323     #undef i
324     }
325    
326    
327     static
328     addneigh(nl, i, j) /* i and j are neighbors; add them to list */
329     register BYTE *nl[];
330     register int i;
331     int j;
332     {
333     int nc;
334     char *nnl;
335     register int t;
336    
337     for (nc = 0; nc < 2; nc++) { /* do both neighbors */
338     for (t = 0; nl[i][t] != i; t++)
339     if (nl[i][t] == j)
340     break; /* in list already */
341     if (nl[i][t] == i) { /* add to list */
342     nl[i][t++] = j;
343     if (t % NBSIZ == 0) { /* enlarge list */
344 greg 2.13 if ((nnl = realloc((void *)nl[i],
345     t+NBSIZ)) == NULL)
346 greg 2.2 t--;
347     else
348     nl[i] = (BYTE *)nnl;
349     }
350     nl[i][t] = i; /* terminator */
351     }
352     t = i; i = j; j = t; /* swap and do it again */
353     }
354     }
355    
356    
357     static unsigned
358     dist(col, r, g, b) /* find distance from clrtab entry to r,g,b */
359     register BYTE col[3];
360     int r, g, b;
361     {
362 greg 2.4 register int tmp;
363 greg 2.2 register unsigned sum;
364    
365     tmp = col[RED]*NRED/256 - r;
366     sum = tmp*tmp;
367     tmp = col[GRN]*NGRN/256 - g;
368     sum += tmp*tmp;
369     tmp = col[BLU]*NBLU/256 - b;
370     sum += tmp*tmp;
371     return(sum);
372     }
373    
374    
375     static
376     setclosest(nl, r, g, b) /* find index closest to color and assign */
377     BYTE *nl[];
378     int r, g, b;
379     {
380     int ident;
381     unsigned min;
382     register unsigned d;
383     register BYTE *p;
384     /* get starting value */
385     min = dist(clrtab[ident=histo[r][g][b]], r, g, b);
386     /* find minimum */
387     for (p = nl[ident]; *p != ident; p++)
388     if ((d = dist(clrtab[*p], r, g, b)) < min) {
389     min = d;
390     histo[r][g][b] = *p;
391     }
392     }
393     #endif