Asignación condicional de valores a celdas ráster adyacentes?

12

Tengo un ráster de valor:

m <- matrix(c(2,4,5,5,2,8,7,3,1,6,
         5,7,5,7,1,6,7,2,6,3,
         4,7,3,4,5,3,7,9,3,8,
         9,3,6,8,3,4,7,3,7,8,
         3,3,7,7,5,3,2,8,9,8,
         7,6,2,6,5,2,2,7,7,7,
         4,7,2,5,7,7,7,3,3,5,
         7,6,7,5,9,6,5,2,3,2,
         4,9,2,5,5,8,3,3,1,2,
         5,2,6,5,1,5,3,7,7,2),nrow=10, ncol=10, byrow = T)
r <- raster(m)
extent(r) <- matrix(c(0, 0, 10, 10), nrow=2)
plot(r)
text(r)

Desde este ráster, ¿cómo puedo asignar valores (o cambiar valores) a las 8 celdas adyacentes de la celda actual de acuerdo con esta ilustración? Coloqué un punto rojo dentro de la celda actual de esta línea de código:

points(xFromCol(r, col=5), yFromRow(r, row=5),col="red",pch=16)

ingrese la descripción de la imagen aquí

Aquí, el resultado esperado será:

ingrese la descripción de la imagen aquí

donde el valor de la celda actual (es decir, 5 en el ráster de valor) se reemplaza por 0.

En general, los nuevos valores para las 8 celdas adyacentes deben calcularse de la siguiente manera:

Nuevo valor = promedio de los valores de celda contenidos en el rectángulo rojo * distancia entre la celda actual (punto rojo) y la celda adyacente (es decir, sqrt (2) para celdas diagonalmente adyacentes o 1 de lo contrario)

Actualizar

Cuando los límites para las celdas adyacentes están fuera de los límites de la trama, necesito calcular nuevos valores para las celdas adyacentes que respetan las condiciones. Las celdas adyacentes que no respetan las condiciones serán iguales a "NA".

Por ejemplo, si la posición de referencia es c (1,1) en lugar de c (5,5) utilizando la notación [fila, col], solo se puede calcular el nuevo valor en la esquina inferior derecha. Por lo tanto, el resultado esperado será:

     [,1] [,2] [,3]       
[1,] NA   NA   NA         
[2,] NA   0    NA         
[3,] NA   NA   New_value

Por ejemplo, si la posición de referencia es c (3,1), solo se pueden calcular los nuevos valores en las esquinas superior derecha, derecha e inferior derecha. Por lo tanto, el resultado esperado será:

     [,1] [,2] [,3]       
[1,] NA   NA   New_value         
[2,] NA   0    New_value         
[3,] NA   NA   New_value

Aquí está mi primer intento de usar la función, focalpero tengo algunas dificultades para hacer un código automático.

Seleccionar celdas adyacentes

mat_perc <- matrix(c(1,1,1,1,1,
                     1,1,1,1,1,
                     1,1,0,1,1,
                     1,1,1,1,1,
                     1,1,1,1,1), nrow=5, ncol=5, byrow = T)
cell_perc <- adjacent(r, cellFromRowCol(r, 5, 5), directions=mat_perc, pairs=FALSE, sorted=TRUE, include=TRUE)
r_perc <- rasterFromCells(r, cell_perc)
r_perc <- setValues(r_perc,extract(r, cell_perc))
plot(r_perc)
text(r_perc)

si la celda adyacente se encuentra en la esquina superior izquierda de la celda actual

focal_m <- matrix(c(1,1,NA,1,1,NA,NA,NA,NA), nrow=3, ncol=3, byrow = T)
focal_function <- function(x) mean(x,na.rm=T)*sqrt(2)
test <- as.matrix(focal(r_perc, focal_m, focal_function))

si la celda adyacente se encuentra en la esquina superior media de la celda actual

focal_m <- matrix(c(1,1,1,1,1,1,NA,NA,NA), nrow=3, ncol=3, byrow = T)
focal_function <- function(x) mean(x,na.rm=T)
test <- as.matrix(focal(r_perc, focal_m, focal_function))

si la celda adyacente se encuentra en la esquina superior izquierda de la celda actual

focal_m <- matrix(c(NA,1,1,NA,1,1,NA,NA,NA), nrow=3, ncol=3, byrow = T)
focal_function <- function(x) mean(x,na.rm=T)*sqrt(2)
test <- as.matrix(focal(r_perc, focal_m, focal_function))

si la celda adyacente se encuentra en la esquina izquierda de la celda actual

focal_m <- matrix(c(1,1,NA,1,1,NA,1,1,NA), nrow=3, ncol=3, byrow = T)
focal_function <- function(x) mean(x,na.rm=T)
test <- as.matrix(focal(r_perc, focal_m, focal_function))

si la celda adyacente se encuentra en la esquina derecha de la celda actual

focal_m <- matrix(c(NA,1,1,NA,1,1,NA,1,1), nrow=3, ncol=3, byrow = T)
focal_function <- function(x) mean(x,na.rm=T)
test <- as.matrix(focal(r_perc, focal_m, focal_function))

si la celda adyacente se encuentra en la esquina inferior izquierda de la celda actual

focal_m <- matrix(c(NA,NA,NA,1,1,NA,1,1,NA), nrow=3, ncol=3, byrow = T)
focal_function <- function(x) mean(x,na.rm=T)*sqrt(2)
test <- as.matrix(focal(r_perc, focal_m, focal_function))

si la celda adyacente se encuentra en la esquina inferior central de la celda actual

focal_m <- matrix(c(NA,NA,NA,1,1,1,1,1,1), nrow=3, ncol=3, byrow = T)
focal_function <- function(x) mean(x,na.rm=T)
test <- as.matrix(focal(r_perc, focal_m, focal_function))

si la celda adyacente se encuentra en la esquina inferior derecha de la celda actual

focal_m <- matrix(c(NA,NA,NA,NA,1,1,NA,1,1), nrow=3, ncol=3, byrow = T)
focal_function <- function(x) mean(x,na.rm=T)*sqrt(2)
test <- as.matrix(focal(r_perc, focal_m, focal_function))
Pierre
fuente
+1 ¡Desearía que todas las preguntas estuvieran tan bien enmarcadas! ¿Está buscando una operación focal (estadísticas de ventanas móviles)? Consulte el rasterpaquete de R y la focal()función (p. 90 documentación): cran.r-project.org/web/packages/raster/raster.pdf
Aaron
Muchas gracias Aaron por tu consejo! De hecho, la función focal parece ser muy útil, pero no estoy familiarizado con ella. Por ejemplo, para la celda adyacente = 8 (figura en la esquina superior izquierda), probé mat <- matrix(c(1,1,0,0,0,1,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0), nrow=5, ncol=5, byrow = T) f.rast <- function(x) mean(x)*sqrt(2) aggr <- as.matrix(focal(r, mat, f.rast)). ¿Cómo puedo obtener el resultado solo para las 8 celdas adyacentes de la celda actual y no para todo el ráster? En este caso, el resultado debería ser: res <- matrix(c(7.42,0,0,0,0,0,0,0,0), nrow=3, ncol=3, byrow = T). Muchas gracias !
Pierre
@Pierre ¿Necesita calcular valores adyacentes solo para la fila de posición 5, col 5? ¿O mover esta posición de referencia, por ejemplo, a una nueva posición de referencia fila 6, col 6?
Guzmán
2
¿Puede explicar más (editando su pregunta) sobre cómo necesita calcular los valores adyacentes cuando los límites de las celdas adyacentes están fuera de los límites ráster? Ej .: fila 1, col 1.
Guzmán
1
Ustedes ejemplos no tienen sentido. En el primero, si la posición de referencia es c (1,1), solo la parte inferior derecha c (2,2) obtendrá el nuevo valor, pero usted ha demostrado que c (3,3) obtiene el New_Value. Además, la c (1,1) se convertirá en 0, no en c (2,2).
Farid Cheraghi

Respuestas:

4

La AssignValuesToAdjacentRasterCellssiguiente función devuelve un nuevo objeto RasterLayer con los valores deseados asignados desde la entrada ráster original . La función verifica si las celdas adyacentes desde la posición de referencia están dentro de los límites ráster. También muestra mensajes si hay algún límite. Si necesita mover la posición de referencia, simplemente puede escribir una iteración cambiando la posición de entrada a c ( i , j ).

Entrada de datos

# Load packages
library("raster")

# Load matrix data
m <- matrix(c(2,4,5,5,2,8,7,3,1,6,
              5,7,5,7,1,6,7,2,6,3,
              4,7,3,4,5,3,7,9,3,8,
              9,3,6,8,3,4,7,3,7,8,
              3,3,7,7,5,3,2,8,9,8,
              7,6,2,6,5,2,2,7,7,7,
              4,7,2,5,7,7,7,3,3,5,
              7,6,7,5,9,6,5,2,3,2,
              4,9,2,5,5,8,3,3,1,2,
              5,2,6,5,1,5,3,7,7,2), nrow=10, ncol=10, byrow = TRUE)

# Convert matrix to RasterLayer object
r <- raster(m)

# Assign extent to raster
extent(r) <- matrix(c(0, 0, 10, 10), nrow=2)

# Plot original raster
plot(r)
text(r)
points(xFromCol(r, col=5), yFromRow(r, row=5), col="red", pch=16)

Función

# Function to assigning values to the adjacent raster cells based on conditions
# Input raster: RasterLayer object
# Input position: two-dimension vector (e.g. c(5,5))

AssignValuesToAdjacentRasterCells <- function(raster, position) {

  # Reference position
  rowPosition = position[1]
  colPosition = position[2]

  # Adjacent cells positions
  adjacentBelow1 = rowPosition + 1
  adjacentBelow2 = rowPosition + 2
  adjacentUpper1 = rowPosition - 1
  adjacentUpper2 = rowPosition - 2
  adjacentLeft1 = colPosition - 1 
  adjacentLeft2 = colPosition - 2 
  adjacentRight1 = colPosition + 1
  adjacentRight2 = colPosition + 2

  # Check if adjacent cells positions are out of raster positions limits
  belowBound1 = adjacentBelow1 <= nrow(raster)
  belowBound2 = adjacentBelow2 <= nrow(raster)
  upperBound1 = adjacentUpper1 > 0
  upperBound2 = adjacentUpper2 > 0
  leftBound1 = adjacentLeft1 > 0 
  leftBound2 = adjacentLeft2 > 0 
  rightBound1 = adjacentRight1 <= ncol(raster)
  rightBound2 = adjacentRight2 <= ncol(raster) 

  if(upperBound2 & leftBound2) {

    val1 = mean(r[adjacentUpper2:adjacentUpper1, adjacentLeft2:adjacentLeft1]) * sqrt(2)

  } else {

    val1 = NA

  }

  if(upperBound2 & leftBound1 & rightBound1) {

    val2 = mean(r[adjacentUpper1:adjacentUpper2, adjacentLeft1:adjacentRight1])

  } else {

    val2 = NA

  }

  if(upperBound2 & rightBound2) {

    val3 = mean(r[adjacentUpper2:adjacentUpper1, adjacentRight1:adjacentRight2]) * sqrt(2)

  } else {

    val3 = NA

  }

  if(upperBound1 & belowBound1 & leftBound2) {

    val4 = mean(r[adjacentUpper1:adjacentBelow1, adjacentLeft2:adjacentLeft1])

  } else {

    val4 = NA

  }

  val5 = 0

  if(upperBound1 & belowBound1 & rightBound2) {

    val6 = mean(r[adjacentUpper1:adjacentBelow1, adjacentRight1:adjacentRight2])

  } else {

    val6 = NA

  }

  if(belowBound2 & leftBound2) {

    val7 = mean(r[adjacentBelow1:adjacentBelow2, adjacentLeft2:adjacentLeft1]) * sqrt(2)

  } else {

    val7 = NA

  }

  if(belowBound2 & leftBound1 & rightBound1) {

    val8 = mean(r[adjacentBelow1:adjacentBelow2, adjacentLeft1:adjacentRight1])

  } else {

    val8 = NA

  }

  if(belowBound2 & rightBound2) {

    val9 = mean(r[adjacentBelow1:adjacentBelow2, adjacentRight1:adjacentRight2]) * sqrt(2)

  } else {

    val9 = NA

  }

  # Build matrix
  mValues = matrix(data = c(val1, val2, val3,
                            val4, val5, val6,
                            val7, val8, val9), nrow = 3, ncol = 3, byrow = TRUE)    

  if(upperBound1) {

    a = adjacentUpper1

  } else {

    # Warning message
    cat(paste("\n Upper bound out of raster limits!"))
    a = rowPosition
    mValues <- mValues[-1,]

  }

  if(belowBound1) {

    b = adjacentBelow1

  } else {

    # Warning message
    cat(paste("\n Below bound out of raster limits!"))
    b = rowPosition
    mValues <- mValues[-3,]

  }

  if(leftBound1) {

    c = adjacentLeft1

  } else {

    # Warning message
    cat(paste("\n Left bound out of raster limits!"))
    c = colPosition
    mValues <- mValues[,-1]

  }

  if(rightBound1) {

    d = adjacentRight1

  } else {

    # Warning
    cat(paste("\n Right bound out of raster limits!"))
    d = colPosition
    mValues <- mValues[,-3]

  }

  # Convert matrix to RasterLayer object
  rValues = raster(mValues)

  # Assign values to raster
  raster[a:b, c:d] = rValues[,]  

  # Assign extent to raster
  extent(raster) <- matrix(c(0, 0, 10, 10), nrow = 2)

  # Return raster with assigned values
  return(raster)      

}

Ejecutar ejemplos

# Run function AssignValuesToAdjacentRasterCells

# reference position (1,1)
example1 <- AssignValuesToAdjacentRasterCells(raster = r, position = c(1,1))

# reference position (1,5)
example2 <- AssignValuesToAdjacentRasterCells(raster = r, position = c(1,5))

# reference position (1,10)
example3 <- AssignValuesToAdjacentRasterCells(raster = r, position = c(1,10))

# reference position (5,1)
example4 <- AssignValuesToAdjacentRasterCells(raster = r, position = c(5,1))

# reference position (5,5)
example5 <- AssignValuesToAdjacentRasterCells(raster = r, position = c(5,5))

# reference position (5,10)
example6 <- AssignValuesToAdjacentRasterCells(raster = r, position = c(5,10))

# reference position (10,1)
example7 <- AssignValuesToAdjacentRasterCells(raster = r, position = c(10,1))

# reference position (10,5)
example8 <- AssignValuesToAdjacentRasterCells(raster = r, position = c(10,5))

# reference position (10,10)
example9 <- AssignValuesToAdjacentRasterCells(raster = r, position = c(10,10))

Trazar ejemplos

# Plot examples
par(mfrow=(c(3,3)))

plot(example1, main = "Position ref. (1,1)")
text(example1)
points(xFromCol(example1, col=1), yFromRow(example1, row=1), col="red", cex=2.5, lwd=2.5)

plot(example2, main = "Position ref. (1,5)")
text(example2)
points(xFromCol(example2, col=5), yFromRow(example2, row=1), col="red", cex=2.5, lwd=2.5)

plot(example3, main = "Position ref. (1,10)")
text(example3)
points(xFromCol(example3, col=10), yFromRow(example3, row=1), col="red", cex=2.5, lwd=2.5)

plot(example4, main = "Position ref. (5,1)")
text(example4)
points(xFromCol(example4, col=1), yFromRow(example4, row=5), col="red", cex=2.5, lwd=2.5)

plot(example5, main = "Position ref. (5,5)")
text(example5)
points(xFromCol(example5, col=5), yFromRow(example5, row=5), col="red", cex=2.5, lwd=2.5)

plot(example6, main = "Position ref. (5,10)")
text(example6)
points(xFromCol(example6, col=10), yFromRow(example6, row=5), col="red", cex=2.5, lwd=2.5)

plot(example7, main = "Position ref. (10,1)")
text(example7)
points(xFromCol(example7, col=1), yFromRow(example7, row=10), col="red", cex=2.5, lwd=2.5)

plot(example8, main = "Position ref. (10,5)")
text(example8)
points(xFromCol(example8, col=5), yFromRow(example8, row=10), col="red", cex=2.5, lwd=2.5)

plot(example9, main = "Position ref. (10,10)")
text(example9)
points(xFromCol(example9, col=10), yFromRow(example9, row=10), col="red", cex=2.5, lwd=2.5)

Ejemplo de la figura

ejemploFigura

Nota: los NAvalores medios de los glóbulos blancos

Guzmán
fuente
3

Para un operador de matriz en una matriz pequeña, esto tiene sentido y es manejable. Sin embargo, es posible que desee repensar realmente su lógica al aplicar una función como esta a un gran ráster. Conceptualmente, esto no sigue realmente en la aplicación general. Estás hablando de lo que tradicionalmente se ha denominado estadística de bloque. Sin embargo, una estadística de bloque es, por naturaleza, comenzando en una esquina del ráster y reemplazando bloques de valores, dentro de un tamaño de ventana especificado, con un operador. Normalmente este tipo de operador es para agregar datos. Sería considerablemente más manejable si pensara en términos de uso de condiciones para calcular el valor central de una matriz. De esta manera, podría usar fácilmente una función focal.

Solo tenga en cuenta que la función focal de la trama está leyendo en bloques de datos que representan los valores focales en el vecindario definido en función de la matriz pasada al argumento w. El resultado es un vector para cada vecindario y el resultado del operador focal se asigna solo a la celda focal y no a todo el vecindario. Piense en ello como agarrar una matriz que rodea el valor de una celda, operar sobre ella, asignar un nuevo valor a la celda y luego pasar a la siguiente celda.

Si se asegura de que na.rm = FALSE, entonces el vector siempre representará la vecindad exacta (es decir, el mismo vector de longitud) y se convertirá en un objeto de matriz que se puede operar dentro de una función. Debido a esto, simplemente puede escribir una función que tome el vector esperado, coaccione en una matriz, aplique su lógica de notación de vecindad y luego asigne un único valor como resultado. Esta función se puede pasar a la función ráster :: focal.

Esto es lo que sucedería en cada celda con base en una simple coerción y evaluación de la ventana focal. El objeto "w" sería esencialmente la misma definición de matriz que uno pasaría el argumento w en foco. Esto es lo que define el tamaño del vector de subconjunto en cada evaluación focal.

w=c(5,5)
x <- runif(w[1]*w[2])
x[25] <- NA
print(x)
( x <- matrix(x, nrow=w[1], ncol=w[2]) ) 
( se <- mean(x, na.rm=TRUE) * sqrt(2) )
ifelse( as.vector(x[(length(as.vector(x)) + 1)/2]) <= se, 1, 0) 

Ahora cree una función que se pueda aplicar a focal aplica la lógica anterior. En este caso, puede asignar el objeto se como valor o usarlo como condición en algo como "ifelse" para asignar un valor basado en una evaluación. Estoy agregando la declaración ifelse para ilustrar cómo uno evaluaría múltiples condiciones del vecindario y aplicaría una condición de posición de matriz (notación de vecindario). En esta función ficticia, la coerción de x a una matriz es completamente innecesaria y solo existe para ilustrar cómo se haría. Se pueden aplicar condiciones de notación de vecindad directamente al vector, sin coerción matricial, porque la posición en el vector se aplicaría a su ubicación en la ventana focal y permanecería fija.

f.rast <- function(x, dims=c(5,5)) {
  x <- matrix(x, nrow=dims[1], ncol=dims[2]) 
  se <- mean(x, na.rm=TRUE) * sqrt(2)
  ifelse( as.vector(x[(length(as.vector(x)) + 1)/2]) <= se, 1, 0)   
}  

Y aplicarlo a una trama

library(raster)
r <- raster(nrows=100, ncols=100)
  r[] <- runif( ncell(r) )
  plot(r)

( r.class <- focal(r, w = matrix(1, nrow=w[1], ncol=w[2]), fun=f.rast) )
plot(r.class)  
Jeffrey Evans
fuente
2

Puede actualizar fácilmente los valores de ráster al subdividir el ráster utilizando la notación [row, col]. Solo tenga en cuenta que la fila y la columna comienzan desde la esquina superior izquierda del ráster; r [1,1] es el índice de píxeles superior izquierdo y r [2,1] es el que está debajo de r [1,1].

ingrese la descripción de la imagen aquí

# the function to update raster cell values
focal_raster_update <- function(r, row, col) {
  # copy the raster to hold the temporary values
  r_copy <- r
  r_copy[row,col] <- 0
  #upper left
  r_copy[row-1,col-1] <- mean(r[(row-2):(row-1),(col-2):(col-1)]) * sqrt(2)
  #upper mid
  r_copy[row-1,col] <- mean(r[(row-2):(row-1),(col-1):(col+1)])
  #upper right
  r_copy[row-1,col+1] <- mean(r[(row-2):(row-1),(col+1):(col+2)]) * sqrt(2)
  #left
  r_copy[row,col-1] <- mean(r[(row-1):(row+1),(col-2):(col-1)])
  #right
  r_copy[row,col+1] <- mean(r[(row-1):(row+1),(col+1):(col+2)])
  #bottom left
  r_copy[row+1,col-1] <- mean(r[(row+1):(row+2),(col-2):(col-1)]) * sqrt(2)
  #bottom mid
  r_copy[row+1,col] <- mean(r[(row+1):(row+2),(col-1):(col+1)])
  #bottom right
  r_copy[row+1,col+1] <- mean(r[(row+1):(row+2),(col+1):(col+2)]) * sqrt(2)
  return(r_copy)
}
col <- 5
row <- 5
r <- focal_raster_update(r,row,col)

dev.set(1)
plot(r)
text(r,digits=2)
Farid Cheraghi
fuente