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

# Content
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 }