ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/colortab.c
Revision: 1.3
Committed: Tue Oct 3 11:10:10 1989 UTC (34 years, 7 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 1.2: +75 -50 lines
Log Message:
Improved color table allocation, second cut.

File Contents

# Content
1 /* Copyright (c) 1989 Regents of the University of California */
2
3 #ifndef lint
4 static char SCCSid[] = "$SunId$ LBL";
5 #endif
6
7 /*
8 * colortab.c - allocate and control dynamic color table.
9 *
10 * We start off with a uniform partition of color space.
11 * As pixels are sent to the frame buffer, a histogram is built.
12 * When a new color table is requested, the histogram is used
13 * to make a pseudo-optimal partition, after which the
14 * histogram is cleared. This algorithm
15 * performs only as well as the next drawing's color
16 * distribution is correlated to the last.
17 */
18
19 #include "color.h"
20
21 #define NULL 0
22 /* histogram resolution */
23 #define NRED 24
24 #define NGRN 32
25 #define NBLU 16
26 #define HMAX NGRN
27 /* minimum box count for adaptive partition */
28 #define MINSAMP 7
29 /* maximum distance^2 before color reassign */
30 #define MAXDST2 5
31 /* maximum frame buffer depth */
32 #define FBDEPTH 8
33 /* color map resolution */
34 #define MAPSIZ 256
35 /* map a color */
36 #define map_col(c,p) clrmap[ colval(c,p)<1. ? \
37 (int)(colval(c,p)*MAPSIZ) : MAPSIZ-1 ]
38 /* color partition tree */
39 #define CNODE short
40 #define set_branch(p,c) ((c)<<2|(p))
41 #define set_pval(pv) ((pv)<<2|3)
42 #define is_pval(cn) (((cn)&3)==3)
43 #define part(cn) ((cn)>>2)
44 #define prim(cn) ((cn)&3)
45 #define pval(cn) ((cn)>>2)
46 /* our color table */
47 struct tabent {
48 long sum[3]; /* sum of colors using this entry */
49 long n; /* number of colors */
50 short ent[3]; /* current table value */
51 } clrtab[1<<FBDEPTH];
52 /* our color correction map */
53 static BYTE clrmap[MAPSIZ];
54 /* histogram of colors used */
55 static unsigned histo[NRED][NGRN][NBLU];
56 /* initial color cube boundaries */
57 static int CLRCUBE[3][2] = {0,NRED,0,NGRN,0,NBLU};
58 /* color cube partition */
59 static CNODE ctree[1<<(FBDEPTH+1)];
60 /* callback for pixel assignment */
61 static int (*set_pixel)();
62
63
64 int
65 new_ctab(ncolors, cset) /* start new color table with max ncolors */
66 int ncolors;
67 int (*cset)();
68 {
69 if (ncolors < 1 || ncolors > 1<<FBDEPTH || cset == NULL)
70 return(0);
71 /* assign pixel callback routine */
72 set_pixel = cset;
73 /* clear color table */
74 bzero(clrtab, sizeof(clrtab));
75 /* partition color space */
76 cut(ctree, FBDEPTH, CLRCUBE, 0, ncolors);
77 /* clear histogram */
78 bzero(histo, sizeof(histo));
79 /* return number of colors used */
80 return(ncolors);
81 }
82
83
84 int
85 get_pixel(col) /* get pixel for color */
86 COLOR col;
87 {
88 int r, g, b;
89 int cv[3];
90 register union { CNODE *t; struct tabent *e; } p;
91 register int h;
92 /* map color */
93 r = map_col(col,RED);
94 g = map_col(col,GRN);
95 b = map_col(col,BLU);
96 /* reduce resolution */
97 cv[RED] = (r*NRED)>>8;
98 cv[GRN] = (g*NGRN)>>8;
99 cv[BLU] = (b*NBLU)>>8;
100 /* add to histogram */
101 histo[cv[RED]][cv[GRN]][cv[BLU]]++;
102 /* find pixel in tree */
103 p.t = ctree;
104 for (h = FBDEPTH; h > 0; h--) {
105 if (is_pval(*p.t))
106 break;
107 if (cv[prim(*p.t)] < part(*p.t))
108 p.t++; /* left branch */
109 else
110 p.t += 1<<h; /* right branch */
111 }
112 h = pval(*p.t);
113 /* add to color table */
114 p.e = clrtab + h;
115 /* add to sum */
116 p.e->sum[RED] += r;
117 p.e->sum[GRN] += g;
118 p.e->sum[BLU] += b;
119 p.e->n++;
120 /* recompute average */
121 r = p.e->sum[RED] / p.e->n;
122 g = p.e->sum[GRN] / p.e->n;
123 b = p.e->sum[BLU] / p.e->n;
124 /* check for movement */
125 if (p.e->n == 1 ||
126 (r-p.e->ent[RED])*(r-p.e->ent[RED]) +
127 (g-p.e->ent[GRN])*(g-p.e->ent[GRN]) +
128 (b-p.e->ent[BLU])*(b-p.e->ent[BLU]) > MAXDST2) {
129 p.e->ent[RED] = r;
130 p.e->ent[GRN] = g; /* reassign pixel */
131 p.e->ent[BLU] = b;
132 #ifdef notdef
133 printf("pixel %d = (%d,%d,%d) (%d refs)\n",
134 h, r, g, b, p.e->n);
135 #endif
136 (*set_pixel)(h, r, g, b);
137 }
138 return(h); /* return pixel value */
139 }
140
141
142 make_cmap(gam) /* make gamma correction map */
143 double gam;
144 {
145 extern double pow();
146 register int i;
147
148 for (i = 0; i < MAPSIZ; i++)
149 clrmap[i] = 256.0 * pow(i/(double)MAPSIZ, 1.0/gam);
150 }
151
152
153 static
154 cut(tree, height, box, c0, c1) /* partition color space */
155 register CNODE *tree;
156 int height;
157 register int box[3][2];
158 int c0, c1;
159 {
160 int kb[3][2];
161
162 if (c1-c0 <= 1) { /* assign pixel */
163 *tree = set_pval(c0);
164 return;
165 }
166 /* split box */
167 *tree = split(box);
168 bcopy(box, kb, sizeof(kb));
169 /* do left (lesser) branch */
170 kb[prim(*tree)][1] = part(*tree);
171 cut(tree+1, height-1, kb, c0, (c0+c1)>>1);
172 /* do right branch */
173 kb[prim(*tree)][0] = part(*tree);
174 kb[prim(*tree)][1] = box[prim(*tree)][1];
175 cut(tree+(1<<height), height-1, kb, (c0+c1)>>1, c1);
176 }
177
178
179 static int
180 split(box) /* find median cut for box */
181 register int box[3][2];
182 {
183 #define c0 r
184 register int r, g, b;
185 int pri;
186 int t[HMAX], med;
187 /* find dominant axis */
188 pri = RED;
189 if (box[GRN][1]-box[GRN][0] > box[pri][1]-box[pri][0])
190 pri = GRN;
191 if (box[BLU][1]-box[BLU][0] > box[pri][1]-box[pri][0])
192 pri = BLU;
193 /* sum histogram over box */
194 med = 0;
195 switch (pri) {
196 case RED:
197 for (r = box[RED][0]; r < box[RED][1]; r++) {
198 t[r] = 0;
199 for (g = box[GRN][0]; g < box[GRN][1]; g++)
200 for (b = box[BLU][0]; b < box[BLU][1]; b++)
201 t[r] += histo[r][g][b];
202 med += t[r];
203 }
204 break;
205 case GRN:
206 for (g = box[GRN][0]; g < box[GRN][1]; g++) {
207 t[g] = 0;
208 for (b = box[BLU][0]; b < box[BLU][1]; b++)
209 for (r = box[RED][0]; r < box[RED][1]; r++)
210 t[g] += histo[r][g][b];
211 med += t[g];
212 }
213 break;
214 case BLU:
215 for (b = box[BLU][0]; b < box[BLU][1]; b++) {
216 t[b] = 0;
217 for (r = box[RED][0]; r < box[RED][1]; r++)
218 for (g = box[GRN][0]; g < box[GRN][1]; g++)
219 t[b] += histo[r][g][b];
220 med += t[b];
221 }
222 break;
223 }
224 if (med < MINSAMP) /* if too sparse, split at midpoint */
225 return(set_branch(pri,(box[pri][0]+box[pri][1])>>1));
226 /* find median position */
227 med >>= 1;
228 for (c0 = box[pri][0]; med > 0; c0++)
229 med -= t[c0];
230 if (c0 > (box[pri][0]+box[pri][1])>>1) /* if past the midpoint */
231 c0--; /* part left of median */
232 return(set_branch(pri,c0));
233 #undef c0
234 }