8211d6d3ea7284cbe0932d126d841c2769ef1ad2
[ctsim.git] / src / if2img.cpp
1 /*****************************************************************************
2 ** FILE IDENTIFICATION
3 **
4 **   Name:          if2img.cpp
5 **   Purpose:       Convert an image file to a viewable image
6 **   Programmer:    Kevin Rosenberg
7 **   Date Started:  April 2000
8 **
9 **  This is part of the CTSim program
10 **  Copyright (C) 1983-2000 Kevin Rosenberg
11 **
12 **  $Id: if2img.cpp,v 1.12 2000/07/09 08:47:41 kevin Exp $
13 **
14 **  This program is free software; you can redistribute it and/or modify
15 **  it under the terms of the GNU General Public License (version 2) as
16 **  published by the Free Software Foundation.
17 **
18 **  This program is distributed in the hope that it will be useful,
19 **  but WITHOUT ANY WARRANTY; without even the implied warranty of
20 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21 **  GNU General Public License for more details.
22 **
23 **  You should have received a copy of the GNU General Public License
24 **  along with this program; if not, write to the Free Software
25 **  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26 ******************************************************************************/
27
28 #include "ct.h"
29
30
31 #if HAVE_PNG
32 void sdf2d_to_png (ImageFile& im, char *outfile, int bitdepth, int nxcell, int nycell, double densmin, double densmax);
33 #endif
34 #if HAVE_GIF
35 void sdf2d_to_gif (ImageFile& im, char *outfile, int nxcell, int nycell, double densmin, double densmax);
36 #endif
37 void sdf2d_to_pgm (ImageFile& im, char *outfile, int nxcell, int nycell, double densmin, double densmax);
38 void sdf2d_to_pgmasc (ImageFile& im, char *outfile, int nxcell, int nycell, double densmin, double densmax);
39
40 enum { O_SCALE, O_MIN, O_MAX, O_AUTO, O_CENTER, O_STATS, O_FORMAT, O_LABELS, 
41        O_HELP, O_VERBOSE, O_VERSION, O_DEBUG };
42
43 static struct option my_options[] =
44 {
45   {"scale", 1, 0, O_SCALE},
46   {"min", 1, 0, O_MIN},
47   {"max", 1, 0, O_MAX},
48   {"auto", 1, 0, O_AUTO},
49   {"center", 1, 0, O_CENTER},
50   {"format", 1, 0, O_FORMAT},
51   {"labels", 0, 0, O_LABELS},
52   {"stats", 0, 0, O_STATS},
53   {"verbose", 0, 0, O_VERBOSE},
54   {"debug", 0, 0, O_DEBUG},
55   {"help", 0, 0, O_HELP},
56   {"version", 0, 0, O_VERSION},
57   {0, 0, 0, 0}
58 };
59
60 enum { O_AUTO_FULL, O_AUTO_STD0_1, O_AUTO_STD0_5, O_AUTO_STD1, O_AUTO_STD2, O_AUTO_STD3 };
61 static const char O_AUTO_FULL_STR[]="full";
62 static const char O_AUTO_STD0_1_STR[]="std0.1";
63 static const char O_AUTO_STD0_5_STR[]="std0.5";
64 static const char O_AUTO_STD1_STR[]="std1";
65 static const char O_AUTO_STD2_STR[]="std2";
66 static const char O_AUTO_STD3_STR[]="std3";
67
68 enum { O_CENTER_MEAN, O_CENTER_MODE };
69 static const char O_CENTER_MEAN_STR[]="mean";
70 static const char O_CENTER_MODE_STR[]="mode";
71
72 enum { O_FORMAT_GIF, O_FORMAT_PNG, O_FORMAT_PNG16, O_FORMAT_PGM, O_FORMAT_PGMASC, O_FORMAT_DISP };
73 static const char O_FORMAT_GIF_STR[]="gif";
74 static const char O_FORMAT_PNG_STR[]="png" ;
75 static const char O_FORMAT_PNG16_STR[]="png16" ;
76 static const char O_FORMAT_PGM_STR[]="pgm";
77 static const char O_FORMAT_PGMASC_STR[]="pgmasc";
78 static const char O_FORMAT_DISP_STR[]="disp";
79
80 void 
81 if2img_usage (const char *program)
82 {
83   cout << "usage: " << fileBasename(program) << " ifname outfile [OPTIONS]" << endl;
84   cout << "Convert IF file to an image file" << endl;
85   cout << endl;
86   cout << "     sdfname    Name of input SDF file" << endl;
87   cout << "     outfile    Name of output file" << endl;
88   cout << "     --format   Output format" << endl;
89   cout << "         pgm    PGM (portable graymap) format (default)" << endl;
90   cout << "         pgmasc PGM (portable graymap) ASCII format" << endl;
91 #ifdef HAVE_PNG
92   cout << "         png    PNG (8-bit) format" << endl;
93   cout << "         png16  PNG (16-bit) format" << endl;
94 #endif
95 #ifdef HAVE_GIF
96   cout << "         gif    GIF format" << endl;
97 #endif
98   cout << "         disp   Display on screen" << endl;
99   cout << "     --center   Center of window" << endl;
100   cout << "         mode   Mode is center of window (default)" << endl;
101   cout << "         mean   Mean is center of window" << endl;
102   cout << "     --auto     Set auto window" << endl;
103   cout << "         full   Use full window (default)" << endl;
104   cout << "         std0.1 Use 0.1 standard deviation about center" << endl;
105   cout << "         std0.5 Use 0.5 standard deviation about center" << endl;
106   cout << "         std1   Use one standard deviation about center" << endl;
107   cout << "         std2   Use two standard deviations about center" << endl;
108   cout << "         std3   Use three standard deviations about center" << endl;
109   cout << "     --scale    Scaling factor for output size" << endl;
110   cout << "     --min      Set minimum intensity" << endl;
111   cout << "     --max      Set maximum intensity" << endl;
112   cout << "     --stats    Print image statistics" << endl;
113   cout << "     --labels   Print image labels" << endl;
114   cout << "     --debug    Set debug mode" << endl;
115   cout << "     --verbose  Set verbose mode" << endl;
116   cout << "     --version  Print version" << endl;
117   cout << "     --help     Print this help message" << endl;
118 }
119
120
121 int 
122 if2img_main (int argc, char *const argv[])
123 {
124   ImageFile* pim = NULL;
125
126   double densmin = HUGE_VAL, densmax = -HUGE_VAL;
127   char *in_file, *out_file;
128   int opt_verbose = 0;
129   int opt_scale = 1;
130   int opt_auto = O_AUTO_FULL;
131   int opt_set_max = 0;
132   int opt_set_min = 0;
133   int opt_stats = 0;
134   int opt_debug = 0;
135   int opt_center = O_CENTER_MODE;
136   int opt_format = O_FORMAT_PGM;
137   int opt_labels = 0;
138
139   while (1)
140     {
141       int c = getopt_long (argc, argv, "", my_options, NULL);
142       char *endptr = NULL;
143       char *endstr;
144       
145       if (c == -1)
146         break;
147       
148       switch (c)
149         {
150         case O_MIN:
151           opt_set_min = 1;
152           densmin = strtod(optarg, &endptr);
153           endstr = optarg + strlen(optarg);
154           if (endptr != endstr)
155             {
156               sys_error (ERR_SEVERE, "Error setting --min to %s", optarg);
157               if2img_usage(argv[0]);
158               return (1);
159             }
160           break;
161         case O_MAX:
162           opt_set_max = 1;
163           densmax = strtod(optarg, &endptr);
164           endstr = optarg + strlen(optarg);
165           if (endptr != endstr)
166             {
167               sys_error (ERR_SEVERE, "Error setting --max to %s", optarg);
168               if2img_usage(argv[0]);
169               return (1);
170             }
171           break;
172         case O_SCALE:
173           opt_scale = strtol(optarg, &endptr, 10);
174           endstr = optarg + strlen(optarg);
175           if (endptr != endstr)
176             {
177               sys_error (ERR_SEVERE, "Error setting --scale to %s", optarg);
178               if2img_usage(argv[0]);
179               return (1);
180             }
181           break;
182         case O_AUTO:
183           if (strcmp(optarg, O_AUTO_FULL_STR) == 0)
184             opt_auto = O_AUTO_FULL;
185           else if (strcmp(optarg, O_AUTO_STD1_STR) == 0)
186             opt_auto = O_AUTO_STD1;
187           else if (strcmp(optarg, O_AUTO_STD0_5_STR) == 0)
188             opt_auto = O_AUTO_STD0_5;
189           else if (strcmp(optarg, O_AUTO_STD0_1_STR) == 0)
190             opt_auto = O_AUTO_STD0_1;
191           else if (strcmp(optarg, O_AUTO_STD2_STR) == 0)
192             opt_auto = O_AUTO_STD2;
193           else if (strcmp(optarg, O_AUTO_STD3_STR) == 0)
194             opt_auto = O_AUTO_STD3;
195           else
196             {
197               sys_error (ERR_SEVERE, "Invalid auto mode %s", optarg);
198               if2img_usage(argv[0]);
199               return (1);
200             }
201                 break;
202         case O_CENTER:
203           if (strcmp(optarg, O_CENTER_MEAN_STR) == 0)
204             opt_center = O_CENTER_MEAN;
205           else if (strcmp(optarg, O_CENTER_MODE_STR) == 0)
206             opt_center = O_CENTER_MODE;
207           else
208             {
209               sys_error (ERR_SEVERE, "Invalid center mode %s", optarg);
210               if2img_usage(argv[0]);
211               return (1);
212             }
213           break;
214         case O_FORMAT:
215           if (strcmp(optarg, O_FORMAT_PGM_STR) == 0)
216             opt_format = O_FORMAT_PGM;
217           else if (strcmp(optarg, O_FORMAT_PGMASC_STR) == 0)
218             opt_format = O_FORMAT_PGMASC;
219 #if HAVE_PNG
220           else if (strcmp(optarg, O_FORMAT_PNG_STR) == 0)
221             opt_format = O_FORMAT_PNG;
222           else if (strcmp(optarg, O_FORMAT_PNG16_STR) == 0)
223             opt_format = O_FORMAT_PNG16;
224 #endif
225 #if HAVE_GIF
226           else if (strcmp(optarg, O_FORMAT_GIF_STR) == 0)
227             opt_format = O_FORMAT_GIF;
228 #endif
229           else if (strcmp(optarg, O_FORMAT_DISP_STR) == 0)
230             opt_format = O_FORMAT_DISP;
231           else {
232               sys_error (ERR_SEVERE, "Invalid format mode %s", optarg);
233               if2img_usage(argv[0]);
234               return (1);
235             }
236           break;
237         case O_LABELS:
238           opt_labels = 1;
239           break;
240         case O_VERBOSE:
241           opt_verbose = 1;
242           break;
243         case O_DEBUG:
244           opt_debug = 1;
245           break;
246         case O_STATS:
247           opt_stats = 1;
248           break;
249         case O_VERSION:
250 #ifdef VERSION
251           cout << "Version " << VERSION;
252 #else
253           cout << "Unknown version number" << endl;
254 #endif
255           return (0);
256         case O_HELP:
257         case '?':
258           if2img_usage(argv[0]);
259           return (0);
260         default:
261           if2img_usage(argv[0]);
262           return (1);
263         }
264     }
265
266   if ((opt_format == O_FORMAT_DISP && optind + 1 != argc) 
267       || (opt_format != O_FORMAT_DISP && optind + 2 != argc))
268     {
269         if2img_usage(argv[0]);
270         return (1);
271     }
272   
273   in_file = argv[optind];
274
275   if (opt_format != O_FORMAT_DISP)
276       out_file = argv[optind+1];
277   else out_file = NULL;
278
279   pim = new ImageFile ();
280   ImageFile& im = *pim;
281   if (! im.fileRead(in_file)) {
282     sys_error (ERR_FATAL, "File %s does not exist", in_file);
283     return (1);
284   }
285
286   if (opt_labels)
287     im.printLabels(cout);
288
289   if (opt_stats || (! (opt_set_max && opt_set_min))) {
290     double minfound = HUGE_VAL, maxfound = -HUGE_VAL;
291     double mode = 0, mean = 0, stddev = 0, window = 0;
292     double spread;
293     int hist[256];
294     int ibin, nbin = 256;
295     int max_bin, max_binindex; 
296     double maxbin;
297     int nx = im.nx();
298     int ny = im.ny();
299     ImageFileArray v = im.getArray();
300     
301     maxbin = nbin - 1;
302     for (int ix = 0; ix < nx; ix++) {
303       for (int iy = 0; iy < ny; iy++) {
304         if (v[ix][iy] > maxfound)
305           maxfound = v[ix][iy];
306         if (v[ix][iy] < minfound)
307           minfound = v[ix][iy];
308         mean += v[ix][iy];
309       }
310     }
311     spread = maxfound - minfound;
312     if (spread == 0)
313       mode = minfound;
314     else {
315       for (ibin = 0; ibin < nbin; ibin++)
316         hist[ibin] = 0;
317       for (int ix = 0; ix < nx; ix++) {
318         for (int iy = 0; iy < ny; iy++) {
319           int b = (int) ((((v[ix][iy] - minfound) / spread) * (double) maxbin) + 0.5);
320           hist[b]++;
321         }
322       }
323       max_binindex = 0;
324       max_bin = -1;
325       for (ibin = 0; ibin < nbin; ibin++) {
326         if (hist[ibin] > max_bin) {
327           max_bin = hist[ibin];
328           max_binindex = ibin;
329         }
330       }
331       mode = (((double) max_binindex) * spread / ((double) maxbin)) + minfound;
332     }
333     
334     if (opt_auto == O_AUTO_FULL) {
335         if (! opt_set_max)
336           densmax = maxfound;
337         if (! opt_set_min)
338           densmin = minfound;
339     }
340     if (opt_stats || opt_auto != O_AUTO_FULL) {
341       mean /= nx * ny;
342       for (int ix = 0; ix < nx; ix++) {
343         for (int iy = 0; iy < ny; iy++) {
344             double diff = (v[ix][iy] - mean);
345             stddev += diff * diff;
346         }
347       }
348       stddev = sqrt(stddev / (nx * ny));
349       if (opt_auto == O_AUTO_FULL)
350         ;
351       else if (opt_auto == O_AUTO_STD1)
352             window = stddev;
353       else if (opt_auto == O_AUTO_STD0_1)
354         window = stddev * 0.1;
355       else if (opt_auto == O_AUTO_STD0_5)
356         window = stddev * 0.5;
357           else if (opt_auto == O_AUTO_STD2)
358             window = stddev * 2;
359       else if (opt_auto == O_AUTO_STD3)
360         window = stddev * 3;
361       else {
362         sys_error (ERR_SEVERE, "Internal Error: Invalid auto mode %d", opt_auto);
363         return (1);
364       }
365     }
366     if (opt_stats) {
367       cout <<"nx: " << nx << endl;
368       cout <<"ny: " << ny << endl;
369       cout <<"min: " << minfound << endl;
370       cout <<"max: " << maxfound << endl;
371       cout <<"mean: " << mean << endl;
372       cout <<"mode: " << mode << endl;
373       cout <<"stddev: " << stddev << endl;
374     }
375     if (opt_auto != O_AUTO_FULL) {
376       double center;
377       
378       if (opt_center == O_CENTER_MODE)
379         center = mode;
380       else if (opt_center == O_CENTER_MEAN)
381         center = mean;
382       else {
383         sys_error (ERR_SEVERE, "Internal Error: Invalid center mode %d", opt_center);
384         return (1);
385       }
386       if (! opt_set_max)
387         densmax = center + window;
388       if (! opt_set_min)
389         densmin = center - window;
390       }
391   }
392   
393   if (opt_stats) {
394     cout << "min display: " << densmin << endl;
395     cout << "max display: " << densmax << endl;
396   }
397   
398   if (opt_format == O_FORMAT_PGM)
399     sdf2d_to_pgm (im, out_file, opt_scale, opt_scale, densmin, densmax);
400   else if (opt_format == O_FORMAT_PGMASC)
401     sdf2d_to_pgmasc (im, out_file, opt_scale, opt_scale, densmin, densmax);
402 #if HAVE_PNG
403   else if (opt_format == O_FORMAT_PNG)
404     sdf2d_to_png (im, out_file, 8, opt_scale, opt_scale, densmin, densmax);
405   else if (opt_format == O_FORMAT_PNG16)
406     sdf2d_to_png (im, out_file, 16, opt_scale, opt_scale, densmin, densmax);
407 #endif
408 #if HAVE_GIF
409   else if (opt_format == O_FORMAT_GIF) 
410     sdf2d_to_gif (im, out_file, opt_scale, opt_scale, densmin, densmax);
411 #endif
412   else if (opt_format == O_FORMAT_DISP) {
413 #if HAVE_SGP
414     im.displayScaling (opt_scale, densmin, densmax);
415     cio_kb_getc();
416     //    sgp2_close(sgp2_get_active_win());
417 #endif
418   }
419   else
420     {
421       sys_error (ERR_SEVERE, "Internal Error: Invalid format mode %d", opt_format);
422       return (1);
423     }
424   return (0);
425 }
426
427
428 void 
429 sdf2d_to_pgm (ImageFile& im, char *outfile, int nxcell, int nycell, double densmin, double densmax)
430 {
431   FILE *fp;
432   int nx = im.nx();
433   int ny = im.ny();
434   ImageFileArray v = im.getArray();
435
436   unsigned char rowp [nx * nxcell];
437
438   if ((fp = fopen (outfile, "wb")) == NULL)
439      return;
440
441   fprintf(fp, "P5\n");
442   fprintf(fp, "%d %d\n", nx, ny);
443   fprintf(fp, "255\n");
444
445   for (int irow = ny - 1; irow >= 0; irow--) {
446     for (int icol = 0; icol < nx; icol++) {
447       int pos = icol * nxcell;
448       double dens = (v[icol][irow] - densmin) / (densmax - densmin);
449       dens = clamp (dens, 0., 1.);
450       for (int p = pos; p < pos + nxcell; p++) {
451         rowp[p] = static_cast<unsigned int> (dens * 255.);
452       }
453     }
454     for (int ir = 0; ir < nycell; ir++) {
455       for (int ic = 0; ic < nx * nxcell; ic++) 
456         fprintf(fp, "%c ", rowp[ic]);
457     }
458   }
459
460   fclose(fp);
461 }
462
463 void 
464 sdf2d_to_pgmasc (ImageFile& im, char *outfile, int nxcell, int nycell, double densmin, double densmax)
465 {
466   FILE *fp;
467   int nx = im.nx();
468   int ny = im.ny();
469   ImageFileArray v = im.getArray();
470
471   unsigned char rowp [nx * nxcell];
472   if (rowp == NULL)
473     return;
474
475   if ((fp = fopen (outfile, "wb")) == NULL)
476      return;
477
478   fprintf(fp, "P2\n");
479   fprintf(fp, "%d %d\n", nx, ny);
480   fprintf(fp, "255\n");
481
482   for (int irow = ny - 1; irow >= 0; irow--) {
483     for (int icol = 0; icol < nx; icol++) {
484       int pos = icol * nxcell;
485       double dens = (v[icol][irow] - densmin) / (densmax - densmin);
486       dens = clamp (dens, 0., 1.);
487       for (int p = pos; p < pos + nxcell; p++) {
488         rowp[p] = static_cast<unsigned int> (dens * 255.);
489       }
490     }
491     for (int ir = 0; ir < nycell; ir++) {
492       for (int ic = 0; ic < nx * nxcell; ic++) 
493         fprintf(fp, "%d ", rowp[ic]);
494       fprintf(fp, "\n");
495     }
496   }
497
498   fclose(fp);
499 }
500
501
502 #ifdef HAVE_PNG
503 void 
504 sdf2d_to_png (ImageFile& im, char *outfile, int bitdepth, int nxcell, int nycell, double densmin, double densmax)
505 {
506   FILE *fp;
507   png_structp png_ptr;
508   png_infop info_ptr;
509   double max_out_level = (1 << bitdepth) - 1;
510   int nx = im.nx();
511   int ny = im.ny();
512   ImageFileArray v = im.getArray();
513
514   unsigned char rowp [nx * nxcell * (bitdepth / 8)];
515
516   if ((fp = fopen (outfile, "wb")) == NULL)
517      return;
518
519   png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
520   if (! png_ptr)
521     return;
522
523   info_ptr = png_create_info_struct(png_ptr);
524   if (! info_ptr) {
525     png_destroy_write_struct(&png_ptr, (png_infopp) NULL);
526     fclose(fp);
527     return;
528   }
529
530   if (setjmp(png_ptr->jmpbuf)) {
531     png_destroy_write_struct(&png_ptr, &info_ptr);
532     fclose(fp);
533     return;
534   }
535
536   png_init_io(png_ptr, fp);
537
538   png_set_IHDR(png_ptr, info_ptr, nx * nxcell, ny * nycell, bitdepth, PNG_COLOR_TYPE_GRAY, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_DEFAULT);
539
540   png_write_info(png_ptr, info_ptr);
541   for (int irow = ny - 1; irow >= 0; irow--) {
542     png_bytep row_pointer = rowp;
543     
544     for (int icol = 0; icol < nx; icol++) {
545       int pos = icol * nxcell;
546       double dens = (v[icol][irow] - densmin) / (densmax - densmin);
547       dens = clamp (dens, 0., 1.);
548       unsigned int outval = static_cast<unsigned int> (dens * max_out_level);
549
550       for (int p = pos; p < pos + nxcell; p++) {
551         if (bitdepth == 8)
552           rowp[p] = outval;
553         else {
554           int rowpos = p * 2;
555           rowp[rowpos] = (outval >> 8) & 0xFF;
556           rowp[rowpos+1] = (outval & 0xFF);
557         }
558       }
559     }
560     for (int ir = 0; ir < nycell; ir++)
561       png_write_rows (png_ptr, &row_pointer, 1);
562   }
563
564   png_write_end(png_ptr, info_ptr);
565   png_destroy_write_struct(&png_ptr, &info_ptr);
566
567   fclose(fp);
568 }
569 #endif
570
571 #ifdef HAVE_GD
572 #include "gd.h"
573 static const int N_GRAYSCALE=256;
574 #endif
575
576 void
577 sdf2d_to_gif (ImageFile& im, char *outfile, int nxcell, int nycell, double densmin, double densmax)
578 {
579 #ifdef HAVE_GD
580   gdImagePtr gif;
581   FILE *out;
582   int gs_indices[N_GRAYSCALE];
583   int nx = im.nx();
584   int ny = im.ny();
585   ImageFileArray v = im.getArray();
586
587   unsigned char rowp [nx * nxcell];
588   if (rowp == NULL)
589     return;
590
591   gif = gdImageCreate(nx * nxcell, ny * nycell);
592   for (int i = 0; i < N_GRAYSCALE; i++)
593     gs_indices[i] = gdImageColorAllocate(gif, i, i, i);
594
595   int lastrow = ny * nycell - 1;
596   for (int irow = 0; irow < ny; irow++) {
597     int rpos = irow * nycell;
598     for (int ir = rpos; ir < rpos + nycell; ir++) {
599       for (int icol = 0; icol < nx; icol++) {
600         int cpos = icol * nxcell;
601         double dens = (v[icol][irow] - densmin) / (densmax - densmin);
602         dens = clamp(dens, 0., 1.);
603         for (int ic = cpos; ic < cpos + nxcell; ic++) {
604           rowp[ic] = (unsigned int) (dens * (double) (N_GRAYSCALE - 1));
605           gdImageSetPixel(gif, ic, lastrow - ir, gs_indices[rowp[ic]]);
606         }
607       }
608     }
609   }
610
611   if ((out = fopen(outfile,"w")) == NULL) {
612     sys_error(ERR_FATAL, "Error opening output file %s for writing", outfile);
613     return (1);
614   }
615   gdImageGif(gif,out);
616   fclose(out);
617   gdImageDestroy(gif);
618 #else
619   cout << "This version does not support GIF" << endl;
620 #endif
621 }
622
623 #ifndef NO_MAIN
624 int 
625 main (int argc, char *const argv[])
626 {
627   int retval = 1;
628
629   try {
630     retval = if2img_main(argc, argv);
631   } catch (exception e) {
632     cerr << "Exception: " << e.what() << endl;
633   } catch (...) {
634     cerr << "Unknown exception" << endl;
635   }
636
637   return (retval);
638 }
639 #endif