ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/px/clrtab.c
Revision: 2.8
Committed: Thu Dec 9 11:57:15 1993 UTC (30 years, 4 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.7: +6 -5 lines
Log Message:
changed dith_colrs() so it can be reset by dith_colrs(NULL, NULL, 0)

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