ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/px/pmblur2.c
Revision: 2.8
Committed: Tue Jun 3 21:31:51 2025 UTC (86 minutes, 33 seconds ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 2.7: +2 -4 lines
Log Message:
refactor: More consistent use of global char * progname and fixargv0()

File Contents

# User Rev Content
1 greg 2.1 #ifndef lint
2 greg 2.8 static const char RCSid[] = "$Id: pmblur2.c,v 2.7 2019/11/07 23:20:29 greg Exp $";
3 greg 2.1 #endif
4     /*
5     * pmblur2.c - program to computer better motion blur from ranimove frames.
6     *
7     * Created by Greg Ward on 10/3/12.
8     */
9    
10     #include "copyright.h"
11    
12     #include "standard.h"
13     #include "platform.h"
14     #include "color.h"
15     #include "view.h"
16    
17     #define ZGONE (2.*FHUGE) /* non-existent depth value */
18    
19     const char *hdrspec; /* HDR image specification string */
20     const char *zbfspec; /* depth buffer specification string */
21     const char *mvospec; /* motion vector specification string */
22    
23     RESOLU imres; /* image size and orientation */
24     double pixaspect = 1.; /* pixel aspect ratio */
25    
26     COLOR *imsum; /* blurred image in progress */
27     VIEW vwsum; /* averaged view for blurred image */
28     char imfmt[32] = PICFMT; /* image format */
29    
30     int nsamps; /* number of time samples */
31    
32     COLOR *imbuf; /* accumulation buffer for this time sample */
33     float *zbuf; /* associated depth buffer */
34    
35     COLR *imprev; /* previous loaded image frame */
36     float *zprev; /* loaded depth buffer */
37     double exprev; /* previous image exposure */
38     VIEW vwprev = STDVIEW; /* previous view */
39     int fnprev; /* frame number for previous view */
40    
41     typedef struct {
42     VIEW *vp; /* view pointer */
43     int gotview; /* got view parameters? */
44     double ev; /* exposure value */
45     } IMGHEAD; /* holder for individual header information */
46    
47    
48     /* Process line from picture header */
49     static int
50     headline(char *s, void *p)
51     {
52     IMGHEAD *ip = (IMGHEAD *)p;
53 greg 2.6 char fmt[MAXFMTLEN];
54 greg 2.1
55     if (isview(s)) {
56     ip->gotview += (sscanview(ip->vp, s) > 0);
57     return(1);
58     }
59     if (isexpos(s)) {
60     ip->ev *= exposval(s);
61     return(1);
62     }
63     if (formatval(fmt, s)) {
64     if (globmatch(imfmt, fmt)) {
65     strcpy(imfmt, fmt);
66     return(1);
67     }
68     error(WARNING, "wrong picture format");
69     return(-1);
70     }
71     if (isaspect(s)) {
72     pixaspect = aspectval(s);
73     return(1);
74     }
75     return(0);
76     }
77    
78    
79     /* Load previous frame (allocates arrays on first call) */
80     static void
81     loadprev(int fno)
82     {
83     char *err;
84     IMGHEAD ih;
85     RESOLU rs;
86     char fname[256];
87     FILE *fp;
88     int y, hres;
89     int fd;
90    
91     if (fno == fnprev) /* already loaded? */
92     return;
93     sprintf(fname, hdrspec, fno); /* open picture file */
94     if ((fp = fopen(fname, "r")) == NULL) {
95     sprintf(errmsg, "cannot open picture file \"%s\"", fname);
96     error(SYSTEM, errmsg);
97     }
98     ih.vp = &vwprev;
99     ih.gotview = 0;
100     ih.ev = 1.;
101     if (getheader(fp, headline, &ih) < 0)
102     goto readerr;
103     if (!ih.gotview) {
104     sprintf(errmsg, "missing view in picture \"%s\"", fname);
105     error(USER, errmsg);
106     }
107     if ((err = setview(&vwprev)) != NULL)
108     error(USER, err);
109     exprev = ih.ev;
110     if (!fgetsresolu(&rs, fp))
111     goto readerr;
112 greg 2.3 if (rs.rt != PIXSTANDARD) {
113     sprintf(errmsg, "unsupported orientation in picture \"%s\"", fname);
114     error(USER, errmsg);
115     }
116 greg 2.1 if (!imres.xr) { /* allocate buffers */
117     imres = rs;
118     imsum = (COLOR *)ecalloc(imres.xr*imres.yr, sizeof(COLOR));
119     imbuf = (COLOR *)emalloc(sizeof(COLOR)*imres.xr*imres.yr);
120     zbuf = (float *)emalloc(sizeof(float)*imres.xr*imres.yr);
121     imprev = (COLR *)emalloc(sizeof(COLR)*rs.xr*rs.yr);
122     zprev = (float *)emalloc(sizeof(float)*rs.xr*rs.yr);
123     } else if ((imres.xr != rs.xr) | (imres.yr != rs.yr)) {
124     sprintf(errmsg, "resolution mismatch in picture \"%s\"", fname);
125     error(USER, errmsg);
126     }
127     hres = scanlen(&rs); /* load picture */
128     for (y = 0; y < numscans(&rs); y++)
129     if (freadcolrs(imprev + y*hres, hres, fp) < 0)
130     goto readerr;
131     fclose(fp);
132     sprintf(fname, zbfspec, fno); /* load depth buffer */
133 greg 2.7 if ((fd = open_float_depth(fname, (long)rs.xr*rs.yr)) < 0) {
134 greg 2.1 sprintf(errmsg, "cannot open depth buffer \"%s\"", fname);
135     error(SYSTEM, errmsg);
136     }
137     if (read(fd, zprev, sizeof(float)*rs.xr*rs.yr) != sizeof(float)*rs.xr*rs.yr)
138     goto readerr;
139     close(fd);
140     fnprev = fno;
141     return;
142     readerr:
143     sprintf(errmsg, "error loading file \"%s\"", fname);
144     error(USER, errmsg);
145     }
146    
147    
148     /* Interpolate between two image pixels */
149     /* XXX skipping expensive ray vector calculations for now */
150     static void
151 greg 2.3 interp_pixel(COLOR con, const VIEW *vwn, int xn, int yn, double zval,
152     double pos, int xp, int yp, int interpOK)
153 greg 2.1 {
154     const int hres = scanlen(&imres);
155     RREAL ipos;
156     FVECT wprev, wcoor, rdir;
157     int np, xd, yd, nd;
158     COLOR cpr;
159 greg 2.3 double sf;
160 greg 2.1 /* check if off image */
161     if ((xp < 0) | (xp >= hres))
162     return;
163     if ((yp < 0) | (yp >= numscans(&imres)))
164     return;
165     np = yp*hres + xp; /* get indexed destination */
166     xd = (1.-pos)*xp + pos*xn + .5;
167     yd = (1.-pos)*yp + pos*yn + .5;
168     nd = yd*hres + xd;
169 greg 2.3 /* check depth */
170     if (interpOK)
171     zval = (1.-pos)*zprev[np] + pos*zval;
172 greg 2.1 if (zval >= zbuf[nd])
173     return;
174 greg 2.3 zbuf[nd] = zval; /* assign new depth */
175     copycolor(imbuf[nd], con); /* assign new color */
176     if (!interpOK)
177     return;
178 greg 2.1 scalecolor(imbuf[nd], pos);
179     sf = (1.-pos)/exprev;
180     colr_color(cpr, imprev[np]);
181     scalecolor(cpr, sf);
182     addcolor(imbuf[nd], cpr);
183     }
184    
185    
186     /* Find neighbor with minimum depth from buffer */
187     static int
188     neigh_zmin(const float *zb, int n)
189     {
190     const int hres = scanlen(&imres);
191     const int vc = n / hres;
192     const int hc = n - vc*hres;
193     float zbest = ZGONE;
194     int nbest = 0;
195    
196     if (hc > 0 && zb[n-1] < zbest)
197     zbest = zb[nbest = n-1];
198     if (hc < hres-1 && zb[n+1] < zbest)
199     zbest = zb[nbest = n+1];
200     if (vc > 0 && zb[n-hres] < zbest)
201     zbest = zb[nbest = n-hres];
202     if (vc < numscans(&imres)-1 && zb[n+hres] < zbest)
203     return(n+hres);
204     return(nbest);
205     }
206    
207    
208 greg 2.5 /* Expand foreground pixels to mitigate aliasing/fill errors */
209 greg 2.1 static void
210     fill_missing(void)
211     {
212     int n, m;
213    
214     for (n = imres.xr*imres.yr; n--; )
215 greg 2.5 if (zbuf[n] > 1.25*zbuf[m = neigh_zmin(zbuf,n)])
216 greg 2.1 copycolor(imbuf[n], imbuf[m]);
217     }
218    
219    
220     /* Load a subframe */
221     static void
222     addframe(double fpos)
223     {
224     COLOR backg;
225     char *err;
226     VIEW fvw;
227     RESOLU rs;
228     IMGHEAD ihead;
229     char fname[256];
230     FILE *fpimg;
231     int fdzbf, fdmvo;
232     COLR *iscan;
233     float *zscan;
234     uint16 *mscan;
235     int hres, n, h;
236    
237     loadprev((int)fpos); /* make sure we have previous */
238     fpos -= floor(fpos);
239     if (fpos <= .02) { /* special case */
240     COLOR col;
241     for (n = imres.xr*imres.yr; n--; ) {
242     colr_color(col, imprev[n]);
243     addcolor(imsum[n], col);
244     }
245     return;
246     }
247     /* open input files */
248     sprintf(fname, hdrspec, fnprev+1);
249     if ((fpimg = fopen(fname, "r")) == NULL)
250     goto openerr;
251     fvw = vwprev;
252     ihead.vp = &fvw;
253     ihead.gotview = 0;
254     ihead.ev = 1.;
255     if (getheader(fpimg, headline, &ihead) < 0)
256     goto readerr;
257     if (!ihead.gotview) {
258     sprintf(errmsg, "missing view in picture \"%s\"", fname);
259     error(USER, errmsg);
260     }
261     if ((err = setview(&fvw)) != NULL)
262     error(USER, err);
263     if (!fgetsresolu(&rs, fpimg))
264     goto readerr;
265 greg 2.3 if (rs.rt != PIXSTANDARD) {
266     sprintf(errmsg, "unsupported orientation in picture \"%s\"", fname);
267     error(USER, errmsg);
268     }
269 greg 2.1 if ((rs.xr != imres.xr) | (rs.yr != imres.yr)) {
270     sprintf(errmsg, "resolution mismatch for picture \"%s\"", fname);
271     error(USER, errmsg);
272     }
273     vwsum.type = fvw.type; /* average in view */
274     for (n = 3; n--; ) {
275     vwsum.vp[n] += (1.-fpos)*vwprev.vp[n] + fpos*fvw.vp[n];
276     vwsum.vdir[n] += (1.-fpos)*vwprev.vdir[n] + fpos*fvw.vdir[n];
277     vwsum.vup[n] += (1.-fpos)*vwprev.vdir[n] + fpos*fvw.vdir[n];
278     }
279     vwsum.vdist += (1.-fpos)*vwprev.vdist + fpos*fvw.vdist;
280     vwsum.horiz += (1.-fpos)*vwprev.horiz + fpos*fvw.horiz;
281     vwsum.vert += (1.-fpos)*vwprev.vert + fpos*fvw.vert;
282     vwsum.voff += (1.-fpos)*vwprev.voff + fpos*fvw.voff;
283     vwsum.hoff += (1.-fpos)*vwprev.hoff + fpos*fvw.hoff;
284     vwsum.vfore += (1.-fpos)*vwprev.vfore + fpos*fvw.vfore;
285     vwsum.vaft += (1.-fpos)*vwprev.vaft + fpos*fvw.vaft;
286     sprintf(fname, zbfspec, fnprev+1);
287     if ((fdzbf = open(fname, O_RDONLY)) < 0)
288     goto openerr;
289     sprintf(fname, mvospec, fnprev+1);
290     if ((fdmvo = open(fname, O_RDONLY)) < 0)
291     goto openerr;
292     setcolor(backg, .0, .0, .0); /* clear image & depth buffers */
293     for (n = rs.xr*rs.yr; n--; ) {
294     if (zprev[n] >= .9*FHUGE &&
295     zprev[neigh_zmin(zprev,n)] >= .9*FHUGE)
296     colr_color(backg, imprev[n]);
297     copycolor(imbuf[n], backg);
298     zbuf[n] = ZGONE;
299     }
300     hres = scanlen(&rs); /* process a scanline at a time */
301     iscan = (COLR *)emalloc(sizeof(COLR)*hres);
302     zscan = (float *)emalloc(sizeof(float)*hres);
303     mscan = (uint16 *)emalloc(sizeof(uint16)*3*hres);
304     for (n = 0; n < numscans(&rs); n++) {
305     const double sf = 1./ihead.ev;
306     COLOR cval;
307     if (freadcolrs(iscan, hres, fpimg) < 0)
308     goto readerr;
309     if (read(fdzbf, zscan, sizeof(float)*hres) !=
310     sizeof(float)*hres)
311     goto readerr;
312     if (read(fdmvo, mscan, sizeof(uint16)*3*hres) !=
313     sizeof(uint16)*3*hres)
314     goto readerr;
315     for (h = hres; h--; ) {
316     if (!mscan[3*h])
317     continue; /* unknown motion */
318     colr_color(cval, iscan[h]);
319     scalecolor(cval, sf);
320     interp_pixel(cval, &fvw, h, n, zscan[h], fpos,
321     h + (int)mscan[3*h] - 32768,
322 greg 2.3 n - (int)mscan[3*h+1] + 32768,
323     mscan[3*h+2]);
324 greg 2.1 }
325     }
326     /* fill in missing pixels */
327     fill_missing();
328     /* add in results */
329     for (n = imres.xr*imres.yr; n--; )
330     addcolor(imsum[n], imbuf[n]);
331     /* clean up */
332     free(mscan);
333     free(zscan);
334     free(iscan);
335     close(fdmvo);
336     close(fdzbf);
337     fclose(fpimg);
338     return;
339     openerr:
340     sprintf(errmsg, "cannot open input \"%s\"", fname);
341     error(SYSTEM, errmsg);
342     readerr:
343     error(SYSTEM, "error reading input file");
344     }
345    
346    
347     /* Average and write our image out to the given file */
348     static void
349     write_average(FILE *fp)
350     {
351     const int hres = scanlen(&imres);
352     const double sf = 1./(double)nsamps;
353     const float csf = exprev*sf;
354     int n, h;
355     /* normalize view & image */
356     for (n = 3; n--; ) {
357     vwsum.vp[n] *= sf;
358     vwsum.vdir[n] *= sf;
359     vwsum.vup[n] *= sf;
360     }
361     vwsum.vdist *= sf;
362     vwsum.horiz *= sf;
363     vwsum.vert *= sf;
364     vwsum.voff *= sf;
365     vwsum.hoff *= sf;
366     vwsum.vfore *= sf;
367     vwsum.vaft *= sf;
368     for (n = imres.xr*imres.yr; n--; )
369     scalecolor(imsum[n], csf);
370     /* write it out */
371     fputs(VIEWSTR, fp);
372     fprintview(&vwsum, fp);
373     fputc('\n', fp);
374     if ((pixaspect < .98) | (pixaspect > 1.02))
375     fputaspect(pixaspect, fp);
376     fputexpos(exprev, fp);
377     if (strcmp(imfmt, PICFMT))
378     fputformat(imfmt, fp);
379     fputc('\n', fp); /* end of info. header */
380     fputsresolu(&imres, fp);
381     for (n = 0; n < numscans(&imres); n++)
382     if (fwritescan(imsum + n*hres, hres, fp) < 0)
383     error(SYSTEM, "write error on picture output");
384     }
385    
386     /* Load frame sequence and compute motion blur output */
387     int
388     main(int argc, char *argv[])
389     {
390     double fstart, fend, fstep, fcur;
391    
392 greg 2.8 fixargv0(argv[0]); /* sets global progname */
393 greg 2.1 SET_DEFAULT_BINARY();
394     if (argc != 5)
395     goto userr;
396 greg 2.2 /* get frame range & sampling */
397     switch (sscanf(argv[1], "%lf,%lf/%d", &fstart, &fend, &nsamps)) {
398 greg 2.1 case 1:
399 greg 2.4 fend = fstart;
400 greg 2.2 nsamps = 0;
401 greg 2.1 break;
402     case 2:
403 greg 2.2 nsamps = 0;
404     /* fall through */
405     case 3:
406 greg 2.1 if (fend < fstart)
407     goto userr;
408 greg 2.4 if (fend <= fstart+FTINY)
409     nsamps = 0;
410 greg 2.1 break;
411     default:
412     goto userr;
413     }
414     if (fstart < 1)
415     goto userr;
416 greg 2.2 if (nsamps <= 0)
417     nsamps = (fend - fstart)*17.;
418 greg 2.1 if (nsamps) {
419 greg 2.2 if (nsamps > 100) nsamps = 100;
420 greg 2.1 fstep = (fend - fstart)/nsamps;
421     } else {
422     fstep = 1.;
423     fstart -= .5;
424     nsamps = 1;
425     }
426 greg 2.2 hdrspec = argv[2];
427     zbfspec = argv[3];
428     mvospec = argv[4];
429 greg 2.1 /* load and filter each subframe */
430     for (fcur = fstart + .5*fstep; fcur <= fend; fcur += fstep)
431     addframe(fcur);
432     /* write results to stdout */
433     SET_FILE_BINARY(stdout);
434     newheader("RADIANCE", stdout);
435     printargs(argc, argv, stdout);
436     fputnow(stdout);
437     write_average(stdout);
438     return(fflush(stdout) == EOF);
439     userr:
440 greg 2.4 fprintf(stderr, "Usage: %s f0,f1[/n] HDRspec ZBUFspec MVOspec\n", progname);
441 greg 2.1 return(1);
442     }