ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/px/pmblur2.c
Revision: 2.1
Committed: Fri Oct 5 00:59:38 2012 UTC (11 years, 6 months ago) by greg
Content type: text/plain
Branch: MAIN
Log Message:
Created pmblur2 command to compute better motion blur from ranimove runs

File Contents

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