ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/px/clrtab.c
Revision: 2.15
Committed: Mon Jun 30 14:59:12 2003 UTC (20 years, 10 months ago) by schorsch
Content type: text/plain
Branch: MAIN
Changes since 2.14: +9 -5 lines
Log Message:
Replaced most outdated BSD function calls with their posix equivalents, and cleaned up a few other platform dependencies.

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: clrtab.c,v 2.14 2003/05/13 17:58:33 greg Exp $";
3 #endif
4 /*
5 * Simple median-cut color quantization based on colortab.c
6 */
7
8 #include "copyright.h"
9
10 #include <string.h>
11
12 #include "standard.h"
13 #include "color.h"
14
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 extern BYTE clrtab[256][3];
28 /* 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 /* define CLOSEST to get closest colors */
36 #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
44 static cut(), mktabent(), closest(), addneigh(), setclosest();
45 static int split();
46 static unsigned dist();
47
48
49 new_histo(n) /* clear our histogram */
50 int n;
51 {
52 memset((void *)histo, '\0', sizeof(histo));
53 return(0);
54 }
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 #ifdef CLOSEST
85 closest(ncolors); /* ensure colors picked are closest */
86 #endif
87 /* reset dithering function */
88 dith_colrs((BYTE *)NULL, (COLR *)NULL, 0);
89 /* 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 static short (*cerr)[3] = NULL;
120 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 if (N) {
126 free((void *)cerr);
127 cerr = NULL;
128 }
129 if (n)
130 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 memset((void *)cerr, '\0', 3*N*sizeof(short));
138 }
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 memcpy((void *)kb, (void *)box, sizeof(kb));
177 /* 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 long t[HMAX], med;
195 /* 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 unsigned long sum[3];
251 unsigned r, g;
252 unsigned long n;
253 register unsigned b, c;
254 /* 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 if (c = histo[r][g][b]) {
261 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 if (n >= (1L<<23)/HMAX) { /* avoid overflow */
269 sum[RED] /= n;
270 sum[GRN] /= n;
271 sum[BLU] /= n;
272 n = 1;
273 }
274 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
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 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 addneigh(neigh, histo[r][g][b], histo[r+1][g][b]);
310 if (g < NGRN-1 && histo[r][g][b] != histo[r][g+1][b])
311 addneigh(neigh, histo[r][g][b], histo[r][g+1][b]);
312 if (b < NBLU-1 && histo[r][g][b] != histo[r][g][b+1])
313 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 if ((nnl = realloc((void *)nl[i],
345 t+NBSIZ)) == NULL)
346 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 register int tmp;
363 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