1

I'd like to filter a large raster, but only run the filter if the center cell of the window is a specific value. Essentially I'd like to remove some speckle (false positives) from an image (pixels of 0 or 1), but only run the filter if window center is 1.

# create some raster data
library(raster)
r <- raster(ncols=12, nrows=12)
set.seed(0)
r[] <- round(runif(ncell(r))*0.7 )
plot(r)

enter image description here

# custom filter
w=matrix(1,5,5)
gameOfLife <- function(x) {
f <- focal(x, w=w, pad=TRUE, padValue=0)
#  window with with less than 5 cells die
x[f < 5] <- 0
# window with 5 or more cells live
x[f >= 5] <- 1
x
}

plot(gameOfLife(r))

enter image description here

The 2 circled cells, above, meet the criteria (having at least 5 values of 1 around them) but were initially a 0 and I want them to remain a 0. Thus, the filter only applies if the center value is already a 1.

Hope that makes sense. Many thanks in advance

ThrushJacket
  • 145
  • 9

1 Answers1

2

It is possible, by passing a function to the fun argument of focal. Functions passed on like that should operate on numeric vectors. If you use a 5x5 weight matrix, the center cell will be the 13th element of that numeric vector. You can use this information to check whether your center cell is 0 in the beginning and return values conditionally.

r[sample(1:ncell(r), 30)] <- NA # add NA values to example raster

gol_fun <- function(x) {

  # more general definition of center cell for weight matrices with odd side size
  center <- x[ceiling(length(x)/2)]

  if (center==0 | is.na(center)) { # handle NA values
    return(center)
  } 

  ncells <- sum(x, na.rm=TRUE)

  if (ncells<5) { #  window with with less than 5 cells die
    return(0)
  } else if (ncells >= 5) { # window with 5 or more cells live
    return(1)
  }
}




gameOfLife <- function(x) {
  f <- focal(x, w=w, fun=gol_fun, pad=TRUE, padValue=0)
}


plot(r)
plot(gameOfLife(r))
joberlin
  • 321
  • 1
  • 4
  • Many thanks joberlin! One last Q, if you're up for it. My raster is obviously a bit more complex than the example scenario and has NAs that break the function. I've been trying on my own (unsuccessfuly) to tweak your code to work through NAs but having trouble. r[12,8] <- NA – ThrushJacket Jan 11 '17 at 15:49
  • Comment timed out I tried adding an extra if else after the initial if clause to skip if NA too. Def feeling thick b/c I can't fix this one bit... – ThrushJacket Jan 11 '17 at 16:11
  • I've edited my answer so that the function now includes handling NA values and adds NA values to the example raster. – joberlin Jan 12 '17 at 07:41