ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/colortab.c
Revision: 2.5
Committed: Sat Feb 22 02:07:28 2003 UTC (21 years, 2 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.4: +69 -10 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 * colortab.c - allocate and control dynamic color table.
6 *
7 * We start off with a uniform partition of color space.
8 * As pixels are sent to the frame buffer, a histogram is built.
9 * When a new color table is requested, the histogram is used
10 * to make a pseudo-optimal partition, after which the
11 * histogram is cleared. This algorithm
12 * performs only as well as the next drawing's color
13 * distribution is correlated to the last.
14 *
15 * External symbols declared in drvier.h
16 */
17
18 /* ====================================================================
19 * The Radiance Software License, Version 1.0
20 *
21 * Copyright (c) 1990 - 2002 The Regents of the University of California,
22 * through Lawrence Berkeley National Laboratory. All rights reserved.
23 *
24 * Redistribution and use in source and binary forms, with or without
25 * modification, are permitted provided that the following conditions
26 * are met:
27 *
28 * 1. Redistributions of source code must retain the above copyright
29 * notice, this list of conditions and the following disclaimer.
30 *
31 * 2. Redistributions in binary form must reproduce the above copyright
32 * notice, this list of conditions and the following disclaimer in
33 * the documentation and/or other materials provided with the
34 * distribution.
35 *
36 * 3. The end-user documentation included with the redistribution,
37 * if any, must include the following acknowledgment:
38 * "This product includes Radiance software
39 * (http://radsite.lbl.gov/)
40 * developed by the Lawrence Berkeley National Laboratory
41 * (http://www.lbl.gov/)."
42 * Alternately, this acknowledgment may appear in the software itself,
43 * if and wherever such third-party acknowledgments normally appear.
44 *
45 * 4. The names "Radiance," "Lawrence Berkeley National Laboratory"
46 * and "The Regents of the University of California" must
47 * not be used to endorse or promote products derived from this
48 * software without prior written permission. For written
49 * permission, please contact [email protected].
50 *
51 * 5. Products derived from this software may not be called "Radiance",
52 * nor may "Radiance" appear in their name, without prior written
53 * permission of Lawrence Berkeley National Laboratory.
54 *
55 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
56 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
57 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
58 * DISCLAIMED. IN NO EVENT SHALL Lawrence Berkeley National Laboratory OR
59 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
60 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
61 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
62 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
63 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
64 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
65 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
66 * SUCH DAMAGE.
67 * ====================================================================
68 *
69 * This software consists of voluntary contributions made by many
70 * individuals on behalf of Lawrence Berkeley National Laboratory. For more
71 * information on Lawrence Berkeley National Laboratory, please see
72 * <http://www.lbl.gov/>.
73 */
74
75 #include "standard.h"
76
77 #include "color.h"
78 /* histogram resolution */
79 #define NRED 24
80 #define NGRN 32
81 #define NBLU 16
82 #define HMAX NGRN
83 /* minimum box count for adaptive partition */
84 #define MINSAMP 7
85 /* maximum distance^2 before color reassign */
86 #define MAXDST2 12
87 /* map a color */
88 #define map_col(c,p) clrmap[p][ colval(c,p)<1. ? \
89 (int)(colval(c,p)*256.) : 255 ]
90 /* color partition tree */
91 #define CNODE short
92 #define set_branch(p,c) ((c)<<2|(p))
93 #define set_pval(pv) ((pv)<<2|3)
94 #define is_branch(cn) (((cn)&3)!=3)
95 #define is_pval(cn) (((cn)&3)==3)
96 #define part(cn) ((cn)>>2)
97 #define prim(cn) ((cn)&3)
98 #define pval(cn) ((cn)>>2)
99 /* our color table */
100 static struct tabent {
101 long sum[3]; /* sum of colors using this entry */
102 int n; /* number of colors */
103 BYTE ent[3]; /* current table value */
104 } *clrtab = NULL;
105 /* color cube partition */
106 static CNODE *ctree = NULL;
107 /* our color correction map */
108 static BYTE clrmap[3][256];
109 /* histogram of colors used */
110 static unsigned short histo[NRED][NGRN][NBLU];
111 /* initial color cube boundary */
112 static int CLRCUBE[3][2] = {{0,NRED},{0,NGRN},{0,NBLU}};
113
114 static int split();
115 static void cut();
116
117
118 int
119 new_ctab(ncolors) /* start new color table with max ncolors */
120 int ncolors;
121 {
122 int treesize;
123
124 if (ncolors < 1)
125 return(0);
126 /* free old tables */
127 if (clrtab != NULL)
128 free((void *)clrtab);
129 if (ctree != NULL)
130 free((void *)ctree);
131 /* get new tables */
132 for (treesize = 1; treesize < ncolors; treesize <<= 1)
133 ;
134 treesize <<= 1;
135 clrtab = (struct tabent *)calloc(ncolors, sizeof(struct tabent));
136 ctree = (CNODE *)malloc(treesize*sizeof(CNODE));
137 if (clrtab == NULL || ctree == NULL)
138 return(0);
139 /* partition color space */
140 cut(ctree, 0, CLRCUBE, 0, ncolors);
141 /* clear histogram */
142 bzero((char *)histo, sizeof(histo));
143 /* return number of colors used */
144 return(ncolors);
145 }
146
147
148 int
149 get_pixel(col, set_pixel) /* get pixel for color */
150 COLOR col;
151 void (*set_pixel)();
152 {
153 int r, g, b;
154 int cv[3];
155 register CNODE *tp;
156 register int h;
157 /* map color */
158 r = map_col(col,RED);
159 g = map_col(col,GRN);
160 b = map_col(col,BLU);
161 /* reduce resolution */
162 cv[RED] = (r*NRED)>>8;
163 cv[GRN] = (g*NGRN)>>8;
164 cv[BLU] = (b*NBLU)>>8;
165 /* add to histogram */
166 histo[cv[RED]][cv[GRN]][cv[BLU]]++;
167 /* find pixel in tree */
168 for (tp = ctree, h = 0; is_branch(*tp); h++)
169 if (cv[prim(*tp)] < part(*tp))
170 tp += 1<<h; /* left branch */
171 else
172 tp += 1<<(h+1); /* right branch */
173 h = pval(*tp);
174 /* add to color table */
175 clrtab[h].sum[RED] += r;
176 clrtab[h].sum[GRN] += g;
177 clrtab[h].sum[BLU] += b;
178 clrtab[h].n++;
179 /* recompute average */
180 r = clrtab[h].sum[RED] / clrtab[h].n;
181 g = clrtab[h].sum[GRN] / clrtab[h].n;
182 b = clrtab[h].sum[BLU] / clrtab[h].n;
183 /* check for movement */
184 if (clrtab[h].n == 1 ||
185 (r-clrtab[h].ent[RED])*(r-clrtab[h].ent[RED]) +
186 (g-clrtab[h].ent[GRN])*(g-clrtab[h].ent[GRN]) +
187 (b-clrtab[h].ent[BLU])*(b-clrtab[h].ent[BLU]) > MAXDST2) {
188 clrtab[h].ent[RED] = r;
189 clrtab[h].ent[GRN] = g; /* reassign pixel */
190 clrtab[h].ent[BLU] = b;
191 #ifdef DEBUG
192 sprintf(errmsg, "pixel %d = (%d,%d,%d) (%d refs)\n",
193 h, r, g, b, clrtab[h].n);
194 eputs(errmsg);
195 #endif
196 (*set_pixel)(h, r, g, b);
197 }
198 return(h); /* return pixel value */
199 }
200
201
202 void
203 make_gmap(gam) /* make gamma correction map */
204 double gam;
205 {
206 register int i;
207
208 for (i = 0; i < 256; i++)
209 clrmap[RED][i] =
210 clrmap[GRN][i] =
211 clrmap[BLU][i] = 256.0 * pow((i+0.5)/256.0, 1.0/gam);
212 }
213
214
215 void
216 set_cmap(rmap, gmap, bmap) /* set custom color correction map */
217 BYTE *rmap, *gmap, *bmap;
218 {
219 bcopy((char *)rmap, (char *)clrmap[RED], 256);
220 bcopy((char *)gmap, (char *)clrmap[GRN], 256);
221 bcopy((char *)bmap, (char *)clrmap[BLU], 256);
222 }
223
224
225 void
226 map_color(rgb, col) /* map a color to a byte triplet */
227 BYTE rgb[3];
228 COLOR col;
229 {
230 rgb[RED] = map_col(col,RED);
231 rgb[GRN] = map_col(col,GRN);
232 rgb[BLU] = map_col(col,BLU);
233 }
234
235
236 static void
237 cut(tree, level, box, c0, c1) /* partition color space */
238 register CNODE *tree;
239 int level;
240 register int box[3][2];
241 int c0, c1;
242 {
243 int kb[3][2];
244
245 if (c1-c0 <= 1) { /* assign pixel */
246 *tree = set_pval(c0);
247 return;
248 }
249 /* split box */
250 *tree = split(box);
251 bcopy((char *)box, (char *)kb, sizeof(kb));
252 /* do left (lesser) branch */
253 kb[prim(*tree)][1] = part(*tree);
254 cut(tree+(1<<level), level+1, kb, c0, (c0+c1)>>1);
255 /* do right branch */
256 kb[prim(*tree)][0] = part(*tree);
257 kb[prim(*tree)][1] = box[prim(*tree)][1];
258 cut(tree+(1<<(level+1)), level+1, kb, (c0+c1)>>1, c1);
259 }
260
261
262 static int
263 split(box) /* find median cut for box */
264 register int box[3][2];
265 {
266 #define c0 r
267 register int r, g, b;
268 int pri;
269 long t[HMAX], med;
270 /* find dominant axis */
271 pri = RED;
272 if (box[GRN][1]-box[GRN][0] > box[pri][1]-box[pri][0])
273 pri = GRN;
274 if (box[BLU][1]-box[BLU][0] > box[pri][1]-box[pri][0])
275 pri = BLU;
276 /* sum histogram over box */
277 med = 0;
278 switch (pri) {
279 case RED:
280 for (r = box[RED][0]; r < box[RED][1]; r++) {
281 t[r] = 0;
282 for (g = box[GRN][0]; g < box[GRN][1]; g++)
283 for (b = box[BLU][0]; b < box[BLU][1]; b++)
284 t[r] += histo[r][g][b];
285 med += t[r];
286 }
287 break;
288 case GRN:
289 for (g = box[GRN][0]; g < box[GRN][1]; g++) {
290 t[g] = 0;
291 for (b = box[BLU][0]; b < box[BLU][1]; b++)
292 for (r = box[RED][0]; r < box[RED][1]; r++)
293 t[g] += histo[r][g][b];
294 med += t[g];
295 }
296 break;
297 case BLU:
298 for (b = box[BLU][0]; b < box[BLU][1]; b++) {
299 t[b] = 0;
300 for (r = box[RED][0]; r < box[RED][1]; r++)
301 for (g = box[GRN][0]; g < box[GRN][1]; g++)
302 t[b] += histo[r][g][b];
303 med += t[b];
304 }
305 break;
306 }
307 if (med < MINSAMP) /* if too sparse, split at midpoint */
308 return(set_branch(pri,(box[pri][0]+box[pri][1])>>1));
309 /* find median position */
310 med >>= 1;
311 for (c0 = box[pri][0]; med > 0; c0++)
312 med -= t[c0];
313 if (c0 > (box[pri][0]+box[pri][1])>>1) /* if past the midpoint */
314 c0--; /* part left of median */
315 return(set_branch(pri,c0));
316 #undef c0
317 }