ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/colortab.c
Revision: 1.15
Committed: Wed Nov 7 17:16:58 1990 UTC (33 years, 5 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 1.14: +6 -6 lines
Log Message:
minor fixes to gamma correction

File Contents

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