ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/colortab.c
Revision: 2.6
Committed: Tue Feb 25 02:47:22 2003 UTC (21 years, 2 months ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: rad3R5
Changes since 2.5: +1 -56 lines
Log Message:
Replaced inline copyright notice with #include "copyright.h"

File Contents

# User Rev Content
1 greg 1.1 #ifndef lint
2 greg 2.5 static const char RCSid[] = "$Id$";
3 greg 1.1 #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 greg 2.5 *
15     * External symbols declared in drvier.h
16     */
17    
18 greg 2.6 #include "copyright.h"
19 greg 1.1
20 greg 1.15 #include "standard.h"
21    
22 greg 1.1 #include "color.h"
23     /* histogram resolution */
24 greg 1.3 #define NRED 24
25 greg 1.1 #define NGRN 32
26 greg 1.3 #define NBLU 16
27 greg 1.1 #define HMAX NGRN
28     /* minimum box count for adaptive partition */
29     #define MINSAMP 7
30 greg 1.3 /* maximum distance^2 before color reassign */
31 greg 1.5 #define MAXDST2 12
32 greg 1.1 /* map a color */
33 greg 1.4 #define map_col(c,p) clrmap[p][ colval(c,p)<1. ? \
34     (int)(colval(c,p)*256.) : 255 ]
35 greg 1.1 /* color partition tree */
36     #define CNODE short
37 greg 2.2 #define set_branch(p,c) ((c)<<2|(p))
38 greg 1.1 #define set_pval(pv) ((pv)<<2|3)
39 greg 1.7 #define is_branch(cn) (((cn)&3)!=3)
40 greg 1.1 #define is_pval(cn) (((cn)&3)==3)
41     #define part(cn) ((cn)>>2)
42     #define prim(cn) ((cn)&3)
43     #define pval(cn) ((cn)>>2)
44     /* our color table */
45 greg 1.6 static struct tabent {
46 greg 1.3 long sum[3]; /* sum of colors using this entry */
47 greg 1.15 int n; /* number of colors */
48     BYTE ent[3]; /* current table value */
49 greg 1.8 } *clrtab = NULL;
50     /* color cube partition */
51     static CNODE *ctree = NULL;
52 greg 1.1 /* our color correction map */
53 greg 1.4 static BYTE clrmap[3][256];
54 greg 1.1 /* histogram of colors used */
55 greg 1.9 static unsigned short histo[NRED][NGRN][NBLU];
56 greg 1.8 /* initial color cube boundary */
57 greg 2.3 static int CLRCUBE[3][2] = {{0,NRED},{0,NGRN},{0,NBLU}};
58    
59 greg 2.5 static int split();
60     static void cut();
61 greg 1.1
62    
63 greg 1.3 int
64 greg 1.4 new_ctab(ncolors) /* start new color table with max ncolors */
65 greg 1.1 int ncolors;
66     {
67 greg 1.8 int treesize;
68    
69 greg 1.6 if (ncolors < 1)
70 greg 1.3 return(0);
71 greg 1.8 /* free old tables */
72     if (clrtab != NULL)
73 greg 2.5 free((void *)clrtab);
74 greg 1.8 if (ctree != NULL)
75 greg 2.5 free((void *)ctree);
76 greg 1.8 /* get new tables */
77     for (treesize = 1; treesize < ncolors; treesize <<= 1)
78     ;
79     treesize <<= 1;
80     clrtab = (struct tabent *)calloc(ncolors, sizeof(struct tabent));
81     ctree = (CNODE *)malloc(treesize*sizeof(CNODE));
82     if (clrtab == NULL || ctree == NULL)
83     return(0);
84 greg 1.3 /* partition color space */
85 greg 1.7 cut(ctree, 0, CLRCUBE, 0, ncolors);
86 greg 1.1 /* clear histogram */
87 greg 1.11 bzero((char *)histo, sizeof(histo));
88 greg 1.3 /* return number of colors used */
89     return(ncolors);
90 greg 1.1 }
91    
92    
93     int
94 greg 1.4 get_pixel(col, set_pixel) /* get pixel for color */
95 greg 1.1 COLOR col;
96 greg 2.5 void (*set_pixel)();
97 greg 1.1 {
98 greg 1.3 int r, g, b;
99 greg 1.1 int cv[3];
100 greg 1.10 register CNODE *tp;
101 greg 1.1 register int h;
102 greg 1.3 /* map color */
103     r = map_col(col,RED);
104     g = map_col(col,GRN);
105     b = map_col(col,BLU);
106     /* reduce resolution */
107     cv[RED] = (r*NRED)>>8;
108     cv[GRN] = (g*NGRN)>>8;
109     cv[BLU] = (b*NBLU)>>8;
110     /* add to histogram */
111 greg 1.1 histo[cv[RED]][cv[GRN]][cv[BLU]]++;
112 greg 1.3 /* find pixel in tree */
113 greg 1.10 for (tp = ctree, h = 0; is_branch(*tp); h++)
114     if (cv[prim(*tp)] < part(*tp))
115     tp += 1<<h; /* left branch */
116 greg 1.1 else
117 greg 1.15 tp += 1<<(h+1); /* right branch */
118 greg 1.10 h = pval(*tp);
119 greg 1.3 /* add to color table */
120 greg 1.10 clrtab[h].sum[RED] += r;
121     clrtab[h].sum[GRN] += g;
122     clrtab[h].sum[BLU] += b;
123     clrtab[h].n++;
124 greg 1.3 /* recompute average */
125 greg 1.10 r = clrtab[h].sum[RED] / clrtab[h].n;
126     g = clrtab[h].sum[GRN] / clrtab[h].n;
127     b = clrtab[h].sum[BLU] / clrtab[h].n;
128 greg 1.3 /* check for movement */
129 greg 1.10 if (clrtab[h].n == 1 ||
130     (r-clrtab[h].ent[RED])*(r-clrtab[h].ent[RED]) +
131     (g-clrtab[h].ent[GRN])*(g-clrtab[h].ent[GRN]) +
132     (b-clrtab[h].ent[BLU])*(b-clrtab[h].ent[BLU]) > MAXDST2) {
133     clrtab[h].ent[RED] = r;
134 greg 2.2 clrtab[h].ent[GRN] = g; /* reassign pixel */
135 greg 1.10 clrtab[h].ent[BLU] = b;
136 greg 1.12 #ifdef DEBUG
137     sprintf(errmsg, "pixel %d = (%d,%d,%d) (%d refs)\n",
138 greg 1.10 h, r, g, b, clrtab[h].n);
139 greg 1.12 eputs(errmsg);
140 greg 1.1 #endif
141 greg 1.3 (*set_pixel)(h, r, g, b);
142     }
143     return(h); /* return pixel value */
144 greg 1.1 }
145    
146    
147 greg 2.5 void
148 greg 1.4 make_gmap(gam) /* make gamma correction map */
149 greg 2.2 double gam;
150 greg 1.1 {
151     register int i;
152    
153 greg 1.4 for (i = 0; i < 256; i++)
154     clrmap[RED][i] =
155     clrmap[GRN][i] =
156 greg 1.15 clrmap[BLU][i] = 256.0 * pow((i+0.5)/256.0, 1.0/gam);
157 greg 1.4 }
158    
159    
160 greg 2.5 void
161 greg 1.4 set_cmap(rmap, gmap, bmap) /* set custom color correction map */
162     BYTE *rmap, *gmap, *bmap;
163     {
164 greg 1.11 bcopy((char *)rmap, (char *)clrmap[RED], 256);
165     bcopy((char *)gmap, (char *)clrmap[GRN], 256);
166     bcopy((char *)bmap, (char *)clrmap[BLU], 256);
167 greg 1.1 }
168    
169    
170 greg 2.5 void
171 greg 1.13 map_color(rgb, col) /* map a color to a byte triplet */
172     BYTE rgb[3];
173     COLOR col;
174     {
175     rgb[RED] = map_col(col,RED);
176     rgb[GRN] = map_col(col,GRN);
177     rgb[BLU] = map_col(col,BLU);
178     }
179    
180    
181 greg 2.5 static void
182 greg 1.7 cut(tree, level, box, c0, c1) /* partition color space */
183 greg 1.1 register CNODE *tree;
184 greg 1.7 int level;
185 greg 1.1 register int box[3][2];
186     int c0, c1;
187     {
188     int kb[3][2];
189    
190 greg 1.3 if (c1-c0 <= 1) { /* assign pixel */
191 greg 1.1 *tree = set_pval(c0);
192     return;
193     }
194     /* split box */
195     *tree = split(box);
196 greg 1.11 bcopy((char *)box, (char *)kb, sizeof(kb));
197 greg 1.3 /* do left (lesser) branch */
198 greg 1.1 kb[prim(*tree)][1] = part(*tree);
199 greg 1.7 cut(tree+(1<<level), level+1, kb, c0, (c0+c1)>>1);
200 greg 1.3 /* do right branch */
201 greg 1.1 kb[prim(*tree)][0] = part(*tree);
202     kb[prim(*tree)][1] = box[prim(*tree)][1];
203 greg 1.7 cut(tree+(1<<(level+1)), level+1, kb, (c0+c1)>>1, c1);
204 greg 1.1 }
205    
206    
207     static int
208     split(box) /* find median cut for box */
209     register int box[3][2];
210     {
211     #define c0 r
212     register int r, g, b;
213     int pri;
214 greg 2.4 long t[HMAX], med;
215 greg 1.1 /* find dominant axis */
216     pri = RED;
217     if (box[GRN][1]-box[GRN][0] > box[pri][1]-box[pri][0])
218     pri = GRN;
219     if (box[BLU][1]-box[BLU][0] > box[pri][1]-box[pri][0])
220     pri = BLU;
221     /* sum histogram over box */
222     med = 0;
223     switch (pri) {
224     case RED:
225     for (r = box[RED][0]; r < box[RED][1]; r++) {
226     t[r] = 0;
227     for (g = box[GRN][0]; g < box[GRN][1]; g++)
228     for (b = box[BLU][0]; b < box[BLU][1]; b++)
229     t[r] += histo[r][g][b];
230     med += t[r];
231     }
232     break;
233     case GRN:
234     for (g = box[GRN][0]; g < box[GRN][1]; g++) {
235     t[g] = 0;
236     for (b = box[BLU][0]; b < box[BLU][1]; b++)
237     for (r = box[RED][0]; r < box[RED][1]; r++)
238     t[g] += histo[r][g][b];
239     med += t[g];
240     }
241     break;
242     case BLU:
243     for (b = box[BLU][0]; b < box[BLU][1]; b++) {
244     t[b] = 0;
245     for (r = box[RED][0]; r < box[RED][1]; r++)
246     for (g = box[GRN][0]; g < box[GRN][1]; g++)
247     t[b] += histo[r][g][b];
248     med += t[b];
249     }
250     break;
251     }
252     if (med < MINSAMP) /* if too sparse, split at midpoint */
253     return(set_branch(pri,(box[pri][0]+box[pri][1])>>1));
254     /* find median position */
255     med >>= 1;
256     for (c0 = box[pri][0]; med > 0; c0++)
257     med -= t[c0];
258     if (c0 > (box[pri][0]+box[pri][1])>>1) /* if past the midpoint */
259     c0--; /* part left of median */
260     return(set_branch(pri,c0));
261     #undef c0
262     }