ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/px/clrtab.c
Revision: 2.9
Committed: Thu Dec 9 12:04:23 1993 UTC (30 years, 4 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.8: +2 -0 lines
Log Message:
added dith_colrs() reset to new_clrtab() function

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