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

# Content
1 /* Copyright (c) 1993 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 extern 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 /* define CLOSEST to get closest colors */
35 #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
43 static cut(), mktabent(), closest(), addneigh(), setclosest();
44 static int split();
45 static unsigned dist();
46
47
48 new_histo(n) /* clear our histogram */
49 int n;
50 {
51 bzero((char *)histo, sizeof(histo));
52 return(0);
53 }
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 #ifdef CLOSEST
84 closest(ncolors); /* ensure colors picked are closest */
85 #endif
86 /* reset dithering function */
87 dith_colrs((BYTE *)NULL, (COLR *)NULL, 0);
88 /* 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 static short (*cerr)[3] = NULL;
119 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 if (N) {
125 free((char *)cerr);
126 cerr = NULL;
127 }
128 if (n)
129 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 long t[HMAX], med;
194 /* 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 unsigned long sum[3];
250 unsigned r, g;
251 unsigned long n;
252 register unsigned b, c;
253 /* 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 if (n >= (1L<<23)/HMAX) { /* avoid overflow */
268 sum[RED] /= n;
269 sum[GRN] /= n;
270 sum[BLU] /= n;
271 n = 1;
272 }
273 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
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 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 addneigh(neigh, histo[r][g][b], histo[r+1][g][b]);
309 if (g < NGRN-1 && histo[r][g][b] != histo[r][g+1][b])
310 addneigh(neigh, histo[r][g][b], histo[r][g+1][b]);
311 if (b < NBLU-1 && histo[r][g][b] != histo[r][g][b+1])
312 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 register int tmp;
361 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