ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/px/clrtab.c
Revision: 2.1
Committed: Mon Oct 12 12:58:39 1992 UTC (31 years, 6 months ago) by greg
Content type: text/plain
Branch: MAIN
Log Message:
Initial revision

File Contents

# User Rev Content
1 greg 2.1 /* Copyright (c) 1992 Regents of the University of California */
2    
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    
35    
36     new_histo() /* clear our histogram */
37     {
38     bzero((char *)histo, sizeof(histo));
39     }
40    
41    
42     cnt_pixel(col) /* add pixel to our histogram */
43     register BYTE col[];
44     {
45     cndx(col)++;
46     }
47    
48    
49     cnt_colrs(cs, n) /* add a scanline to our histogram */
50     register COLR *cs;
51     register int n;
52     {
53     while (n-- > 0) {
54     cndx(cs[0])++;
55     cs++;
56     }
57     }
58    
59    
60     new_clrtab(ncolors) /* make new color table using ncolors */
61     int ncolors;
62     {
63     if (ncolors < 1)
64     return(0);
65     if (ncolors > 256)
66     ncolors = 256;
67     /* partition color space */
68     cut(CLRCUBE, 0, ncolors);
69     /* return new color table size */
70     return(ncolors);
71     }
72    
73    
74     int
75     map_pixel(col) /* get pixel for color */
76     register BYTE col[];
77     {
78     return(cndx(col));
79     }
80    
81    
82     map_colrs(bs, cs, n) /* convert a scanline to color index values */
83     register BYTE *bs;
84     register COLR *cs;
85     register int n;
86     {
87     while (n-- > 0) {
88     *bs++ = cndx(cs[0]);
89     cs++;
90     }
91     }
92    
93    
94     dith_colrs(bs, cs, n) /* convert scanline to dithered index values */
95     register BYTE *bs;
96     register COLR *cs;
97     int n;
98     {
99     static short (*cerr)[3];
100     static int N = 0;
101     int err[3], errp[3];
102     register int x, i;
103    
104     if (n != N) { /* get error propogation array */
105     if (N)
106     cerr = (short (*)[3])realloc((char *)cerr,
107     3*n*sizeof(short));
108     else
109     cerr = (short (*)[3])malloc(3*n*sizeof(short));
110     if (cerr == NULL) {
111     N = 0;
112     map_colrs(bs, cs, n);
113     return;
114     }
115     N = n;
116     bzero((char *)cerr, 3*N*sizeof(short));
117     }
118     err[0] = err[1] = err[2] = 0;
119     for (x = 0; x < n; x++) {
120     for (i = 0; i < 3; i++) { /* dither value */
121     errp[i] = err[i];
122     err[i] += cerr[x][i];
123     #ifdef MAXERR
124     if (err[i] > MAXERR) err[i] = MAXERR;
125     else if (err[i] < -MAXERR) err[i] = -MAXERR;
126     #endif
127     err[i] += cs[x][i];
128     if (err[i] < 0) err[i] = 0;
129     else if (err[i] > 255) err[i] = 255;
130     }
131     bs[x] = cndx(err);
132     for (i = 0; i < 3; i++) { /* propagate error */
133     err[i] -= clrtab[bs[x]][i];
134     err[i] /= 3;
135     cerr[x][i] = err[i] + errp[i];
136     }
137     }
138     }
139    
140    
141     static
142     cut(box, c0, c1) /* partition color space */
143     register int box[3][2];
144     int c0, c1;
145     {
146     register int branch;
147     int kb[3][2];
148    
149     if (c1-c0 <= 1) { /* assign pixel */
150     mktabent(c0, box);
151     return;
152     }
153     /* split box */
154     branch = split(box);
155     bcopy((char *)box, (char *)kb, sizeof(kb));
156     /* do left (lesser) branch */
157     kb[prim(branch)][1] = part(branch);
158     cut(kb, c0, (c0+c1)>>1);
159     /* do right branch */
160     kb[prim(branch)][0] = part(branch);
161     kb[prim(branch)][1] = box[prim(branch)][1];
162     cut(kb, (c0+c1)>>1, c1);
163     }
164    
165    
166     static int
167     split(box) /* find median cut for box */
168     register int box[3][2];
169     {
170     #define c0 r
171     register int r, g, b;
172     int pri;
173     int t[HMAX], med;
174     /* find dominant axis */
175     pri = RED;
176     if (box[GRN][1]-box[GRN][0] > box[pri][1]-box[pri][0])
177     pri = GRN;
178     if (box[BLU][1]-box[BLU][0] > box[pri][1]-box[pri][0])
179     pri = BLU;
180     /* sum histogram over box */
181     med = 0;
182     switch (pri) {
183     case RED:
184     for (r = box[RED][0]; r < box[RED][1]; r++) {
185     t[r] = 0;
186     for (g = box[GRN][0]; g < box[GRN][1]; g++)
187     for (b = box[BLU][0]; b < box[BLU][1]; b++)
188     t[r] += histo[r][g][b];
189     med += t[r];
190     }
191     break;
192     case GRN:
193     for (g = box[GRN][0]; g < box[GRN][1]; g++) {
194     t[g] = 0;
195     for (b = box[BLU][0]; b < box[BLU][1]; b++)
196     for (r = box[RED][0]; r < box[RED][1]; r++)
197     t[g] += histo[r][g][b];
198     med += t[g];
199     }
200     break;
201     case BLU:
202     for (b = box[BLU][0]; b < box[BLU][1]; b++) {
203     t[b] = 0;
204     for (r = box[RED][0]; r < box[RED][1]; r++)
205     for (g = box[GRN][0]; g < box[GRN][1]; g++)
206     t[b] += histo[r][g][b];
207     med += t[b];
208     }
209     break;
210     }
211     if (med < MINSAMP) /* if too sparse, split at midpoint */
212     return(set_branch(pri,(box[pri][0]+box[pri][1])>>1));
213     /* find median position */
214     med >>= 1;
215     for (c0 = box[pri][0]; med > 0; c0++)
216     med -= t[c0];
217     if (c0 > (box[pri][0]+box[pri][1])>>1) /* if past the midpoint */
218     c0--; /* part left of median */
219     return(set_branch(pri,c0));
220     #undef c0
221     }
222    
223    
224     static
225     mktabent(p, box) /* compute average color for box and assign */
226     int p;
227     register int box[3][2];
228     {
229     long sum[3];
230     int r, g, n;
231     register int b, c;
232     /* sum pixels in box */
233     n = 0;
234     sum[RED] = sum[GRN] = sum[BLU] = 0;
235     for (r = box[RED][0]; r < box[RED][1]; r++)
236     for (g = box[GRN][0]; g < box[GRN][1]; g++)
237     for (b = box[BLU][0]; b < box[BLU][1]; b++) {
238     if (c = histo[r][g][b]) {
239     n += c;
240     sum[RED] += (long)c*r;
241     sum[GRN] += (long)c*g;
242     sum[BLU] += (long)c*b;
243     }
244     histo[r][g][b] = p; /* assign pixel */
245     }
246     if (n) { /* compute average */
247     clrtab[p][RED] = sum[RED]*256/NRED/n;
248     clrtab[p][GRN] = sum[GRN]*256/NGRN/n;
249     clrtab[p][BLU] = sum[BLU]*256/NBLU/n;
250     } else { /* empty box -- use midpoint */
251     clrtab[p][RED] = (box[RED][0]+box[RED][1])*256/NRED/2;
252     clrtab[p][GRN] = (box[GRN][0]+box[GRN][1])*256/NGRN/2;
253     clrtab[p][BLU] = (box[BLU][0]+box[BLU][1])*256/NBLU/2;
254     }
255     }