ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/px/pf3.c
Revision: 2.20
Committed: Thu Dec 7 21:15:54 2023 UTC (5 months, 3 weeks ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.19: +1 -6 lines
Log Message:
refactor: Cleaned up and simplified #include's

File Contents

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