main.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662
  1. /***************************************************************************
  2. atcorr - atmospheric correction for Grass GIS
  3. was
  4. 6s - Second Simulation of Satellite Signal in the Solar Spectrum.
  5. -------------------
  6. begin : Fri Jan 10 2003
  7. copyright : (C) 2003 by Christo Zietsman
  8. email : 13422863@sun.ac.za
  9. This program has been rewriten in C/C++ from the fortran source found
  10. on http://www.ltid.inpe.br/dsr/mauro/6s/index.html. This code is
  11. provided as is, with no implied warranty and under the conditions
  12. and restraint as placed on it by previous authors.
  13. atcorr is an atmospheric correction module for Grass GIS. Limited testing
  14. has been done and therefore it should not be assumed that it will work
  15. for all possible inputs.
  16. Care has been taken to test new functionality brought to the module by
  17. Grass such as the command-line options and flags. The extra feature of
  18. supplying an elevation map has not been run to completion, because it
  19. takes to long and no sensible data for the test data was at hand.
  20. Testing would be welcomed. :)
  21. **********
  22. * Code clean-up and port to GRASS 6.3, 15.12.2006:
  23. Yann Chemin, ychemin(at)gmail.com
  24. * Addition of IRS-1C LISS, Feb 2009: Markus Neteler
  25. TODO: use dynamic allocation for TiCache
  26. ***************************************************************************/
  27. #include <cstdlib>
  28. #include <map>
  29. extern "C" {
  30. #include <grass/gis.h>
  31. #include <grass/raster.h>
  32. #include <grass/glocale.h>
  33. }
  34. #include "Transform.h"
  35. #include "6s.h"
  36. /* Input options and flags */
  37. struct Options
  38. {
  39. /* options */
  40. struct Option *iimg; /* input satellite image */
  41. struct Option *iscl; /* input data is scaled to this range */
  42. struct Option *ialt; /* an input elevation map in km used to increase */
  43. /* atmospheric correction accuracy, including this */
  44. /* will make computations take much, much longer */
  45. struct Option *ivis; /* an input visibility map in km (same purpose and effect as ialt) */
  46. struct Option *icnd; /* the input conditions file */
  47. struct Option *oimg; /* output image name */
  48. struct Option *oscl; /* scale the output data (reflectance values) to this range */
  49. /* flags */
  50. struct Flag *oflt; /* output data as floating point and do not round */
  51. struct Flag *irad; /* treat input values as reflectance instead of radiance values */
  52. struct Flag *etmafter; /* treat input data as a satelite image of type etm+ taken after July 1, 2000 */
  53. struct Flag *etmbefore; /* treat input data as a satelite image of type etm+ taken before July 1, 2000 */
  54. struct Flag *optimize;
  55. };
  56. struct ScaleRange
  57. {
  58. int min;
  59. int max;
  60. };
  61. int hit = 0;
  62. int mis = 0;
  63. /* function prototypes */
  64. static void adjust_region (char *, const char *);
  65. static CELL round_c (FCELL);
  66. static void write_fp_to_cell (int, FCELL *);
  67. static void process_raster (int, InputMask, ScaleRange, int, int, int, bool, ScaleRange, bool);
  68. static void copy_colors (char *, const char *, char *);
  69. static void define_module (void);
  70. static struct Options define_options (void);
  71. static void read_scale (Option *, ScaleRange &);
  72. /*
  73. Adjust the region to that of the input raster.
  74. Atmospheric corrections should be done on the whole
  75. satelite image, not just portions.
  76. */
  77. static void adjust_region (char *name, const char *mapset)
  78. {
  79. struct Cell_head iimg_head; /* the input image header file */
  80. Rast_get_cellhd(name, mapset, &iimg_head);
  81. if(Rast_set_window(&iimg_head) < 0)
  82. G_fatal_error (_("Invalid graphics region coordinates"));
  83. }
  84. /* Rounds a floating point cell value */
  85. static CELL round_c (FCELL x)
  86. {
  87. if (x >= 0.0)
  88. return (CELL)(x + .5);
  89. return (CELL)(-(-x + .5));
  90. }
  91. /* Converts the buffer to cell and write it to disk */
  92. static void write_fp_to_cell (int ofd, FCELL* buf)
  93. {
  94. CELL* cbuf;
  95. int col;
  96. cbuf = (CELL*)Rast_allocate_buf(CELL_TYPE);
  97. for(col = 0; col < G_window_cols(); col++) cbuf[col] = round_c(buf[col]);
  98. Rast_put_row(ofd, cbuf, CELL_TYPE);
  99. }
  100. /* See also Cache note below */
  101. class TICache
  102. {
  103. enum TICacheSize
  104. {
  105. MAX_TIs = 4096 /* this value is a guess, increase it if in general
  106. * more categories are used. TODO: use dynamic allocation
  107. * since 4096 is the limit on 32bit */
  108. };
  109. TransformInput tis[MAX_TIs];
  110. float alts[MAX_TIs];
  111. int p;
  112. public:
  113. TICache() { p = 0; for(int i = 0; i < MAX_TIs; i++) alts[i] = -1; }
  114. int search(float alt) {
  115. for(int i = 0; i < MAX_TIs; i++)
  116. if(alt == alts[i])
  117. {
  118. hit++;
  119. return i;
  120. }
  121. mis++;
  122. return -1;
  123. }
  124. TransformInput get(int i) { return tis[i]; }
  125. void add(TransformInput ti, float alt) {
  126. tis[p] = ti;
  127. alts[p] = alt;
  128. p++;
  129. if(p >= MAX_TIs) p = 0;
  130. }
  131. };
  132. /* the transform input map, is a array of ticaches.
  133. The first key is the visibility which matches to a TICache for the altitudes.
  134. This code is horrible, i just spent 20min writing and 5min debugging it. */
  135. /* Cache note:
  136. The DEM cases are in range 0 < DEM < 8888 for the World in case of using an
  137. integer DEM values in meters. So the cache should ideally store 8888 different
  138. cases for the World-type conditions if all happen in the same image. */
  139. class TIMap
  140. {
  141. enum TIMapSize
  142. {
  143. MAX_TICs = 4096 /* this value is a guess. It means that <size> TI's will be
  144. * the max combinations of vis/alt pairs. TODO: use dynamic allocation
  145. * since 4096 is the limit on 32bit */
  146. };
  147. TICache tic[MAX_TICs]; /* array of TICaches */
  148. float visi[MAX_TICs];
  149. int p;
  150. public:
  151. struct Position
  152. {
  153. int i, j;
  154. Position() : i(-1), j(-1) {}
  155. Position(int x, int y) : i(x), j(y) {}
  156. bool valid() { return i != -1 && j != -1; }
  157. };
  158. TIMap() { p = 0; for(int i = 0; i < MAX_TICs; i++) visi[i] = -1; }
  159. Position search(float vis, float alt) {
  160. for(int i = 0; i < MAX_TICs; i++)
  161. if(vis == visi[i]) {
  162. Position pos;
  163. pos.i = i;
  164. pos.j = tic[i].search(alt);
  165. return pos;
  166. }
  167. return Position();
  168. }
  169. TransformInput get(Position pos) { return tic[pos.i].get(pos.j); }
  170. void add(TransformInput ti, float vis, float alt) {
  171. tic[p].add(ti, alt);
  172. visi[p] = vis;
  173. p++;
  174. if(p >= MAX_TICs) p = 0;
  175. }
  176. };
  177. struct IntPair
  178. {
  179. FCELL x;
  180. FCELL y;
  181. IntPair(FCELL i, FCELL j) : x(i), y(j) {}
  182. bool operator<(const IntPair& b) const
  183. {
  184. if(x < b.x) return true;
  185. else if(x > b.x) return false;
  186. else if(y < b.y) return true;
  187. return false;
  188. }
  189. };
  190. typedef std::map<IntPair, TransformInput> CacheMap;
  191. const TransformInput& optimize_va (const FCELL& vis, const FCELL& alt)
  192. {
  193. static CacheMap timap;
  194. static TransformInput ti;
  195. IntPair key(vis, alt);
  196. CacheMap::iterator it = timap.find(key);
  197. if(it != timap.end()) /* search found key */
  198. {
  199. ti = (*it).second;
  200. }
  201. else
  202. {
  203. pre_compute_hv(alt, vis);
  204. ti = compute();
  205. timap.insert(std::make_pair(key, ti));
  206. }
  207. return ti;
  208. }
  209. /* Process the raster and do atmospheric corrections.
  210. Params:
  211. * INPUT FILE
  212. ifd: input file descriptor
  213. iref: input file has radiance values (default is reflectance) ?
  214. iscale: input file's range (default is min = 0, max = 255)
  215. ialt_fd: height map file descriptor, negative if global value is used
  216. ivis_fd: visibility map file descriptor, negative if global value is used
  217. * OUTPUT FILE
  218. ofd: output file descriptor
  219. oflt: if true use FCELL_TYPE for output
  220. oscale: output file's range (default is min = 0, max = 255)
  221. */
  222. static void process_raster (int ifd, InputMask imask, ScaleRange iscale,
  223. int ialt_fd, int ivis_fd, int ofd, bool oflt,
  224. ScaleRange oscale, bool optimize)
  225. {
  226. FCELL* buf; /* buffer for the input values */
  227. FCELL* alt = NULL; /* buffer for the elevation values */
  228. FCELL* vis = NULL; /* buffer for the visibility values */
  229. FCELL prev_alt = -1.f;
  230. FCELL prev_vis = -1.f;
  231. int row, col, nrows, ncols;
  232. /* do initial computation with global elevation and visibility values */
  233. TransformInput ti;
  234. ti = compute();
  235. TICache ticache; /* use this to increase computation speed when an elevation map with categories are given */
  236. /* allocate memory for buffers */
  237. buf = (FCELL*)Rast_allocate_buf(FCELL_TYPE);
  238. if(ialt_fd >= 0) alt = (FCELL*)Rast_allocate_buf(FCELL_TYPE);
  239. if(ivis_fd >= 0) vis = (FCELL*)Rast_allocate_buf(FCELL_TYPE);
  240. G_verbose_message(_("Percent complete..."));
  241. nrows = G_window_rows();
  242. ncols = G_window_cols();
  243. for(row = 0; row < nrows; row++)
  244. {
  245. G_percent(row, nrows, 1); /* keep the user informed of our progress */
  246. /* read the next row */
  247. if(Rast_get_row(ifd, buf, row, FCELL_TYPE) < 0)
  248. G_fatal_error (_("Unable to read input raster map row %d"),
  249. row);
  250. /* read the next row of elevation values */
  251. if(ialt_fd >= 0)
  252. if(Rast_get_row(ialt_fd, alt, row, FCELL_TYPE) < 0)
  253. G_fatal_error (_("Unable to read elevation raster map row %d"),
  254. row);
  255. /* read the next row of elevation values */
  256. if(ivis_fd >= 0)
  257. if(Rast_get_row(ivis_fd, vis, row, FCELL_TYPE) < 0)
  258. G_fatal_error (_("Unable to read visibility raster map row %d"),
  259. row);
  260. /* loop over all the values in the row */
  261. for(col = 0; col < ncols; col++)
  262. {
  263. if((vis && Rast_is_f_null_value(&vis[col])) ||
  264. (alt && Rast_is_f_null_value(&alt[col])) ||
  265. Rast_is_f_null_value(&buf[col]))
  266. {
  267. Rast_set_f_null_value(&buf[col], 1);
  268. continue;
  269. }
  270. alt[col] /= 1000.0f; /* converting to km from input which should be in meter */
  271. /* check if both maps are active and if whether any value has changed */
  272. if((ialt_fd >= 0) && (ivis_fd >= 0) && ((prev_vis != vis[col]) || (prev_alt != alt[col])))
  273. {
  274. prev_alt = alt[col]; /* update new values */
  275. prev_vis = vis[col];
  276. if(optimize) ti = optimize_va(vis[col], alt[col]); /* try to optimize? */
  277. else { /* no optimizations */
  278. pre_compute_hv(alt[col], vis[col]);
  279. ti = compute();
  280. }
  281. }
  282. else /* only one of the maps is being used */
  283. {
  284. if((ivis_fd >= 0) && (prev_vis != vis[col]))
  285. {
  286. prev_vis = vis[col]; /* keep track of previous visibility */
  287. if(optimize)
  288. {
  289. int p = ticache.search(vis[col]);
  290. if(p >= 0) ti = ticache.get(p);
  291. else
  292. {
  293. pre_compute_v(vis[col]); /* re-compute transformation inputs */
  294. ti = compute(); /* ... */
  295. ticache.add(ti, vis[col]);
  296. }
  297. }
  298. else
  299. {
  300. pre_compute_v(vis[col]); /* re-compute transformation inputs */
  301. ti = compute(); /* ... */
  302. }
  303. }
  304. if((ialt_fd >= 0) && (prev_alt != alt[col]))
  305. {
  306. prev_alt = alt[col]; /* keep track of previous altitude */
  307. if(optimize)
  308. {
  309. int p = ticache.search(alt[col]);
  310. if(p >= 0) ti = ticache.get(p);
  311. else
  312. {
  313. pre_compute_h(alt[col]); /* re-compute transformation inputs */
  314. ti = compute(); /* ... */
  315. ticache.add(ti, alt[col]);
  316. }
  317. }
  318. else
  319. {
  320. pre_compute_h(alt[col]); /* re-compute transformation inputs */
  321. ti = compute(); /* ... */
  322. }
  323. }
  324. }
  325. G_debug(3, "Computed r%d (%d), c%d (%d)", row, nrows, col, ncols);
  326. /* transform from iscale.[min,max] to [0,1] */
  327. buf[col] = (buf[col] - iscale.min) / ((float)iscale.max - (float)iscale.min);
  328. buf[col] = transform(ti, imask, buf[col]);
  329. /* transform from [0,1] to oscale.[min,max] */
  330. buf[col] = buf[col] * ((float)oscale.max - (float)oscale.min) + oscale.min;
  331. if(~oflt && (buf[col] > (float)oscale.max))
  332. G_warning (_("The output data will overflow. Reflectance > 100%%"));
  333. }
  334. /* write output */
  335. if(oflt) Rast_put_row(ofd, buf, FCELL_TYPE);
  336. else write_fp_to_cell(ofd, buf);
  337. }
  338. /* free allocated memory */
  339. G_free(buf);
  340. if(ialt_fd >= 0) G_free(alt);
  341. if(ivis_fd >= 0) G_free(vis);
  342. }
  343. /* Copy the colors from map named iname to the map named oname */
  344. static void copy_colors (char *iname, const char *imapset, char *oname)
  345. {
  346. struct Colors colors;
  347. Rast_read_colors(iname, imapset, &colors);
  348. Rast_write_colors(oname, G_mapset(), &colors);
  349. }
  350. /* Define our module so that Grass can print it if the user wants to know more. */
  351. static void define_module (void)
  352. {
  353. struct GModule *module;
  354. module = G_define_module();
  355. module->label = _("Performs atmospheric correction using the 6S algorithm.");
  356. module->description =
  357. _("6S - Second Simulation of Satellite Signal in the Solar Spectrum.");
  358. G_add_keyword(_("imagery"));
  359. G_add_keyword(_("atmospheric correction"));
  360. /*
  361. " Incorporated into Grass by Christo A. Zietsman, January 2003.\n"
  362. " Converted from Fortran to C by Christo A. Zietsman, November 2002.\n\n"
  363. " Adapted by Mauro A. Homem Antunes for atmopheric corrections of\n"
  364. " remotely sensed images in raw format (.RAW) of 8 bits.\n"
  365. " April 4, 2001.\n\n"
  366. " Please refer to the following paper and acknowledge the authors of\n"
  367. " the model:\n"
  368. " Vermote, E.F., Tanre, D., Deuze, J.L., Herman, M., and Morcrette,\n"
  369. " J.J., (1997), Second simulation of the satellite signal in\n"
  370. " the solar spectrum, 6S: An overview., IEEE Trans. Geosc.\n"
  371. " and Remote Sens. 35(3):675-686.\n"
  372. " The code is provided as is and is not to be sold. See notes on\n"
  373. " http://loasys.univ-lille1.fr/informatique/sixs_gb.html\n"
  374. " http://www.ltid.inpe.br/dsr/mauro/6s/index.html\n"
  375. " and on http://www.cs.sun.ac.za/~caz/index.html\n";*/
  376. }
  377. /* Define the options and flags */
  378. static struct Options define_options (void)
  379. {
  380. struct Options opts;
  381. opts.iimg = G_define_standard_option (G_OPT_R_INPUT);
  382. opts.iimg->key = "iimg";
  383. opts.iscl = G_define_option();
  384. opts.iscl->key = "iscl";
  385. opts.iscl->type = TYPE_INTEGER;
  386. opts.iscl->key_desc = "range";
  387. opts.iscl->required = NO;
  388. opts.iscl->answer = "0,255";
  389. opts.iscl->description = _("Input imagery range [0,255]");
  390. opts.iscl->guisection = _("Input");
  391. opts.ialt = G_define_standard_option (G_OPT_R_INPUT);
  392. opts.ialt->key = "ialt";
  393. opts.ialt->required = NO;
  394. opts.ialt->answer = "dem_float";
  395. opts.ialt->description = _("Input altitude raster map in m (optional)");
  396. opts.ialt->guisection = _("Input");
  397. opts.ivis = G_define_standard_option (G_OPT_R_INPUT);
  398. opts.ivis->key = "ivis";
  399. opts.ivis->required = NO;
  400. opts.ivis->description = _("Input visibility raster map in km (optional)");
  401. opts.ivis->guisection = _("Input");
  402. opts.icnd = G_define_standard_option (G_OPT_F_INPUT);
  403. opts.icnd->key = "icnd";
  404. opts.icnd->required = YES;
  405. opts.icnd->description = _("Name of input text file");
  406. opts.oimg = G_define_standard_option (G_OPT_R_OUTPUT);
  407. opts.oimg->key = "oimg";
  408. opts.oscl = G_define_option();
  409. opts.oscl->key = "oscl";
  410. opts.oscl->type = TYPE_INTEGER;
  411. opts.oscl->key_desc = "range";
  412. opts.oscl->answer = "0,255";
  413. opts.oscl->required = NO;
  414. opts.oscl->description = _("Rescale output raster map [0,255]");
  415. opts.oscl->guisection = _("Output");
  416. opts.oflt = G_define_flag();
  417. opts.oflt->key = 'f';
  418. opts.oflt->description = _("Output raster is floating point");
  419. opts.oflt->guisection = _("Output");
  420. opts.irad = G_define_flag();
  421. opts.irad->key = 'r';
  422. opts.irad->description = _("Input map converted to reflectance (default is radiance)");
  423. opts.irad->guisection = _("Input");
  424. opts.etmafter = G_define_flag();
  425. opts.etmafter->key = 'a';
  426. opts.etmafter->description = _("Input from ETM+ image taken after July 1, 2000");
  427. opts.etmafter->guisection = _("Input");
  428. opts.etmbefore = G_define_flag();
  429. opts.etmbefore->key = 'b';
  430. opts.etmbefore->description = _("Input from ETM+ image taken before July 1, 2000");
  431. opts.etmbefore->guisection = _("Input");
  432. opts.optimize = G_define_flag();
  433. opts.optimize->key = 'o';
  434. opts.optimize->description = _("Try to increase computation speed when categorized altitude or/and visibility map is used");
  435. return opts;
  436. }
  437. /* Read the min and max values from the iscl and oscl options */
  438. void read_scale (Option *scl, ScaleRange &range)
  439. {
  440. /* set default values */
  441. range.min = 0;
  442. range.max = 255;
  443. if(scl->answer)
  444. {
  445. sscanf(scl->answers[0], "%d", &range.min);
  446. sscanf(scl->answers[1], "%d", &range.max);
  447. if(range.min==range.max)
  448. {
  449. G_warning (_("Scale range length should be > 0; Using default values: [0,255]"));
  450. range.min = 0;
  451. range.max = 255;
  452. }
  453. }
  454. /* swap values if max is smaller than min */
  455. if(range.max < range.min)
  456. {
  457. int temp;
  458. temp = range.max;
  459. range.max = range.min;
  460. range.min = temp;
  461. }
  462. }
  463. int main(int argc, char* argv[])
  464. {
  465. struct Options opts;
  466. struct ScaleRange iscale; /* input file's data is scaled to this interval */
  467. struct ScaleRange oscale; /* output file's scale */
  468. int iimg_fd; /* input image's file descriptor */
  469. int oimg_fd; /* output image's file descriptor */
  470. int ialt_fd = -1; /* input elevation map's file descriptor */
  471. int ivis_fd = -1; /* input visibility map's file descriptor */
  472. const char *iimg_mapset, *ialt_mapset, *iviz_mapset;
  473. struct History hist;
  474. /* Define module */
  475. define_module();
  476. /* Define the different input options */
  477. opts = define_options();
  478. /**** Start ****/
  479. G_gisinit(argv[0]);
  480. if (G_parser(argc, argv) < 0)
  481. exit (EXIT_FAILURE);
  482. /* open input raster */
  483. if ( (iimg_mapset = G_find_raster2 ( opts.iimg->answer, "") ) == NULL )
  484. G_fatal_error ( _("Raster map <%s> not found"), opts.iimg->answer);
  485. if((iimg_fd = Rast_open_old(opts.iimg->answer, iimg_mapset)) < 0)
  486. G_fatal_error (_("Unable to open raster map <%s>"),
  487. G_fully_qualified_name(opts.iimg->answer, iimg_mapset));
  488. adjust_region(opts.iimg->answer, iimg_mapset);
  489. if(opts.ialt->answer) {
  490. if ( (ialt_mapset = G_find_raster2 ( opts.ialt->answer, "") ) == NULL )
  491. G_fatal_error ( _("Raster map <%s> not found"), opts.ialt->answer);
  492. if((ialt_fd = Rast_open_old(opts.ialt->answer, ialt_mapset)) < 0)
  493. G_fatal_error (_("Unable to open raster map <%s>"),
  494. G_fully_qualified_name(opts.ialt->answer, ialt_mapset));
  495. }
  496. if(opts.ivis->answer) {
  497. if ( (iviz_mapset = G_find_raster2 ( opts.ivis->answer, "") ) == NULL )
  498. G_fatal_error ( _("Raster map <%s> not found"), opts.ivis->answer);
  499. if((ivis_fd = Rast_open_old(opts.ivis->answer, iviz_mapset)) < 0)
  500. G_fatal_error (_("Unable to open raster map <%s>"),
  501. G_fully_qualified_name(opts.ivis->answer, iviz_mapset));
  502. }
  503. /* open a floating point raster or not? */
  504. if(opts.oflt->answer)
  505. {
  506. if((oimg_fd = Rast_open_fp_new(opts.oimg->answer)) < 0)
  507. G_fatal_error (_("Unable to create raster map <%s>"),
  508. opts.oimg->answer);
  509. }
  510. else
  511. {
  512. if((oimg_fd = Rast_open_new(opts.oimg->answer, CELL_TYPE)) < 0)
  513. G_fatal_error (_("Unable to create raster map <%s>"),
  514. opts.oimg->answer);
  515. }
  516. /* read the scale parameters */
  517. read_scale(opts.iscl, iscale);
  518. read_scale(opts.oscl, oscale);
  519. /* initialize this 6s computation and parse the input conditions file */
  520. init_6S(opts.icnd->answer);
  521. InputMask imask = RADIANCE; /* the input mask tells us what transformations if any
  522. needs to be done to make our input values, reflectance
  523. values scaled between 0 and 1 */
  524. if(opts.irad->answer) imask = REFLECTANCE;
  525. if(opts.etmbefore->answer) imask = (InputMask)(imask | ETM_BEFORE);
  526. if(opts.etmafter->answer) imask = (InputMask)(imask | ETM_AFTER);
  527. /* process the input raster and produce our atmospheric corrected output raster. */
  528. process_raster(iimg_fd, imask, iscale, ialt_fd, ivis_fd,
  529. oimg_fd, opts.oflt->answer, oscale, opts.optimize->answer);
  530. /* Close the input and output file descriptors */
  531. Rast_short_history(opts.oimg->answer, "raster", &hist);
  532. Rast_close(iimg_fd);
  533. if(opts.ialt->answer) Rast_close(ialt_fd);
  534. if(opts.ivis->answer) Rast_close(ivis_fd);
  535. Rast_close(oimg_fd);
  536. Rast_command_history(&hist);
  537. Rast_write_history(opts.oimg->answer, &hist);
  538. /* Copy the colors of the input raster to the output raster.
  539. Scaling is ignored and color ranges might not be correct. */
  540. copy_colors(opts.iimg->answer, iimg_mapset, opts.oimg->answer);
  541. exit (EXIT_SUCCESS);
  542. }