2
/****************************************************************************
4
* MODULE: r.resamp.filter
5
* AUTHOR(S): Glynn Clements <glynn gclements.plus.com>
7
* COPYRIGHT: (C) 2010 by Glynn Clements and the GRASS Development Team
9
* This program is free software under the GNU General Public
10
* License (>=v2). Read the file COPYING that comes with GRASS
13
*****************************************************************************/
19
#include <grass/gis.h>
20
#include <grass/raster.h>
21
#include <grass/glocale.h>
23
static double f_box(double x)
29
static double f_bartlett(double x)
35
static double f_hermite(double x)
38
: (2 * x - 3) * x * x + 1;
41
static double f_gauss(double x)
43
return exp(-2 * x * x) * sqrt(2 / M_PI);
46
static double f_normal(double x)
48
return f_gauss(x/2) / 2;
51
static double f_sinc(double x)
53
return (x == 0) ? 1 : sin(M_PI * x) / (M_PI * x);
56
static double lanczos(double x, int a)
59
: f_sinc(x) * f_sinc(x / a);
62
static double f_lanczos1(double x)
67
static double f_lanczos2(double x)
72
static double f_lanczos3(double x)
77
static double f_hann(double x)
79
return cos(M_PI * x) / 2 + 0.5;
82
static double f_hamming(double x)
84
return 0.46 * cos(M_PI * x) + 0.54;
88
static double f_blackman(double x)
90
return cos(M_PI * x) / 2 + 0.08 * cos(2 * M_PI * x) + 0.42;
95
double (*func)(double);
99
static const struct filter_type menu[] = {
101
{"bartlett", f_bartlett, 1},
102
{"gauss", f_gauss, 0},
103
{"normal", f_normal, 0},
104
{"hermite", f_hermite, 1},
106
{"lanczos1", f_lanczos1, 1},
107
{"lanczos2", f_lanczos2, 2},
108
{"lanczos3", f_lanczos3, 3},
110
{"hamming", f_hamming, 0},
111
{"blackman", f_blackman, 0},
115
static char *build_filter_list(void)
117
char *buf = G_malloc(1024);
121
for (i = 0; menu[i].name; i++) {
126
for (q = menu[i].name; *q; p++, q++)
134
static const struct filter_type *find_method(const char *name)
138
for (i = 0; menu[i].name; i++)
139
if (strcmp(menu[i].name, name) == 0)
142
G_fatal_error(_("Filter <%s> not found"), name);
148
double (*func)(double);
153
#define MAX_FILTERS 8
155
static int infile, outfile;
156
static struct filter filters[MAX_FILTERS];
157
static int num_filters;
159
static struct Cell_head dst_w, src_w;
160
static double f_x_radius, f_y_radius;
161
static int row_scale, col_scale;
163
static DCELL *outbuf;
165
static double *h_weights;
166
static double *v_weights;
167
static int *mapcol0, *mapcol1;
168
static int *maprow0, *maprow1;
170
static void make_h_weights(void)
174
h_weights = G_malloc(dst_w.cols * col_scale * sizeof(double));
175
mapcol0 = G_malloc(dst_w.cols * sizeof(int));
176
mapcol1 = G_malloc(dst_w.cols * sizeof(int));
178
for (col = 0; col < dst_w.cols; col++) {
179
double dx = Rast_col_to_easting(col + 0.5, &dst_w);
180
double x0 = Rast_easting_to_col(dx - f_x_radius, &src_w);
181
double x1 = Rast_easting_to_col(dx + f_x_radius, &src_w);
182
int col0 = (int)floor(x0);
183
int col1 = (int)floor(x1) + 1;
184
int cols = col1 - col0;
190
for (j = 0; j < cols; j++) {
191
double sx = Rast_col_to_easting(col0 + j + 0.5, &src_w);
192
double r = fabs(sx - dx);
196
for (k = 0; k < num_filters; k++)
197
w *= (*filters[k].func)(r / filters[k].x_radius);
199
h_weights[col * col_scale + j] = w;
202
for (j = cols; j < col_scale; j++)
203
h_weights[col * col_scale + j] = 0;
207
static void make_v_weights(void)
211
v_weights = G_malloc(dst_w.rows * row_scale * sizeof(double));
212
maprow0 = G_malloc(dst_w.rows * sizeof(int));
213
maprow1 = G_malloc(dst_w.rows * sizeof(int));
215
for (row = 0; row < dst_w.rows; row++) {
216
double dy = Rast_row_to_northing(row + 0.5, &dst_w);
217
double y0 = Rast_northing_to_row(dy + f_y_radius, &src_w);
218
double y1 = Rast_northing_to_row(dy - f_y_radius, &src_w);
219
int row0 = (int)floor(y0);
220
int row1 = (int)floor(y1) + 1;
221
int rows = row1 - row0;
227
for (i = 0; i < rows; i++) {
228
double sy = Rast_row_to_northing(row0 + i + 0.5, &src_w);
229
double r = fabs(sy - dy);
233
for (k = 0; k < num_filters; k++)
234
w *= (*filters[k].func)(r / filters[k].y_radius);
236
v_weights[row * row_scale + i] = w;
239
for (i = rows; i < row_scale; i++)
240
v_weights[row * row_scale + i] = 0;
244
static void h_filter(DCELL *dst, const DCELL *src)
248
for (col = 0; col < dst_w.cols; col++) {
249
int col0 = mapcol0[col];
250
int col1 = mapcol1[col];
251
int cols = col1 - col0;
257
for (j = 0; j < cols; j++) {
258
double w = h_weights[col * col_scale + j];
259
const DCELL *c = &src[col0 + j];
261
if (Rast_is_d_null_value(c)) {
273
if (null || denom == 0)
274
Rast_set_d_null_value(&dst[col], 1);
276
dst[col] = numer / denom;
280
static void v_filter(DCELL *dst, DCELL **src, int row, int rows)
284
for (col = 0; col < dst_w.cols; col++) {
290
for (i = 0; i < rows; i++) {
291
double w = v_weights[row * row_scale + i];
292
const DCELL *c = &src[i][col];
294
if (Rast_is_d_null_value(c)) {
306
if (null || denom == 0)
307
Rast_set_d_null_value(&dst[col], 1);
309
dst[col] = numer / denom;
313
static void filter(void)
322
for (row = 0; row < dst_w.rows; row++) {
323
int row0 = maprow0[row];
324
int row1 = maprow1[row];
325
int rows = row1 - row0;
328
G_percent(row, dst_w.rows, 2);
330
if (row0 >= cur_row && row0 < cur_row + num_rows) {
331
int m = row0 - cur_row;
332
int n = cur_row + num_rows - row0;
335
for (i = 0; i < n; i++) {
336
DCELL *tmp = bufs[i];
337
bufs[i] = bufs[m + i];
349
for (i = num_rows; i < rows; i++) {
350
G_debug(5, "read: %p = %d", bufs[i], row0 + i);
351
Rast_get_d_row(infile, inbuf, row0 + i);
352
h_filter(bufs[i], inbuf);
357
v_filter(outbuf, bufs, row, rows);
359
Rast_put_d_row(outfile, outbuf);
360
G_debug(5, "write: %d", row);
363
G_percent(dst_w.rows, dst_w.rows, 2);
366
int main(int argc, char *argv[])
368
struct GModule *module;
371
struct Option *rastin, *rastout, *method,
372
*radius, *x_radius, *y_radius;
383
module = G_define_module();
384
G_add_keyword(_("raster"));
385
G_add_keyword(_("resample"));
386
G_add_keyword(_("kernel filter"));
387
module->description =
388
_("Resamples raster map layers using an analytic kernel.");
390
parm.rastin = G_define_standard_option(G_OPT_R_INPUT);
392
parm.rastout = G_define_standard_option(G_OPT_R_OUTPUT);
394
parm.method = G_define_option();
395
parm.method->key = "filter";
396
parm.method->type = TYPE_STRING;
397
parm.method->required = YES;
398
parm.method->multiple = YES;
399
parm.method->description = _("Filter kernel(s)");
400
parm.method->options = build_filter_list();
402
parm.radius = G_define_option();
403
parm.radius->key = "radius";
404
parm.radius->type = TYPE_DOUBLE;
405
parm.radius->required = NO;
406
parm.radius->multiple = YES;
407
parm.radius->description = _("Filter radius");
409
parm.x_radius = G_define_option();
410
parm.x_radius->key = "x_radius";
411
parm.x_radius->type = TYPE_DOUBLE;
412
parm.x_radius->required = NO;
413
parm.x_radius->multiple = YES;
414
parm.x_radius->description = _("Filter radius (horizontal)");
416
parm.y_radius = G_define_option();
417
parm.y_radius->key = "y_radius";
418
parm.y_radius->type = TYPE_DOUBLE;
419
parm.y_radius->required = NO;
420
parm.y_radius->multiple = YES;
421
parm.y_radius->description = _("Filter radius (vertical)");
423
flag.nulls = G_define_flag();
424
flag.nulls->key = 'n';
425
flag.nulls->description = _("Propagate NULLs");
427
if (G_parser(argc, argv))
430
if (parm.radius->answer) {
431
if (parm.x_radius->answer || parm.y_radius->answer)
432
G_fatal_error(_("%s= and %s=/%s= are mutually exclusive"),
433
parm.radius->key, parm.x_radius->key, parm.y_radius->key);
436
if (!parm.x_radius->answer && !parm.y_radius->answer)
437
G_fatal_error(_("Either %s= or %s=/%s= required"),
438
parm.radius->key, parm.x_radius->key, parm.y_radius->key);
439
if (!parm.x_radius->answer || !parm.y_radius->answer)
440
G_fatal_error(_("Both %s= and %s= required"),
441
parm.x_radius->key, parm.y_radius->key);
444
nulls = flag.nulls->answer;
446
f_x_radius = f_y_radius = 1e100;
449
const char *filter_arg = parm.method->answers[i];
450
const char *x_radius_arg = parm.radius->answer
451
? parm.radius->answers[i]
452
: parm.x_radius->answers[i];
453
const char *y_radius_arg = parm.radius->answer
454
? parm.radius->answers[i]
455
: parm.y_radius->answers[i];
456
const struct filter_type *type;
457
struct filter *filter;
459
if (!filter_arg && !x_radius_arg && !y_radius_arg)
462
if (!filter_arg || !x_radius_arg || !y_radius_arg)
463
G_fatal_error(_("Differing number of values for filter= and [xy_]radius="));
465
if (num_filters >= MAX_FILTERS)
466
G_fatal_error(_("Too many filters (max: %d)"), MAX_FILTERS);
468
filter = &filters[num_filters++];
469
type = find_method(filter_arg);
470
filter->func = type->func;
471
filter->x_radius = fabs(atof(x_radius_arg));
472
filter->y_radius = fabs(atof(y_radius_arg));
474
double rx = type->radius * filter->x_radius;
475
double ry = type->radius * filter->y_radius;
483
if (f_x_radius > 1e99 || f_y_radius > 1e99)
484
G_fatal_error(_("At least one filter must be finite"));
486
G_get_set_window(&dst_w);
488
/* set window to old map */
489
Rast_get_cellhd(parm.rastin->answer, "", &src_w);
491
/* enlarge source window */
493
double y0 = Rast_row_to_northing(0.5, &dst_w);
494
double y1 = Rast_row_to_northing(dst_w.rows - 0.5, &dst_w);
495
double x0 = Rast_col_to_easting(0.5, &dst_w);
496
double x1 = Rast_col_to_easting(dst_w.cols - 0.5, &dst_w);
497
int r0 = (int)floor(Rast_northing_to_row(y0 + f_y_radius, &src_w) - 0.1);
498
int r1 = (int)ceil(Rast_northing_to_row(y1 - f_y_radius, &src_w) + 0.1);
499
int c0 = (int)floor(Rast_easting_to_col(x0 - f_x_radius, &src_w) - 0.1);
500
int c1 = (int)ceil(Rast_easting_to_col(x1 + f_x_radius, &src_w) + 0.1);
502
src_w.south -= src_w.ns_res * (r1 - src_w.rows);
503
src_w.north += src_w.ns_res * (-r0);
504
src_w.west -= src_w.ew_res * (-c0);
505
src_w.east += src_w.ew_res * (c1 - src_w.cols);
506
src_w.rows = r1 - r0;
507
src_w.cols = c1 - c0;
510
row_scale = 2 + 2 * ceil(f_y_radius / src_w.ns_res);
511
col_scale = 2 + 2 * ceil(f_x_radius / src_w.ew_res);
513
/* allocate buffers for intermediate rows */
514
bufs = G_malloc(row_scale * sizeof(DCELL *));
515
for (i = 0; i < row_scale; i++)
516
bufs[i] = Rast_allocate_d_buf();
518
Rast_set_input_window(&src_w);
519
Rast_set_output_window(&dst_w);
521
inbuf = Rast_allocate_d_input_buf();
522
outbuf = Rast_allocate_d_output_buf();
524
infile = Rast_open_old(parm.rastin->answer, "");
525
outfile = Rast_open_new(parm.rastout->answer, DCELL_TYPE);
532
/* record map metadata/history info */
533
sprintf(title, "Filter resample by %s", parm.method->answer);
534
Rast_put_cell_title(parm.rastout->answer, title);
537
struct History history;
538
char buf_nsres[100], buf_ewres[100];
540
Rast_short_history(parm.rastout->answer, "raster", &history);
541
Rast_set_history(&history, HIST_DATSRC_1, parm.rastin->answer);
542
G_format_resolution(src_w.ns_res, buf_nsres, src_w.proj);
543
G_format_resolution(src_w.ew_res, buf_ewres, src_w.proj);
544
Rast_format_history(&history, HIST_DATSRC_2,
545
"Source map NS res: %s EW res: %s",
546
buf_nsres, buf_ewres);
547
Rast_command_history(&history);
548
Rast_write_history(parm.rastout->answer, &history);
551
/* copy color table from source map */
553
struct Colors colors;
555
if (Rast_read_colors(parm.rastin->answer, "", &colors) < 0)
556
G_fatal_error(_("Unable to read color table for %s"),
557
parm.rastin->answer);
558
Rast_mark_colors_as_fp(&colors);
559
Rast_write_colors(parm.rastout->answer, G_mapset(), &colors);