ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/px/clrtab.c
Revision: 2.12
Committed: Sat Feb 22 02:07:27 2003 UTC (21 years, 2 months ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: rad3R5
Changes since 2.11: +2 -5 lines
Log Message:
Changes and check-in for 3.5 release
Includes new source files and modifications not recorded for many years
See ray/doc/notes/ReleaseNotes for notes between 3.1 and 3.5 release

File Contents

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