ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/px/pf3.c
Revision: 2.22
Committed: Thu Dec 14 18:53:58 2023 UTC (4 months, 2 weeks ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 2.21: +6 -6 lines
Log Message:
perf(pfilt): minor optimizations

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: pf3.c,v 2.21 2023/12/08 17:56:26 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 SCOLOR 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 COLORV *scan, *scp;
93
94 wsum = 0;
95 scolorblack(csum);
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 != 0) & !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 scp = scan + (x+offs)*NCSAMP;
112 saddscolor(csum, scp);
113 }
114 }
115 if (wsum > 1) {
116 d = 1.0/wsum;
117 scalescolor(csum, d);
118 }
119 }
120
121
122 void
123 dogauss( /* gaussian filter */
124 SCOLOR csum,
125 int xcent,
126 int ycent,
127 int c,
128 int r
129 )
130 {
131 double dy, dx, weight, wsum;
132 SCOLOR ctmp;
133 int y;
134 int x, offs;
135 COLORV *scan;
136
137 wsum = FTINY;
138 scolorblack(csum);
139 for (y = ycent-yrad; y <= ycent+yrad; y++) {
140 if (y < 0) continue;
141 if (y >= yres) break;
142 dy = (y_r*(y+.5) - (r+.5))/rad;
143 scan = scanin[y%barsize];
144 for (x = xcent-xrad; x <= xcent+xrad; x++) {
145 offs = x < 0 ? xres : x >= xres ? -xres : 0;
146 if ((offs != 0) & !wrapfilt)
147 continue;
148 dx = (x_c*(x+.5) - (c+.5))/rad;
149 weight = lookgauss(dx*dx + dy*dy);
150 wsum += weight;
151 copyscolor(ctmp, scan+(x+offs)*NCSAMP);
152 scalescolor(ctmp, weight);
153 saddscolor(csum, ctmp);
154 }
155 }
156 weight = 1.0/wsum;
157 scalescolor(csum, weight);
158 }
159
160
161 void
162 dothresh( /* gaussian threshold filter */
163 int xcent,
164 int ycent,
165 int ccent,
166 int rcent
167 )
168 {
169 double d;
170 int r, y, offs;
171 int c, x;
172 float *gscan;
173 /* compute ring sums */
174 memset((char *)ringsum, '\0', (orad+1)*sizeof(float));
175 memset((char *)ringwt, '\0', (orad+1)*sizeof(short));
176 for (r = -orad; r <= orad; r++) {
177 if (rcent+r < 0) continue;
178 if (rcent+r >= nrows) break;
179 gscan = greybar[(rcent+r)%obarsize];
180 for (c = -orad; c <= orad; c++) {
181 offs = ccent+c < 0 ? ncols :
182 ccent+c >= ncols ? -ncols : 0;
183 if ((offs != 0) & !wrapfilt)
184 continue;
185 x = ringndx[c*c + r*r];
186 if (x < 0) continue;
187 ringsum[x] += gscan[ccent+c+offs];
188 ringwt[x]++;
189 }
190 }
191 /* filter each subpixel */
192 for (y = ycent+1-ybrad; y <= ycent+ybrad; y++) {
193 if (y < 0) continue;
194 if (y >= yres) break;
195 d = y_r < 1.0 ? y_r*y - (rcent+.5) : (double)(y - ycent);
196 if (d < -0.5) continue;
197 if (d >= 0.5) break;
198 for (x = xcent+1-xbrad; x <= xcent+xbrad; x++) {
199 offs = x < 0 ? xres : x >= xres ? -xres : 0;
200 if ((offs != 0) & !wrapfilt)
201 continue;
202 d = x_c < 1.0 ? x_c*x - (ccent+.5) : (double)(x - xcent);
203 if (d < -0.5) continue;
204 if (d >= 0.5) break;
205 sumans(x, y, rcent, ccent,
206 pickfilt((*ourbright)(scanin[y%barsize]+(x+offs)*NCSAMP)));
207 }
208 }
209 }
210
211
212 static double
213 pickfilt( /* find filter multiplier for p0 */
214 double p0
215 )
216 {
217 double m = 1.0;
218 double t, num, denom, avg, wsum;
219 double mlimit[2];
220 int ilimit = 4.0/TEPS;
221 int i;
222 /* iterative search for m */
223 mlimit[0] = 1.0; mlimit[1] = orad/rad/CHECKRAD;
224 do {
225 /* compute grey weighted average */
226 i = RSCA*CHECKRAD*rad*m + .5;
227 if (i > orad) i = orad;
228 avg = wsum = 0.0;
229 while (i--) {
230 t = (i+.5)/(m*rad);
231 t = lookgauss(t*t);
232 avg += t*ringsum[i];
233 wsum += t*ringwt[i];
234 }
235 if (avg < 1e-20) /* zero inclusive average */
236 return(1.0);
237 avg /= wsum;
238 /* check threshold */
239 denom = m*m/gausstable[0] - p0/avg;
240 if (denom <= FTINY) { /* zero exclusive average */
241 if (m >= mlimit[1]-REPS)
242 break;
243 m = mlimit[1];
244 continue;
245 }
246 num = p0/avg - 1.0;
247 if (num < 0.0) num = -num;
248 t = num/denom;
249 if (t <= thresh) {
250 if (m <= mlimit[0]+REPS || (thresh-t)/thresh <= TEPS)
251 break;
252 } else {
253 if (m >= mlimit[1]-REPS || (t-thresh)/thresh <= TEPS)
254 break;
255 }
256 t = m; /* remember current m */
257 /* next guesstimate */
258 m = sqrt(gausstable[0]*(num/thresh + p0/avg));
259 if (m < t) { /* bound it */
260 if (m <= mlimit[0]+FTINY)
261 m = 0.5*(mlimit[0] + t);
262 mlimit[1] = t;
263 } else {
264 if (m >= mlimit[1]-FTINY)
265 m = 0.5*(mlimit[1] + t);
266 mlimit[0] = t;
267 }
268 } while (--ilimit > 0);
269 return(m);
270 }
271
272
273 static void
274 sumans( /* sum input pixel to output */
275 int px,
276 int py,
277 int rcent,
278 int ccent,
279 double m
280 )
281 {
282 double dy2, dx;
283 SCOLOR pval, ctmp;
284 int ksiz, r, offs;
285 double pc, pr, norm;
286 int i, c;
287 COLORV *scan, *scp;
288 /*
289 * This normalization method fails at the picture borders because
290 * a different number of input pixels contribute there.
291 */
292 scan = scanin[py%barsize] + (px < 0 ? xres : px >= xres ? -xres : 0)*NCSAMP;
293 copyscolor(pval, scan+px*NCSAMP);
294 pc = x_c*(px+.5);
295 pr = y_r*(py+.5);
296 ksiz = CHECKRAD*m*rad + 1;
297 if (ksiz > orad) ksiz = orad;
298 /* compute normalization */
299 norm = 0.0;
300 i = 0;
301 for (r = rcent-ksiz; r <= rcent+ksiz; r++) {
302 if (r < 0) continue;
303 if (r >= nrows) break;
304 dy2 = (pr - (r+.5))/(m*rad);
305 dy2 *= dy2;
306 for (c = ccent-ksiz; c <= ccent+ksiz; c++) {
307 if (!wrapfilt) {
308 if (c < 0) continue;
309 if (c >= ncols) break;
310 }
311 dx = (pc - (c+.5))/(m*rad);
312 norm += warr[i++] = lookgauss(dx*dx + dy2);
313 }
314 }
315 norm = 1.0/norm;
316 if (x_c < 1.0) norm *= x_c;
317 if (y_r < 1.0) norm *= y_r;
318 /* sum pixels */
319 i = 0;
320 for (r = rcent-ksiz; r <= rcent+ksiz; r++) {
321 if (r < 0) continue;
322 if (r >= nrows) break;
323 scan = scoutbar[r%obarsize];
324 for (c = ccent-ksiz; c <= ccent+ksiz; c++) {
325 offs = c < 0 ? ncols : c >= ncols ? -ncols : 0;
326 if ((offs != 0) & !wrapfilt)
327 continue;
328 copyscolor(ctmp, pval);
329 dx = norm*warr[i++];
330 scalescolor(ctmp, dx);
331 scp = scan + (c+offs)*NCSAMP;
332 saddscolor(scp, ctmp);
333 }
334 }
335 }