[R-sig-Geo] Function to smooth grids using n x n window moving average (low-pass filter)
Paul Hiemstra
p.hiemstra at geo.uu.nl
Mon Jun 23 14:58:42 CEST 2008
Dear list,
I recently implemented a smoothing algorithm that could be interesting
for other people. It smooths a grid by calculating an average for a n x
n window. The input is a SpatialGrid/PixelsDataframe. For a 3x3 window
the algorithm creates 8 shifted matrices in addition to the original
matrix (derived from the grid-object). Adding up these 9 matrices and
dividing them by 9 gives the smoothed matrix. The output is a
SpatialGridDataFrame. Because the algorithm uses just a few simple
matrix operations it is very fast and scalable to large grid-objects.
Maybe the code could be added to the sp-package (Edzer or Roger?)?
This is the code, just three functions. I also provided a small but
functioning example at the bottom:
shift_matrix = function(m, row, col) {
nrow = dim(m)[1]
ncol = dim(m)[2]
if(row > 0) m = rbind(matrix(rep(NA,abs(row)*ncol),
abs(row),ncol),m[1:(nrow-row),])
if(row < 0) m =
rbind(m[-(row-1):nrow,],matrix(rep(NA,abs(row)*ncol), abs(row),ncol))
if(col > 0) m = cbind(matrix(rep(NA,abs(col)*nrow), nrow,
abs(col)),m[,1:(ncol-col)])
if(col < 0) m =
cbind(m[,-(col-1):ncol],matrix(rep(NA,abs(col)*nrow), nrow, abs(col)))
m
}
smooth_matrix = function(m, kernel_size = 3) {
row_nums = rep(floor(kernel_size/2): -floor(kernel_size/2), each =
kernel_size)
col_nums = rep(floor(kernel_size/2): -floor(kernel_size/2), kernel_size)
out = matrix(rep(0,dim(m)[1]*dim(m)[2]), dim(m))
for(i in 1:length(row_nums)) {
out = out + shift_matrix(m, row_nums[i], col_nums[i])
}
return(out / (kernel_size * kernel_size))
}
smooth_grid = function(grd, zcol, kernel_size = 3, add_to_name =
"_smooth") {
if(!fullgrid(grd)) fullgrid(grd) = TRUE
grd[[paste(zcol,add_to_name, sep = "")]] =
as.vector(smooth_matrix(as.matrix(grd[zcol]), kernel_size = kernel_size))
grd
}
## Example script
library(gstat)
data(meuse)
coordinates(meuse) = ~x+y
data(meuse.grid)
gridded(meuse.grid) = ~x+y
meuse.grid$log.zinc = idw(log(zinc)~1, meuse, meuse.grid)$var1.pred
meuse.grid = smooth_grid(meuse.grid, "log.zinc", kernel_size = 3)
spplot(meuse.grid, c("log.zinc","log.zinc_smooth"))
cheers,
Paul
ps The system i run:
R version 2.7.0 (2008-04-22)
i486-pc-linux-gnu
locale:
LC_CTYPE=en_US.UTF-8;LC_NUMERIC=C;LC_TIME=en_US.UTF-8;LC_COLLATE=en_US.UTF-8;LC_MONETARY=C;LC_MESSAGES=en_US.UTF-8;LC_PAPER=en_US.UTF-8;LC_NAME=C;LC_ADDRESS=C;LC_TELEPHONE=C;LC_MEASUREMENT=en_US.UTF-8;LC_IDENTIFICATION=C
attached base packages:
[1] stats graphics grDevices utils datasets methods base
other attached packages:
[1] gstat_0.9-45 sp_0.9-25
loaded via a namespace (and not attached):
[1] grid_2.7.0 lattice_0.17-6 tools_2.7.0
--
Drs. Paul Hiemstra
Department of Physical Geography
Faculty of Geosciences
University of Utrecht
Heidelberglaan 2
P.O. Box 80.115
3508 TC Utrecht
Phone: +31302535773
Fax: +31302531145
http://intamap.geo.uu.nl/~paul
More information about the R-sig-Geo
mailing list