2

I want to process my data (classified single-band raster) according to a specific idea. Pixels that do have less than 2 neighbors of the same class (eg. with the value 1) shall be removed and classified as NA. It seems a lot trickier than I expected this part to be. I imagined it might be similar to the GameOfLife (Cellular Automata). But I could not implement it with a similar methodology of GameOfLife (I tried it like in the examples of the R package 'focal'). I also tried to use focal in general, which seems not to work good as well, as there are restrictions to the function that can be used (several number as input, one number as output) and I also did not manage to think through how to fix the problem with the outer cells of the moving window. Now I tried to use the function adjacend in which I can get the cell-index of 4 or 8 neighbor-cells. This makes it very inefficient though and can not stop thinking that there must be a better alternative.

Has anyone a good idea how I could tackle the problem to change the value of a cell of a specific class in my raster to NA, if it has less then 2 cells with the same classification that it is connected to?

I also tried to work with the mean function in the focal-package, but that approach is way too coarse for my needs.

Original classification (white = NA, green = 0, red = 1, blue =2): enter image description here

I want to get rid of the single pixels of only one class, lets say class one which is shown in red in my plot. I don't want the function to delete any values of other classes though, like class 0 (green) or class 2 (blue).


After trying several methods (game of life, adjacent of the raster package, focal of the raster package, clump of the raster package) I figured out that the clump command was the easiest to implement. I came quite far with a function that could be called in focal (from @Spacedman), but it did not work without problems. Clump seems to be an easy way and the calculation is fast. If you want to perform the command only on special classes, like me, you have to define them as a band first and you can later use raster calculations to get the result you want to achieve.

Classification after using the clump command with clumps < 3 of the red class deleted: enter image description here

The difference might look small, but it's important for my computation.

  • 1
    focal can do this. The values passed to the function are the values in the focla window round each pixel, so you count the number of each classification and conditionally return NA or maybe TRUE or FALSE or anything else and use that. Edit your question, set up some sample data (like a 5x5 matrix) and show us the outputs you expect. – Spacedman Jun 19 '18 at 19:48
  • Thanks for the help again! So it should work with focal? Might an alternative to get the index of all cells with a specific value and check with the adjacent - function if they have at least one neighbor-cell with the same value? Or might that be not easily doable or a too intensive computation? – Li12 Jun 20 '18 at 15:06
  • 2
    Take a look at this thread: gis.stackexchange.com/questions/130993/… – Jeffrey Evans Jun 20 '18 at 23:40
  • Thanks Jeffrey Evans, I have spotted this function and even this thread. But I think I cannot use clump for only one class, can I? Except I would define all other classes as NA and lose them as well... But thanks for the link. Could have been really helpful! – Li12 Jun 21 '18 at 10:25
  • Thanks Jeffrey Evans. I managed to get it work with clump. Thanks a lot for your tip. I created different bands out of the classes, performed clump on the classes that I wanted to edit and then calculated them together again. It was fast and easy. – Li12 Jun 22 '18 at 8:49
2

I set up a simple raster with these values:

> as.matrix(r)
     [,1] [,2] [,3] [,4]
[1,]    0    0    3    3
[2,]    0    0    0    3
[3,]    3    3    0    3
[4,]    0    3    0    0

I want to replace all values that have more than three "3"s with NA in the eight neighbours. So I need a 3x3 weight matrix:

> w = matrix(1,3,3)
> w
     [,1] [,2] [,3]
[1,]    1    1    1
[2,]    1    1    1
[3,]    1    1    1

Now to define the function. It gets passed the 9 values focussed on each pixel. The fifth value will be the raster value in the centre. This function counts the "3"s an if there's more than three of them (using x[-5] to not count the central value) and returns NA, otherwise returns the original value (x[5]):

> fun = function(x){b=x[-5];ifelse(sum(b==3)>3,NA,x[5])}

So let's see:

> as.matrix(focal(r,w,fun))
     [,1] [,2] [,3] [,4]
[1,]   NA   NA   NA   NA
[2,]   NA    0   NA   NA
[3,]   NA    3   NA   NA
[4,]   NA   NA   NA   NA

Apart from the edge effect, this looks right. Those two cells at [3,2] and [2,2] have three or fewer 3s, the other two cells at [3,3] and [2,3] have more.

  • Thanks again. I think this approach is quite good. I came quite far but could not make it work completely. With this function it worked several times, but some times not. I adapted it so, only pixels of a certain class (1) would be changed. I adapted the code so far: w = matrix(c(NA, 1, NA, 1, 0, 1, NA, 1, NA), 3, 3) x <- matrix(c(0, 0, 0, 0, 1, 0, 0, 0, 0), 3, 3) fun = function(x){ b <- x[-5] if (x[5] == 1){ if (sum(b==1)>2){ x[5]=NA } } return(x[5]) } l <- focal(matrix, w, fun) – Li12 Jun 22 '18 at 9:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.