ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/px/clrtab.c
Revision: 2.11
Committed: Mon Dec 12 12:15:51 1994 UTC (29 years, 4 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.10: +4 -0 lines
Log Message:
added static function definitions

File Contents

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