main.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587
  1. /****************************************************************************
  2. *
  3. * MODULE: r.resamp.filter
  4. * AUTHOR(S): Glynn Clements <glynn gclements.plus.com>
  5. * PURPOSE:
  6. * COPYRIGHT: (C) 2010 by Glynn Clements and the GRASS Development Team
  7. *
  8. * This program is free software under the GNU General Public
  9. * License (>=v2). Read the file COPYING that comes with GRASS
  10. * for details.
  11. *
  12. *****************************************************************************/
  13. #include <stdlib.h>
  14. #include <string.h>
  15. #include <limits.h>
  16. #include <math.h>
  17. #include <grass/gis.h>
  18. #include <grass/raster.h>
  19. #include <grass/glocale.h>
  20. static double f_box(double x)
  21. {
  22. return (x > 1) ? 0
  23. : 1;
  24. }
  25. static double f_bartlett(double x)
  26. {
  27. return (x > 1) ? 0
  28. : 1 - x;
  29. }
  30. static double f_hermite(double x)
  31. {
  32. return (x > 1) ? 0
  33. : (2 * x - 3) * x * x + 1;
  34. }
  35. static double f_gauss(double x)
  36. {
  37. return exp(-2 * x * x) * sqrt(2 / M_PI);
  38. }
  39. static double f_normal(double x)
  40. {
  41. return f_gauss(x/2) / 2;
  42. }
  43. static double f_sinc(double x)
  44. {
  45. return (x == 0) ? 1 : sin(M_PI * x) / (M_PI * x);
  46. }
  47. static double lanczos(double x, int a)
  48. {
  49. return (x > a) ? 0
  50. : f_sinc(x) * f_sinc(x / a);
  51. }
  52. static double f_lanczos1(double x)
  53. {
  54. return lanczos(x, 1);
  55. }
  56. static double f_lanczos2(double x)
  57. {
  58. return lanczos(x, 2);
  59. }
  60. static double f_lanczos3(double x)
  61. {
  62. return lanczos(x, 3);
  63. }
  64. static double f_hann(double x)
  65. {
  66. return cos(M_PI * x) / 2 + 0.5;
  67. }
  68. static double f_hamming(double x)
  69. {
  70. return 0.46 * cos(M_PI * x) + 0.54;
  71. }
  72. static double f_blackman(double x)
  73. {
  74. return cos(M_PI * x) / 2 + 0.08 * cos(2 * M_PI * x) + 0.42;
  75. }
  76. struct filter_type {
  77. const char *name;
  78. double (*func)(double);
  79. int radius;
  80. };
  81. static const struct filter_type menu[] = {
  82. {"box", f_box, 1},
  83. {"bartlett", f_bartlett, 1},
  84. {"gauss", f_gauss, 0},
  85. {"normal", f_normal, 0},
  86. {"hermite", f_hermite, 1},
  87. {"sinc", f_sinc, 0},
  88. {"lanczos1", f_lanczos1, 1},
  89. {"lanczos2", f_lanczos2, 2},
  90. {"lanczos3", f_lanczos3, 3},
  91. {"hann", f_hann, 0},
  92. {"hamming", f_hamming, 0},
  93. {"blackman", f_blackman, 0},
  94. {NULL},
  95. };
  96. static char *build_filter_list(void)
  97. {
  98. char *buf = G_malloc(1024);
  99. char *p = buf;
  100. int i;
  101. for (i = 0; menu[i].name; i++) {
  102. const char *q;
  103. if (i)
  104. *p++ = ',';
  105. for (q = menu[i].name; *q; p++, q++)
  106. *p = *q;
  107. }
  108. *p = '\0';
  109. return buf;
  110. }
  111. static const struct filter_type *find_method(const char *name)
  112. {
  113. int i;
  114. for (i = 0; menu[i].name; i++)
  115. if (strcmp(menu[i].name, name) == 0)
  116. return &menu[i];
  117. G_fatal_error(_("Filter <%s> not found"), name);
  118. return NULL;
  119. }
  120. struct filter {
  121. double (*func)(double);
  122. double x_radius;
  123. double y_radius;
  124. };
  125. #define MAX_FILTERS 8
  126. static int infile, outfile;
  127. static struct filter filters[MAX_FILTERS];
  128. static int num_filters;
  129. static int nulls;
  130. static struct Cell_head dst_w, src_w;
  131. static double f_x_radius, f_y_radius;
  132. static int row_scale, col_scale;
  133. static DCELL *inbuf;
  134. static DCELL *outbuf;
  135. static DCELL **bufs;
  136. static double *h_weights;
  137. static double *v_weights;
  138. static int *mapcol0, *mapcol1;
  139. static int *maprow0, *maprow1;
  140. static void make_h_weights(void)
  141. {
  142. int col;
  143. h_weights = G_malloc(dst_w.cols * col_scale * sizeof(double));
  144. mapcol0 = G_malloc(dst_w.cols * sizeof(int));
  145. mapcol1 = G_malloc(dst_w.cols * sizeof(int));
  146. for (col = 0; col < dst_w.cols; col++) {
  147. double dx = Rast_col_to_easting(col + 0.5, &dst_w);
  148. /* do not use Rast_easting_to_col() because it does ll wrap */
  149. /*
  150. double x0 = Rast_easting_to_col(dx - f_x_radius, &src_w);
  151. double x1 = Rast_easting_to_col(dx + f_x_radius, &src_w);
  152. */
  153. double x0 = (dx - f_x_radius - src_w.west) / src_w.ew_res;
  154. double x1 = (dx + f_x_radius - src_w.west) / src_w.ew_res;
  155. int col0 = (int)floor(x0);
  156. int col1 = (int)floor(x1) + 1;
  157. int cols = col1 - col0;
  158. int j;
  159. mapcol0[col] = col0;
  160. mapcol1[col] = col1;
  161. for (j = 0; j < cols; j++) {
  162. double sx = Rast_col_to_easting(col0 + j + 0.5, &src_w);
  163. double r = fabs(sx - dx);
  164. double w = 1.0;
  165. int k;
  166. for (k = 0; k < num_filters; k++)
  167. w *= (*filters[k].func)(r / filters[k].x_radius);
  168. h_weights[col * col_scale + j] = w;
  169. }
  170. for (j = cols; j < col_scale; j++)
  171. h_weights[col * col_scale + j] = 0;
  172. }
  173. }
  174. static void make_v_weights(void)
  175. {
  176. int row;
  177. v_weights = G_malloc(dst_w.rows * row_scale * sizeof(double));
  178. maprow0 = G_malloc(dst_w.rows * sizeof(int));
  179. maprow1 = G_malloc(dst_w.rows * sizeof(int));
  180. for (row = 0; row < dst_w.rows; row++) {
  181. double dy = Rast_row_to_northing(row + 0.5, &dst_w);
  182. double y0 = Rast_northing_to_row(dy + f_y_radius, &src_w);
  183. double y1 = Rast_northing_to_row(dy - f_y_radius, &src_w);
  184. int row0 = (int)floor(y0);
  185. int row1 = (int)floor(y1) + 1;
  186. int rows = row1 - row0;
  187. int i;
  188. maprow0[row] = row0;
  189. maprow1[row] = row1;
  190. for (i = 0; i < rows; i++) {
  191. double sy = Rast_row_to_northing(row0 + i + 0.5, &src_w);
  192. double r = fabs(sy - dy);
  193. double w = 1.0;
  194. int k;
  195. for (k = 0; k < num_filters; k++)
  196. w *= (*filters[k].func)(r / filters[k].y_radius);
  197. v_weights[row * row_scale + i] = w;
  198. }
  199. for (i = rows; i < row_scale; i++)
  200. v_weights[row * row_scale + i] = 0;
  201. }
  202. }
  203. static void h_filter(DCELL *dst, const DCELL *src)
  204. {
  205. int col;
  206. for (col = 0; col < dst_w.cols; col++) {
  207. int col0 = mapcol0[col];
  208. int col1 = mapcol1[col];
  209. int cols = col1 - col0;
  210. double numer = 0.0;
  211. double denom = 0.0;
  212. int null = 0;
  213. int j;
  214. for (j = 0; j < cols; j++) {
  215. double w = h_weights[col * col_scale + j];
  216. const DCELL *c = &src[col0 + j];
  217. if (Rast_is_d_null_value(c)) {
  218. if (nulls) {
  219. null = 1;
  220. break;
  221. }
  222. }
  223. else {
  224. numer += w * (*c);
  225. denom += w;
  226. }
  227. }
  228. if (null || denom == 0)
  229. Rast_set_d_null_value(&dst[col], 1);
  230. else
  231. dst[col] = numer / denom;
  232. }
  233. }
  234. static void v_filter(DCELL *dst, DCELL **src, int row, int rows)
  235. {
  236. int col;
  237. for (col = 0; col < dst_w.cols; col++) {
  238. double numer = 0.0;
  239. double denom = 0.0;
  240. int null = 0;
  241. int i;
  242. for (i = 0; i < rows; i++) {
  243. double w = v_weights[row * row_scale + i];
  244. const DCELL *c = &src[i][col];
  245. if (Rast_is_d_null_value(c)) {
  246. if (nulls) {
  247. null = 1;
  248. break;
  249. }
  250. }
  251. else {
  252. numer += w * (*c);
  253. denom += w;
  254. }
  255. }
  256. if (null || denom == 0)
  257. Rast_set_d_null_value(&dst[col], 1);
  258. else
  259. dst[col] = numer / denom;
  260. }
  261. }
  262. static void filter(void)
  263. {
  264. int cur_row = 0;
  265. int num_rows = 0;
  266. int row;
  267. make_h_weights();
  268. make_v_weights();
  269. for (row = 0; row < dst_w.rows; row++) {
  270. int row0 = maprow0[row];
  271. int row1 = maprow1[row];
  272. int rows = row1 - row0;
  273. int i;
  274. G_percent(row, dst_w.rows, 2);
  275. if (row0 >= cur_row && row0 < cur_row + num_rows) {
  276. int m = row0 - cur_row;
  277. int n = cur_row + num_rows - row0;
  278. int i;
  279. for (i = 0; i < n; i++) {
  280. DCELL *tmp = bufs[i];
  281. bufs[i] = bufs[m + i];
  282. bufs[m + i] = tmp;
  283. }
  284. cur_row = row0;
  285. num_rows = n;
  286. }
  287. else {
  288. cur_row = row0;
  289. num_rows = 0;
  290. }
  291. for (i = num_rows; i < rows; i++) {
  292. G_debug(5, "read: %p = %d", bufs[i], row0 + i);
  293. Rast_get_d_row(infile, inbuf, row0 + i);
  294. h_filter(bufs[i], inbuf);
  295. }
  296. num_rows = rows;
  297. v_filter(outbuf, bufs, row, rows);
  298. Rast_put_d_row(outfile, outbuf);
  299. G_debug(5, "write: %d", row);
  300. }
  301. G_percent(dst_w.rows, dst_w.rows, 2);
  302. }
  303. int main(int argc, char *argv[])
  304. {
  305. struct GModule *module;
  306. struct
  307. {
  308. struct Option *rastin, *rastout, *method,
  309. *radius, *x_radius, *y_radius;
  310. } parm;
  311. struct
  312. {
  313. struct Flag *nulls;
  314. } flag;
  315. char title[64];
  316. int i;
  317. G_gisinit(argv[0]);
  318. module = G_define_module();
  319. G_add_keyword(_("raster"));
  320. G_add_keyword(_("resample"));
  321. G_add_keyword(_("kernel filter"));
  322. G_add_keyword(_("filter"));
  323. module->description =
  324. _("Resamples raster map layers using an analytic kernel.");
  325. parm.rastin = G_define_standard_option(G_OPT_R_INPUT);
  326. parm.rastout = G_define_standard_option(G_OPT_R_OUTPUT);
  327. parm.method = G_define_option();
  328. parm.method->key = "filter";
  329. parm.method->type = TYPE_STRING;
  330. parm.method->required = YES;
  331. parm.method->multiple = YES;
  332. parm.method->description = _("Filter kernel(s)");
  333. parm.method->options = build_filter_list();
  334. parm.radius = G_define_option();
  335. parm.radius->key = "radius";
  336. parm.radius->type = TYPE_DOUBLE;
  337. parm.radius->required = NO;
  338. parm.radius->multiple = YES;
  339. parm.radius->description = _("Filter radius");
  340. parm.x_radius = G_define_option();
  341. parm.x_radius->key = "x_radius";
  342. parm.x_radius->type = TYPE_DOUBLE;
  343. parm.x_radius->required = NO;
  344. parm.x_radius->multiple = YES;
  345. parm.x_radius->description = _("Filter radius (horizontal)");
  346. parm.y_radius = G_define_option();
  347. parm.y_radius->key = "y_radius";
  348. parm.y_radius->type = TYPE_DOUBLE;
  349. parm.y_radius->required = NO;
  350. parm.y_radius->multiple = YES;
  351. parm.y_radius->description = _("Filter radius (vertical)");
  352. flag.nulls = G_define_flag();
  353. flag.nulls->key = 'n';
  354. flag.nulls->description = _("Propagate NULLs");
  355. if (G_parser(argc, argv))
  356. exit(EXIT_FAILURE);
  357. if (parm.radius->answer) {
  358. if (parm.x_radius->answer || parm.y_radius->answer)
  359. G_fatal_error(_("%s= and %s=/%s= are mutually exclusive"),
  360. parm.radius->key, parm.x_radius->key, parm.y_radius->key);
  361. }
  362. else {
  363. if (!parm.x_radius->answer && !parm.y_radius->answer)
  364. G_fatal_error(_("Either %s= or %s=/%s= required"),
  365. parm.radius->key, parm.x_radius->key, parm.y_radius->key);
  366. if (!parm.x_radius->answer || !parm.y_radius->answer)
  367. G_fatal_error(_("Both %s= and %s= required"),
  368. parm.x_radius->key, parm.y_radius->key);
  369. }
  370. nulls = flag.nulls->answer;
  371. f_x_radius = f_y_radius = 1e100;
  372. for (i = 0; ; i++) {
  373. const char *filter_arg = parm.method->answers[i];
  374. const char *x_radius_arg = parm.radius->answer
  375. ? parm.radius->answers[i]
  376. : parm.x_radius->answers[i];
  377. const char *y_radius_arg = parm.radius->answer
  378. ? parm.radius->answers[i]
  379. : parm.y_radius->answers[i];
  380. const struct filter_type *type;
  381. struct filter *filter;
  382. if (!filter_arg && !x_radius_arg && !y_radius_arg)
  383. break;
  384. if (!filter_arg || !x_radius_arg || !y_radius_arg)
  385. G_fatal_error(_("Differing number of values for filter= and [xy_]radius="));
  386. if (num_filters >= MAX_FILTERS)
  387. G_fatal_error(_("Too many filters (max: %d)"), MAX_FILTERS);
  388. filter = &filters[num_filters++];
  389. type = find_method(filter_arg);
  390. filter->func = type->func;
  391. filter->x_radius = fabs(atof(x_radius_arg));
  392. filter->y_radius = fabs(atof(y_radius_arg));
  393. if (type->radius) {
  394. double rx = type->radius * filter->x_radius;
  395. double ry = type->radius * filter->y_radius;
  396. if (rx < f_x_radius)
  397. f_x_radius = rx;
  398. if (ry < f_y_radius)
  399. f_y_radius = ry;
  400. }
  401. }
  402. if (f_x_radius > 1e99 || f_y_radius > 1e99)
  403. G_fatal_error(_("At least one filter must be finite"));
  404. G_get_set_window(&dst_w);
  405. /* set window to old map */
  406. Rast_get_cellhd(parm.rastin->answer, "", &src_w);
  407. if (G_projection() == PROJECTION_LL) {
  408. /* try to shift source window to overlap with destination window */
  409. while (src_w.west >= dst_w.east && src_w.east - 360.0 > dst_w.west) {
  410. src_w.east -= 360.0;
  411. src_w.west -= 360.0;
  412. }
  413. while (src_w.east <= dst_w.west && src_w.west + 360.0 < dst_w.east) {
  414. src_w.east += 360.0;
  415. src_w.west += 360.0;
  416. }
  417. }
  418. /* enlarge source window */
  419. {
  420. double y0 = Rast_row_to_northing(0.5, &dst_w);
  421. double y1 = Rast_row_to_northing(dst_w.rows - 0.5, &dst_w);
  422. double x0 = Rast_col_to_easting(0.5, &dst_w);
  423. double x1 = Rast_col_to_easting(dst_w.cols - 0.5, &dst_w);
  424. int r0 = (int)floor(Rast_northing_to_row(y0 + f_y_radius, &src_w) - 0.1);
  425. int r1 = (int)ceil(Rast_northing_to_row(y1 - f_y_radius, &src_w) + 0.1);
  426. /* do not use Rast_easting_to_col() because it does ll wrap */
  427. /*
  428. int c0 = (int)floor(Rast_easting_to_col(x0 - f_x_radius, &src_w) - 0.1);
  429. int c1 = (int)ceil(Rast_easting_to_col(x1 + f_x_radius, &src_w) + 0.1);
  430. */
  431. int c0 = (int)floor((x0 - f_x_radius - src_w.west) / src_w.ew_res - 0.1);
  432. int c1 = (int)ceil((x1 + f_x_radius - src_w.west) / src_w.ew_res + 0.1);
  433. src_w.south -= src_w.ns_res * (r1 - src_w.rows);
  434. src_w.north += src_w.ns_res * (-r0);
  435. src_w.west -= src_w.ew_res * (-c0);
  436. src_w.east += src_w.ew_res * (c1 - src_w.cols);
  437. src_w.rows = r1 - r0;
  438. src_w.cols = c1 - c0;
  439. }
  440. row_scale = 2 + 2 * ceil(f_y_radius / src_w.ns_res);
  441. col_scale = 2 + 2 * ceil(f_x_radius / src_w.ew_res);
  442. /* allocate buffers for intermediate rows */
  443. bufs = G_malloc(row_scale * sizeof(DCELL *));
  444. for (i = 0; i < row_scale; i++)
  445. bufs[i] = Rast_allocate_d_buf();
  446. Rast_set_input_window(&src_w);
  447. Rast_set_output_window(&dst_w);
  448. inbuf = Rast_allocate_d_input_buf();
  449. outbuf = Rast_allocate_d_output_buf();
  450. infile = Rast_open_old(parm.rastin->answer, "");
  451. outfile = Rast_open_new(parm.rastout->answer, DCELL_TYPE);
  452. filter();
  453. Rast_close(infile);
  454. Rast_close(outfile);
  455. /* record map metadata/history info */
  456. sprintf(title, "Filter resample by %s", parm.method->answer);
  457. Rast_put_cell_title(parm.rastout->answer, title);
  458. {
  459. struct History history;
  460. char buf_nsres[100], buf_ewres[100];
  461. Rast_short_history(parm.rastout->answer, "raster", &history);
  462. Rast_set_history(&history, HIST_DATSRC_1, parm.rastin->answer);
  463. G_format_resolution(src_w.ns_res, buf_nsres, src_w.proj);
  464. G_format_resolution(src_w.ew_res, buf_ewres, src_w.proj);
  465. Rast_format_history(&history, HIST_DATSRC_2,
  466. "Source map NS res: %s EW res: %s",
  467. buf_nsres, buf_ewres);
  468. Rast_command_history(&history);
  469. Rast_write_history(parm.rastout->answer, &history);
  470. }
  471. /* copy color table from source map */
  472. {
  473. struct Colors colors;
  474. if (Rast_read_colors(parm.rastin->answer, "", &colors) < 0)
  475. G_fatal_error(_("Unable to read color table for %s"),
  476. parm.rastin->answer);
  477. Rast_mark_colors_as_fp(&colors);
  478. Rast_write_colors(parm.rastout->answer, G_mapset(), &colors);
  479. }
  480. return EXIT_SUCCESS;
  481. }