Back to index

radiance  4R0+20100331
pfilt.c
Go to the documentation of this file.
00001 #ifndef lint
00002 static const char RCSid[] = "$Id: pfilt.c,v 2.30 2004/03/29 00:34:23 schorsch Exp $";
00003 #endif
00004 /*
00005  *  pfilt.c - program to post-process picture file.
00006  *
00007  *     9/26/85
00008  *     6/23/93       Added additional buffers for value spreading
00009  */
00010 
00011 #include  "copyright.h"
00012 
00013 #include  <signal.h>
00014 #include  <string.h>
00015 
00016 #include  "platform.h"
00017 #include  "standard.h"
00018 #include  "rtio.h"
00019 #include  "color.h"
00020 #include  "view.h"
00021 #include  "paths.h"
00022 #include  "pfilt.h"
00023 
00024 
00025 #define        FEQ(a,b)     ((a) >= .98*(b) && (a) <= 1.02*(b))
00026 
00027 double  CHECKRAD = 2.0;     /* radius to check for filtering */
00028 
00029 #define  THRESHRAD   5.0    /* maximum sample spread in output */
00030 
00031 COLOR  exposure = WHTCOLOR; /* exposure for the frame */
00032 
00033 double rad = 0.0;           /* output pixel radius for filtering */
00034 
00035 double  thresh = 0.0;              /* maximum contribution for subpixel */
00036 
00037 int  nrows = 0;                    /* number of rows for output */
00038 int  ncols = 0;                    /* number of columns for output */
00039 
00040 double x_c = 1.0;           /* ratio of output x size to input */
00041 double y_r = 1.0;           /* ratio of output y size to input */
00042 
00043 int  singlepass = 0;        /* true means skip first pass */
00044 
00045 int  avghot = 0;            /* true means average in bright spots */
00046 
00047 double hotlvl = 100.0;             /* level considered "hot" */
00048 
00049 int  npts = 0;                     /* (half) number of points for stars */
00050 
00051 double spread = 1e-4;              /* spread for star points */
00052 
00053 char  *tfname = NULL;
00054 
00055 char  template[] = TEMPLATE;
00056 
00057 char  *lampdat = "lamp.tab";       /* lamp data file */
00058 
00059 int  order;                 /* scanline ordering of input */
00060 int  xres, yres;            /* resolution of input */
00061 double inpaspect = 1.0;     /* pixel aspect ratio of input */
00062 int  correctaspect = 0;            /* aspect ratio correction? */
00063 
00064 int  wrongformat = 0;
00065 
00066 VIEW  ourview = STDVIEW;
00067 int  gotview = 0;
00068 int  wrapfilt = 0;          /* wrap filter horizontally? */
00069 
00070 int  estatus = 0;           /* exit status (for non-fatal errors) */
00071 
00072 int  xrad;                  /* x search radius */
00073 int  yrad;                  /* y search radius */
00074 int  xbrad;                 /* x box size */
00075 int  ybrad;                 /* y box size */
00076 
00077 int  barsize;               /* size of input scan bar */
00078 COLOR  **scanin;            /* input scan bar */
00079 COLOR  *scanout;            /* output scan line */
00080 COLOR  **scoutbar;          /* output scan bar (if thresh > 0) */
00081 float  **greybar;           /* grey-averaged input values */
00082 int  obarsize = 0;          /* size of output scan bar */
00083 int  orad = 0;                     /* output window radius */
00084 
00085 char  *progname;
00086 
00087 static gethfunc headline;
00088 static brightfunc_t rgb_bright;
00089 static brightfunc_t xyz_bright;
00090 //static double rgb_bright(COLOR  clr);
00091 //static double xyz_bright(COLOR  clr);
00092 static void copyfile(FILE  *in, FILE  *out);
00093 static void pass1(FILE  *in);
00094 static void pass2(FILE  *in);
00095 static void scan2init(void);
00096 static void scan2sync(int  r);
00097 static void scan2flush(void);
00098 
00099 
00100 int
00101 main(
00102        int  argc,
00103        char  **argv
00104 )
00105 {
00106        FILE  *fin;
00107        float  *lampcolor;
00108        char  *lamptype = NULL;
00109        long  fpos;
00110        double outaspect = 0.0;
00111        double d;
00112        int  i, j;
00113        SET_DEFAULT_BINARY();
00114        SET_FILE_BINARY(stdin);
00115        SET_FILE_BINARY(stdout);
00116        if (signal(SIGINT, quit) == SIG_IGN)
00117               signal(SIGINT, SIG_IGN);
00118 #ifdef SIGHUP
00119        if (signal(SIGHUP, quit) == SIG_IGN)
00120               signal(SIGHUP, SIG_IGN);
00121 #endif
00122        signal(SIGTERM, quit);
00123 #ifdef SIGPIPE
00124        signal(SIGPIPE, quit);
00125 #endif
00126 #ifdef SIGXCPU
00127        signal(SIGXCPU, quit);
00128        signal(SIGXFSZ, quit);
00129 #endif
00130 
00131        progname = argv[0] = fixargv0(argv[0]);
00132 
00133        for (i = 1; i < argc; i++)
00134               if (argv[i][0] == '-')
00135                      switch (argv[i][1]) {
00136                      case 'x':
00137                             i++;
00138                             if (argv[i][0] == '/') {
00139                                    x_c = 1.0/atof(argv[i]+1);
00140                                    ncols = 0;
00141                             } else
00142                                    ncols = atoi(argv[i]);
00143                             break;
00144                      case 'y':
00145                             i++;
00146                             if (argv[i][0] == '/') {
00147                                    y_r = 1.0/atof(argv[i]+1);
00148                                    nrows = 0;
00149                             } else
00150                                    nrows = atoi(argv[i]);
00151                             break;
00152                      case 'c':
00153                             correctaspect = !correctaspect;
00154                             break;
00155                      case 'p':
00156                             i++;
00157                             outaspect = atof(argv[i]);
00158                             break;
00159                      case 'e':
00160                             if (argv[i+1][0] == '+' || argv[i+1][0] == '-')
00161                                    d = pow(2.0, atof(argv[i+1]));
00162                             else
00163                                    d = atof(argv[i+1]);
00164                             if (d < 1e-20 || d > 1e20) {
00165                                    fprintf(stderr,
00166                                           "%s: exposure out of range\n",
00167                                                  argv[0]);
00168                                    quit(1);
00169                             }
00170                             switch (argv[i][2]) {
00171                             case '\0':
00172                                    scalecolor(exposure, d);
00173                                    break;
00174                             case 'r':
00175                                    colval(exposure,RED) *= d;
00176                                    break;
00177                             case 'g':
00178                                    colval(exposure,GRN) *= d;
00179                                    break;
00180                             case 'b':
00181                                    colval(exposure,BLU) *= d;
00182                                    break;
00183                             default:
00184                                    goto badopt;
00185                             }
00186                             i++;
00187                             break;
00188                      case 'f':
00189                             lampdat = argv[++i];
00190                             break;
00191                      case 't':
00192                             lamptype = argv[++i];
00193                             break;
00194                      case '1':
00195                             singlepass = 1;
00196                             break;
00197                      case '2':
00198                             singlepass = 0;
00199                             break;
00200                      case 'n':
00201                             npts = atoi(argv[++i]) / 2;
00202                             break;
00203                      case 's':
00204                             spread = atof(argv[++i]);
00205                             break;
00206                      case 'a':
00207                             avghot = !avghot;
00208                             break;
00209                      case 'h':
00210                             hotlvl = atof(argv[++i]);
00211                             break;
00212                      case 'r':
00213                             rad = atof(argv[++i]);
00214                             break;
00215                      case 'm':
00216                             thresh = atof(argv[++i]);
00217                             if (rad <= FTINY)
00218                                    rad = 0.6;
00219                             break;
00220                      case 'b':
00221                             rad = thresh = 0.0;
00222                             break;
00223                      default:;
00224                      badopt:
00225                             fprintf(stderr, "%s: unknown option: %s\n",
00226                                           progname, argv[i]);
00227                             quit(1);
00228                             break;
00229                      }
00230               else
00231                      break;
00232                                    /* get lamp data (if necessary) */
00233        if (lamptype != NULL) {
00234               if (loadlamps(lampdat) < 0)
00235                      quit(1);
00236               if ((lampcolor = matchlamp(lamptype)) == NULL) {
00237                      fprintf(stderr, "%s: unknown lamp type\n", lamptype);
00238                      quit(1);
00239               }
00240               for (j = 0; j < 3; j++)
00241                      if (lampcolor[j] > 1e-4)
00242                             colval(exposure,j) /= lampcolor[j];
00243               freelamps();
00244        }
00245                                    /* open input file */
00246        if (i == argc) {
00247               if (singlepass)
00248                      fin = stdin;
00249               else {
00250                      tfname = mktemp(template);
00251                      if ((fin = fopen(tfname, "w+")) == NULL) {
00252                             fprintf(stderr, "%s: can't create ", progname);
00253                             fprintf(stderr, "temp file \"%s\"\n", tfname);
00254                             quit(1);
00255                      }
00256                      copyfile(stdin, fin);
00257                      if (fseek(fin, 0L, 0) == -1) {
00258                             fprintf(stderr, "%s: seek fail\n", progname);
00259                             quit(1);
00260                      }
00261               }
00262        } else if (i == argc-1) {
00263               if ((fin = fopen(argv[i], "r")) == NULL) {
00264                      fprintf(stderr, "%s: can't open file \"%s\"\n",
00265                                           progname, argv[i]);
00266                      quit(1);
00267               }
00268        } else {
00269               fprintf(stderr, "%s: bad # file arguments\n", progname);
00270               quit(1);
00271        }
00272                                    /* get header */
00273        getheader(fin, headline, NULL);
00274        if (wrongformat) {
00275               fprintf(stderr, "%s: input must be a Radiance picture\n",
00276                             progname);
00277               quit(1);
00278        }
00279                                    /* add new header info. */
00280        printargs(i, argv, stdout);
00281                                    /* get picture size */
00282        if ((order = fgetresolu(&xres, &yres, fin)) < 0) {
00283               fprintf(stderr, "%s: bad picture size\n", progname);
00284               quit(1);
00285        }
00286        if (!(order & YMAJOR))
00287               inpaspect = 1.0/inpaspect;
00288                                    /* wrap around for cylindrical view? */
00289        wrapfilt = gotview && ourview.type == VT_CYL &&
00290                      ourview.horiz >= 360.-FTINY && order & YMAJOR;
00291                                    /* compute output resolution */
00292        if (ncols <= 0)
00293               ncols = x_c*xres + .5;
00294        if (nrows <= 0)
00295               nrows = y_r*yres + .5;
00296        if (outaspect > .01) {
00297               d = inpaspect * yres/xres / outaspect;
00298               if (d * ncols > nrows)
00299                      ncols = nrows / d;
00300               else
00301                      nrows = ncols * d;
00302        }
00303        x_c = (double)ncols/xres;
00304        y_r = (double)nrows/yres;
00305 
00306        if (singlepass) {           /* skip exposure, etc. */
00307               pass1default();
00308               pass2(fin);
00309               quit(0);
00310        }
00311 
00312        fpos = ftell(fin);          /* save input file position */
00313        
00314        pass1(fin);
00315 
00316        if (fseek(fin, fpos, 0) == -1) {
00317               fprintf(stderr, "%s: seek fail\n", progname);
00318               quit(1);
00319        }
00320        pass2(fin);
00321 
00322        quit(estatus);
00323        return estatus; /* pro forma return */
00324 }
00325 
00326 
00327 static double
00328 rgb_bright(
00329        COLOR  clr
00330 )
00331 {
00332        return(bright(clr));
00333 }
00334 
00335 
00336 static double
00337 xyz_bright(
00338        COLOR  clr
00339 )
00340 {
00341        return(clr[CIEY]);
00342 }
00343 
00344 
00345 brightfunc_t *ourbright = rgb_bright;
00346 
00347 static int
00348 headline(                          /* process line from header */
00349        char   *s,
00350        void   *p
00351 )
00352 {
00353        char  fmt[32];
00354 
00355        fputs(s, stdout);           /* copy to output */
00356        if (isaspect(s))            /* get aspect ratio */
00357               inpaspect *= aspectval(s);
00358        else if (isexpos(s))        /* get exposure */
00359               hotlvl *= exposval(s);
00360        else if (formatval(fmt, s)) {      /* get format */
00361               wrongformat = 0;
00362               if (!strcmp(COLRFMT, fmt))
00363                      ourbright = rgb_bright;
00364               else if (!strcmp(CIEFMT, fmt))
00365                      ourbright = xyz_bright;
00366               else
00367                      wrongformat = !globmatch(PICFMT, fmt);
00368        } else if (isview(s) && sscanview(&ourview, s) > 0)
00369               gotview++;
00370        return(0);
00371 }
00372 
00373 
00374 static void
00375 copyfile(                   /* copy a file */
00376        register FILE  *in,
00377        register FILE  *out
00378 )
00379 {
00380        register int  c;
00381 
00382        while ((c = getc(in)) != EOF)
00383               putc(c, out);
00384 
00385        if (ferror(out)) {
00386               fprintf(stderr, "%s: write error in copyfile\n", progname);
00387               quit(1);
00388        }
00389 }
00390 
00391 
00392 static void
00393 pass1(                      /* first pass of picture file */
00394        FILE  *in
00395 )
00396 {
00397        int  i;
00398        COLOR  *scan;
00399 
00400        pass1init();
00401 
00402        scan = (COLOR *)malloc(xres*sizeof(COLOR));
00403        if (scan == NULL) {
00404               fprintf(stderr, "%s: out of memory\n", progname);
00405               quit(1);
00406        }
00407        for (i = 0; i < yres; i++) {
00408               if (freadscan(scan, xres, in) < 0) {
00409                      nrows = (long)nrows * i / yres;    /* adjust frame */
00410                      if (nrows <= 0) {
00411                             fprintf(stderr, "%s: empty frame\n", progname);
00412                             quit(1);
00413                      }
00414                      fprintf(stderr, "%s: warning - partial frame (%d%%)\n",
00415                                    progname, (int)(100L*i/yres));
00416                      yres = i;
00417                      y_r = (double)nrows/yres;
00418                      estatus++;
00419                      break;
00420               }
00421               pass1scan(scan, i);
00422        }
00423        free((void *)scan);
00424 }
00425 
00426 
00427 static void
00428 pass2(               /* last pass on file, write to stdout */
00429        FILE  *in
00430 )
00431 {
00432        int  yread;
00433        int  ycent, xcent;
00434        int  r, c;
00435        
00436        pass2init();
00437        scan2init();
00438        yread = 0;
00439        for (r = 0; r < nrows; r++) {
00440               ycent = (r+.5)*yres/nrows;
00441               while (yread <= ycent+yrad) {
00442                      if (yread < yres) {
00443                             if (freadscan(scanin[yread%barsize],
00444                                           xres, in) < 0) {
00445                                    fprintf(stderr,
00446                                           "%s: truncated input (y=%d)\n",
00447                                           progname, yres-1-yread);
00448                                    quit(1);
00449                             }
00450                             pass2scan(scanin[yread%barsize], yread);
00451                      }
00452                      yread++;
00453               }
00454               if (obarsize > 0)
00455                      scan2sync(r);
00456               for (c = 0; c < ncols; c++) {
00457                      xcent = (c+.5)*xres/ncols;
00458                      if (thresh > FTINY)
00459                             dothresh(xcent, ycent, c, r);
00460                      else if (rad > FTINY)
00461                             dogauss(scanout[c], xcent, ycent, c, r);
00462                      else
00463                             dobox(scanout[c], xcent, ycent, c, r);
00464               }
00465               if (scanout != NULL && fwritescan(scanout, ncols, stdout) < 0) {
00466                      fprintf(stderr, "%s: write error in pass2\n", progname);
00467                      quit(1);
00468               }
00469        }
00470                                    /* skip leftover input */
00471        while (yread < yres) {
00472               if (freadscan(scanin[0], xres, in) < 0)
00473                      break;
00474               yread++;
00475        }
00476        scan2flush();               /* flush output */
00477 }
00478 
00479 
00480 static void
00481 scan2init(void)                    /* prepare scanline arrays */
00482 {
00483        COLOR  ctmp;
00484        double d;
00485        register int  i;
00486 
00487        xbrad = xres/ncols/2 + 1;
00488        ybrad = yres/nrows/2 + 1;
00489        if (rad > FTINY) {
00490               if (nrows >= yres && ncols >= xres)
00491                      rad *= (y_r + x_c)/2.0;
00492 
00493               if (thresh > FTINY) {
00494                      orad = CHECKRAD*THRESHRAD*rad + 1;
00495                      xrad = orad/x_c + xbrad;
00496                      yrad = orad/y_r + ybrad;
00497                      obarsize = 2*orad + 1;
00498               } else {
00499                      xrad = CHECKRAD*rad/x_c + 1;
00500                      yrad = CHECKRAD*rad/y_r + 1;
00501               }
00502               initmask();          /* initialize filter table */
00503        } else {
00504               xrad = xbrad;
00505               yrad = ybrad;
00506        }
00507        barsize = 2*yrad + 1;
00508        scanin = (COLOR **)malloc(barsize*sizeof(COLOR *));
00509        if (scanin == NULL)
00510               goto memerr;
00511        for (i = 0; i < barsize; i++) {
00512               scanin[i] = (COLOR *)malloc(xres*sizeof(COLOR));
00513               if (scanin[i] == NULL)
00514                      goto memerr;
00515        }
00516        if (obarsize > 0) {
00517               scoutbar = (COLOR **)malloc(obarsize*sizeof(COLOR *));
00518               greybar = (float **)malloc(obarsize*sizeof(float *));
00519               if ((scoutbar == NULL) | (greybar == NULL))
00520                      goto memerr;
00521               for (i = 0; i < obarsize; i++) {
00522                      scoutbar[i] = (COLOR *)malloc(ncols*sizeof(COLOR));
00523                      greybar[i] = (float *)malloc(ncols*sizeof(float));
00524                      if ((scoutbar[i] == NULL) | (greybar[i] == NULL))
00525                             goto memerr;
00526               }
00527        } else {
00528               scanout = (COLOR *)malloc(ncols*sizeof(COLOR));
00529               if (scanout == NULL)
00530                      goto memerr;
00531        }
00532                                    /* record pixel aspect ratio */
00533        if (!correctaspect) {
00534               d = order & YMAJOR ? x_c/y_r : y_r/x_c ;
00535               if (!FEQ(d,1.0))
00536                      fputaspect(d, stdout);
00537        }
00538                                    /* record exposure */
00539        d = (*ourbright)(exposure);
00540        if (!FEQ(d,1.0))
00541               fputexpos(d, stdout);
00542                                    /* record color correction */
00543        copycolor(ctmp, exposure);
00544        scalecolor(ctmp, 1.0/d);
00545        if (!FEQ(colval(ctmp,RED),colval(ctmp,GRN)) ||
00546                      !FEQ(colval(ctmp,GRN),colval(ctmp,BLU)))
00547               fputcolcor(ctmp, stdout);
00548        printf("\n");
00549                                    /* write out resolution */
00550        fputresolu(order, ncols, nrows, stdout);
00551        return;
00552 memerr:
00553        fprintf(stderr, "%s: out of memory\n", progname);
00554        quit(1);
00555 }
00556 
00557 
00558 static void
00559 scan2sync(                  /* synchronize grey averages and output scan */
00560        int  r
00561 )
00562 {
00563        static int  nextrow = 0;
00564        COLOR  ctmp;
00565        int  ybot;
00566        register int  c;
00567                                    /* average input scanlines */
00568        while (nextrow <= r+orad && nextrow < nrows) {
00569               ybot = (nextrow+.5)*yres/nrows;
00570               for (c = 0; c < ncols; c++) {
00571                      dobox(ctmp, (int)((c+.5)*xres/ncols),ybot, c,nextrow);
00572                      greybar[nextrow%obarsize][c] = (*ourbright)(ctmp);
00573               }
00574                                    /* and zero output scanline */
00575               memset((char *)scoutbar[nextrow%obarsize], '\0', ncols*sizeof(COLOR));
00576               nextrow++;
00577        }
00578                                    /* point to top scanline for output */
00579        if (r-orad >= 0)
00580               scanout = scoutbar[(r-orad)%obarsize];
00581        else
00582               scanout = NULL;
00583 }
00584 
00585 
00586 static void
00587 scan2flush(void)                   /* flush output buffer */
00588 {
00589        register int  r;
00590 
00591        for (r = nrows-orad; r < nrows; r++)
00592               if (fwritescan(scoutbar[r%obarsize], ncols, stdout) < 0)
00593                      break;
00594        if (fflush(stdout) < 0) {
00595               fprintf(stderr, "%s: write error at end of pass2\n", progname);
00596               quit(1);
00597        }
00598 }
00599 
00600 
00601 void
00602 quit(code)           /* remove temporary file and exit */
00603 int  code;
00604 {
00605        if (tfname != NULL)
00606               unlink(tfname);
00607        exit(code);
00608 }