ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/px/pf3.c
Revision: 2.17
Committed: Sun Jul 27 22:12:03 2003 UTC (20 years, 9 months ago) by schorsch
Content type: text/plain
Branch: MAIN
Changes since 2.16: +2 -2 lines
Log Message:
Added grouping parens to reduce ambiguity warnings.

File Contents

# User Rev Content
1 greg 1.1 #ifndef lint
2 schorsch 2.17 static const char RCSid[] = "$Id: pf3.c,v 2.16 2003/06/30 14:59:12 schorsch Exp $";
3 greg 1.1 #endif
4     /*
5     * pf3.c - routines for gaussian and box filtering
6     *
7     * 8/13/86
8     */
9    
10 greg 2.7 #include "standard.h"
11 greg 1.1
12 schorsch 2.16 #include <string.h>
13    
14 greg 1.1 #include "color.h"
15    
16 greg 2.14 #define RSCA 1.13 /* square-radius multiplier: sqrt(4/PI) */
17 greg 2.9 #define TEPS 0.2 /* threshold proximity goal */
18 greg 2.10 #define REPS 0.1 /* radius proximity goal */
19 greg 1.1
20 greg 2.7 extern double CHECKRAD; /* radius over which gaussian is summed */
21    
22 greg 1.1 extern double rad; /* output pixel radius for filtering */
23    
24 greg 2.7 extern double thresh; /* maximum contribution for subpixel */
25    
26 greg 1.1 extern int nrows; /* number of rows for output */
27     extern int ncols; /* number of columns for output */
28    
29     extern int xres, yres; /* resolution of input */
30    
31     extern double x_c, y_r; /* conversion factors */
32    
33 greg 2.7 extern int xrad; /* x search radius */
34     extern int yrad; /* y search radius */
35     extern int xbrad; /* x box size */
36     extern int ybrad; /* y box size */
37 greg 1.1
38     extern int barsize; /* size of input scan bar */
39     extern COLOR **scanin; /* input scan bar */
40     extern COLOR *scanout; /* output scan line */
41 greg 2.7 extern COLOR **scoutbar; /* output scan bar (if thresh > 0) */
42     extern float **greybar; /* grey-averaged input values */
43     extern int obarsize; /* size of output scan bar */
44     extern int orad; /* output window radius */
45 greg 1.1
46 greg 2.12 extern int wrapfilt; /* wrap filter horizontally? */
47    
48 greg 1.1 extern char *progname;
49    
50 greg 2.5 float *gausstable; /* gauss lookup table */
51 greg 1.1
52 greg 2.7 float *ringsum; /* sum of ring values */
53     short *ringwt; /* weight (count) of ring values */
54     short *ringndx; /* ring index table */
55     float *warr; /* array of pixel weights */
56    
57 greg 2.12 extern double (*ourbright)(); /* brightness computation function */
58    
59 greg 2.7 double pickfilt();
60    
61 greg 2.6 #define lookgauss(x) gausstable[(int)(10.*(x)+.5)]
62 greg 1.1
63    
64     initmask() /* initialize gaussian lookup table */
65     {
66 greg 2.7 int gtabsiz;
67     double gaussN;
68 greg 2.5 double d;
69 greg 1.1 register int x;
70    
71 greg 2.15 gtabsiz = 111*CHECKRAD*CHECKRAD;
72 greg 2.7 gausstable = (float *)malloc(gtabsiz*sizeof(float));
73     if (gausstable == NULL)
74     goto memerr;
75     d = x_c*y_r*0.25/(rad*rad);
76 greg 2.14 gausstable[0] = exp(-d);
77 greg 2.7 for (x = 1; x < gtabsiz; x++)
78 greg 2.14 if (x*0.1 <= d)
79 greg 2.5 gausstable[x] = gausstable[0];
80 greg 2.14 else
81     gausstable[x] = exp(-x*0.1);
82 greg 2.7 if (obarsize == 0)
83     return;
84     /* compute integral of filter */
85 greg 2.14 gaussN = PI*d*exp(-d); /* plateau */
86     for (d = sqrt(d)+0.05; d <= RSCA*CHECKRAD; d += 0.1)
87     gaussN += 0.1*2.0*PI*d*exp(-d*d);
88 greg 2.7 /* normalize filter */
89     gaussN = x_c*y_r/(rad*rad*gaussN);
90     for (x = 0; x < gtabsiz; x++)
91     gausstable[x] *= gaussN;
92     /* create ring averages table */
93     ringndx = (short *)malloc((2*orad*orad+1)*sizeof(short));
94     if (ringndx == NULL)
95     goto memerr;
96     for (x = 2*orad*orad+1; --x > orad*orad; )
97     ringndx[x] = -1;
98     do
99 greg 2.8 ringndx[x] = sqrt((double)x);
100 greg 2.7 while (x--);
101     ringsum = (float *)malloc((orad+1)*sizeof(float));
102     ringwt = (short *)malloc((orad+1)*sizeof(short));
103     warr = (float *)malloc(obarsize*obarsize*sizeof(float));
104 schorsch 2.17 if ((ringsum == NULL) | (ringwt == 0) | (warr == NULL))
105 greg 2.7 goto memerr;
106     return;
107     memerr:
108     fprintf(stderr, "%s: out of memory in initmask\n", progname);
109     quit(1);
110 greg 1.1 }
111    
112    
113     dobox(csum, xcent, ycent, c, r) /* simple box filter */
114     COLOR csum;
115     int xcent, ycent;
116     int c, r;
117     {
118 greg 2.6 int wsum;
119     double d;
120     int y;
121 greg 2.12 register int x, offs;
122 greg 2.2 register COLOR *scan;
123 greg 2.7
124 greg 1.1 wsum = 0;
125     setcolor(csum, 0.0, 0.0, 0.0);
126 greg 2.7 for (y = ycent+1-ybrad; y <= ycent+ybrad; y++) {
127 greg 2.4 if (y < 0) continue;
128     if (y >= yres) break;
129 greg 2.13 d = y_r < 1.0 ? y_r*y - (r+.5) : (double)(y - ycent);
130 greg 2.7 if (d < -0.5) continue;
131     if (d >= 0.5) break;
132 greg 1.1 scan = scanin[y%barsize];
133 greg 2.7 for (x = xcent+1-xbrad; x <= xcent+xbrad; x++) {
134 greg 2.12 offs = x < 0 ? xres : x >= xres ? -xres : 0;
135     if (offs && !wrapfilt)
136     continue;
137 greg 2.13 d = x_c < 1.0 ? x_c*x - (c+.5) : (double)(x - xcent);
138 greg 2.7 if (d < -0.5) continue;
139     if (d >= 0.5) break;
140 greg 1.1 wsum++;
141 greg 2.12 addcolor(csum, scan[x+offs]);
142 greg 1.1 }
143     }
144 greg 2.14 if (wsum > 1) {
145     d = 1.0/wsum;
146     scalecolor(csum, d);
147     }
148 greg 1.1 }
149    
150    
151     dogauss(csum, xcent, ycent, c, r) /* gaussian filter */
152     COLOR csum;
153     int xcent, ycent;
154     int c, r;
155     {
156 greg 2.6 double dy, dx, weight, wsum;
157     COLOR ctmp;
158     int y;
159 greg 2.12 register int x, offs;
160 greg 2.2 register COLOR *scan;
161 greg 1.1
162     wsum = FTINY;
163     setcolor(csum, 0.0, 0.0, 0.0);
164 greg 1.2 for (y = ycent-yrad; y <= ycent+yrad; y++) {
165 greg 2.4 if (y < 0) continue;
166     if (y >= yres) break;
167 greg 1.2 dy = (y_r*(y+.5) - (r+.5))/rad;
168 greg 1.1 scan = scanin[y%barsize];
169 greg 1.2 for (x = xcent-xrad; x <= xcent+xrad; x++) {
170 greg 2.12 offs = x < 0 ? xres : x >= xres ? -xres : 0;
171     if (offs && !wrapfilt)
172     continue;
173 greg 1.2 dx = (x_c*(x+.5) - (c+.5))/rad;
174 greg 2.6 weight = lookgauss(dx*dx + dy*dy);
175 greg 1.1 wsum += weight;
176 greg 2.12 copycolor(ctmp, scan[x+offs]);
177 greg 1.1 scalecolor(ctmp, weight);
178     addcolor(csum, ctmp);
179     }
180     }
181 greg 2.14 weight = 1.0/wsum;
182     scalecolor(csum, weight);
183 greg 2.7 }
184    
185    
186     dothresh(xcent, ycent, ccent, rcent) /* gaussian threshold filter */
187     int xcent, ycent;
188     int ccent, rcent;
189     {
190     double d;
191 greg 2.12 int r, y, offs;
192 greg 2.7 register int c, x;
193     register float *gscan;
194     /* compute ring sums */
195 schorsch 2.16 memset((char *)ringsum, '\0', (orad+1)*sizeof(float));
196     memset((char *)ringwt, '\0', (orad+1)*sizeof(short));
197 greg 2.7 for (r = -orad; r <= orad; r++) {
198     if (rcent+r < 0) continue;
199 greg 2.8 if (rcent+r >= nrows) break;
200 greg 2.7 gscan = greybar[(rcent+r)%obarsize];
201     for (c = -orad; c <= orad; c++) {
202 greg 2.12 offs = ccent+c < 0 ? ncols :
203     ccent+c >= ncols ? -ncols : 0;
204     if (offs && !wrapfilt)
205     continue;
206 greg 2.7 x = ringndx[c*c + r*r];
207     if (x < 0) continue;
208 greg 2.12 ringsum[x] += gscan[ccent+c+offs];
209 greg 2.7 ringwt[x]++;
210     }
211     }
212     /* filter each subpixel */
213     for (y = ycent+1-ybrad; y <= ycent+ybrad; y++) {
214     if (y < 0) continue;
215     if (y >= yres) break;
216 greg 2.13 d = y_r < 1.0 ? y_r*y - (rcent+.5) : (double)(y - ycent);
217 greg 2.7 if (d < -0.5) continue;
218     if (d >= 0.5) break;
219     for (x = xcent+1-xbrad; x <= xcent+xbrad; x++) {
220 greg 2.12 offs = x < 0 ? xres : x >= xres ? -xres : 0;
221     if (offs && !wrapfilt)
222     continue;
223 greg 2.13 d = x_c < 1.0 ? x_c*x - (ccent+.5) : (double)(x - xcent);
224 greg 2.7 if (d < -0.5) continue;
225     if (d >= 0.5) break;
226 greg 2.12 sumans(x, y, rcent, ccent,
227     pickfilt((*ourbright)(scanin[y%barsize][x+offs])));
228 greg 2.7 }
229     }
230     }
231    
232    
233     double
234     pickfilt(p0) /* find filter multiplier for p0 */
235     double p0;
236     {
237     double m = 1.0;
238 greg 2.10 double t, num, denom, avg, wsum;
239     double mlimit[2];
240 greg 2.14 int ilimit = 4.0/TEPS;
241 greg 2.7 register int i;
242     /* iterative search for m */
243 greg 2.11 mlimit[0] = 1.0; mlimit[1] = orad/rad/CHECKRAD;
244 greg 2.7 do {
245     /* compute grey weighted average */
246 greg 2.14 i = RSCA*CHECKRAD*rad*m + .5;
247 greg 2.8 if (i > orad) i = orad;
248 greg 2.7 avg = wsum = 0.0;
249     while (i--) {
250 greg 2.8 t = (i+.5)/(m*rad);
251 greg 2.7 t = lookgauss(t*t);
252     avg += t*ringsum[i];
253     wsum += t*ringwt[i];
254     }
255 greg 2.10 if (avg < 1e-20) /* zero inclusive average */
256     return(1.0);
257 greg 2.7 avg /= wsum;
258     /* check threshold */
259 greg 2.10 denom = m*m/gausstable[0] - p0/avg;
260 greg 2.11 if (denom <= FTINY) { /* zero exclusive average */
261     if (m >= mlimit[1]-REPS)
262     break;
263     m = mlimit[1];
264     continue;
265     }
266 greg 2.10 num = p0/avg - 1.0;
267     if (num < 0.0) num = -num;
268     t = num/denom;
269     if (t <= thresh) {
270     if (m <= mlimit[0]+REPS || (thresh-t)/thresh <= TEPS)
271     break;
272     } else {
273     if (m >= mlimit[1]-REPS || (t-thresh)/thresh <= TEPS)
274     break;
275     }
276     t = m; /* remember current m */
277 greg 2.7 /* next guesstimate */
278 greg 2.10 m = sqrt(gausstable[0]*(num/thresh + p0/avg));
279     if (m < t) { /* bound it */
280     if (m <= mlimit[0]+FTINY)
281     m = 0.5*(mlimit[0] + t);
282     mlimit[1] = t;
283     } else {
284     if (m >= mlimit[1]-FTINY)
285     m = 0.5*(mlimit[1] + t);
286     mlimit[0] = t;
287     }
288 greg 2.7 } while (--ilimit > 0);
289     return(m);
290     }
291    
292    
293     sumans(px, py, rcent, ccent, m) /* sum input pixel to output */
294     int px, py;
295     int rcent, ccent;
296     double m;
297     {
298 greg 2.14 double dy2, dx;
299 greg 2.7 COLOR pval, ctmp;
300 greg 2.12 int ksiz, r, offs;
301 greg 2.7 double pc, pr, norm;
302     register int i, c;
303     register COLOR *scan;
304 greg 2.12 /*
305     * This normalization method fails at the picture borders because
306     * a different number of input pixels contribute there.
307     */
308     scan = scanin[py%barsize] + (px < 0 ? xres : px >= xres ? -xres : 0);
309     copycolor(pval, scan[px]);
310 greg 2.7 pc = x_c*(px+.5);
311     pr = y_r*(py+.5);
312     ksiz = CHECKRAD*m*rad + 1;
313     if (ksiz > orad) ksiz = orad;
314     /* compute normalization */
315     norm = 0.0;
316     i = 0;
317     for (r = rcent-ksiz; r <= rcent+ksiz; r++) {
318     if (r < 0) continue;
319     if (r >= nrows) break;
320 greg 2.14 dy2 = (pr - (r+.5))/(m*rad);
321     dy2 *= dy2;
322 greg 2.7 for (c = ccent-ksiz; c <= ccent+ksiz; c++) {
323 greg 2.12 if (!wrapfilt) {
324     if (c < 0) continue;
325     if (c >= ncols) break;
326     }
327 greg 2.7 dx = (pc - (c+.5))/(m*rad);
328 greg 2.14 norm += warr[i++] = lookgauss(dx*dx + dy2);
329 greg 2.7 }
330     }
331     norm = 1.0/norm;
332     if (x_c < 1.0) norm *= x_c;
333     if (y_r < 1.0) norm *= y_r;
334     /* sum pixels */
335     i = 0;
336     for (r = rcent-ksiz; r <= rcent+ksiz; r++) {
337     if (r < 0) continue;
338     if (r >= nrows) break;
339     scan = scoutbar[r%obarsize];
340     for (c = ccent-ksiz; c <= ccent+ksiz; c++) {
341 greg 2.12 offs = c < 0 ? ncols : c >= ncols ? -ncols : 0;
342     if (offs && !wrapfilt)
343     continue;
344 greg 2.7 copycolor(ctmp, pval);
345     dx = norm*warr[i++];
346     scalecolor(ctmp, dx);
347 greg 2.12 addcolor(scan[c+offs], ctmp);
348 greg 2.7 }
349     }
350 greg 1.1 }