Affectation conditionnelle de valeurs aux cellules raster adjacentes?

12

J'ai un raster de valeur:

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)

À partir de ce raster, comment puis-je attribuer des valeurs (ou modifier des valeurs) aux 8 cellules adjacentes de la cellule actuelle selon cette illustration? J'ai placé un point rouge dans la cellule actuelle de cette ligne de code:

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

entrez la description de l'image ici

Ici, le résultat attendu sera:

entrez la description de l'image ici

où la valeur de la cellule actuelle (c'est-à-dire 5 dans le raster de valeurs) est remplacée par 0.

Globalement, les nouvelles valeurs pour les 8 cellules adjacentes doivent être calculées comme suit:

Nouvelle valeur = moyenne des valeurs des cellules contenues dans le rectangle rouge * distance entre la cellule actuelle (point rouge) et la cellule adjacente (c.-à-d. Sqrt (2) pour les cellules adjacentes en diagonale ou 1 sinon)

Mise à jour

Lorsque les limites des cellules adjacentes sont hors des limites du raster, je dois calculer de nouvelles valeurs pour les cellules adjacentes qui respectent les conditions. Les cellules adjacentes qui ne respectent pas les conditions seront égales à "NA".

Par exemple, si la position de référence est c (1,1) au lieu de c (5,5) en utilisant la notation [ligne, col], seule la nouvelle valeur dans le coin inférieur droit peut être calculée. Ainsi, le résultat attendu sera:

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

Par exemple, si la position de référence est c (3,1), seules les nouvelles valeurs dans les coins supérieur droit, droit et inférieur droit peuvent être calculées. Ainsi, le résultat attendu sera:

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

Voici ma première tentative en utilisant la fonction, focalmais j'ai du mal à créer un code automatique.

Sélectionnez les cellules adjacentes

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 cellule adjacente est située dans le coin supérieur gauche de la cellule actuelle

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 cellule adjacente est située dans le coin supérieur moyen de la cellule actuelle

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 cellule adjacente est située dans le coin supérieur gauche de la cellule actuelle

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 cellule adjacente est située dans le coin gauche de la cellule actuelle

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 cellule adjacente est située dans le coin droit de la cellule actuelle

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 cellule adjacente est située dans le coin inférieur gauche de la cellule actuelle

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 cellule adjacente est située dans le coin inférieur-milieu de la cellule actuelle

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 cellule adjacente est située dans le coin inférieur droit de la cellule actuelle

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
la source
+1 J'aimerais que toutes les questions soient bien cadrées! Vous recherchez une opération focale (statistiques de fenêtres mobiles)? Découvrez le rasterpackage de R et la focal()fonction (documentation p. 90): cran.r-project.org/web/packages/raster/raster.pdf
Aaron
Merci beaucoup Aaron pour vos conseils! En effet, la fonction focale semble être très utile mais je ne la connais pas. Par exemple, pour la cellule adjacente = 8 (figure dans le coin supérieur gauche), j'ai testé 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)). Comment puis-je obtenir le résultat uniquement pour les 8 cellules adjacentes de la cellule actuelle et pas pour tout le raster? Ici, le résultat devrait être: res <- matrix(c(7.42,0,0,0,0,0,0,0,0), nrow=3, ncol=3, byrow = T). Merci beaucoup !
Pierre
@Pierre Avez-vous besoin de calculer des valeurs adjacentes uniquement pour la ligne de position 5, col 5? Ou déplacer cette position de référence par exemple vers une nouvelle ligne de position de référence 6, col 6?
Guzmán
2
Pouvez-vous expliquer davantage (en modifiant votre question) comment vous devez calculer les valeurs adjacentes lorsque les limites des cellules adjacentes sont hors des limites du raster? Ex: ligne 1, col 1.
Guzmán
1
Vos exemples n'ont pas de sens. Dans le premier, si la position de référence est c (1,1), alors seul le coin inférieur droit c (2,2) obtiendra la nouvelle valeur mais vous avez montré que c (3,3) obtient la New_Value. De plus, le c (1,1) deviendra 0 et non c (2,2).
Farid Cheraghi

Réponses:

4

La fonction AssignValuesToAdjacentRasterCellsci-dessous renvoie un nouvel objet RasterLayer avec les valeurs souhaitées attribuées à partir de l' entrée raster d' origine . La fonction vérifie si les cellules adjacentes de la position de référence se trouvent dans les limites du raster. Il affiche également des messages si une limite est sortie. Si vous devez déplacer la position de référence, vous pouvez simplement écrire une itération changeant la position d'entrée en c ( i , j ).

Entrée de données

# 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)

Une fonction

# 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)      

}

Exécuter des exemples

# 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))

Exemples de tracé

# 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)

Exemple de figure

exempleFigure

Remarque: les NAvaleurs moyennes des globules blancs

Guzmán
la source
3

Pour un opérateur matriciel sur une petite matrice, cela a du sens et est traitable. Cependant, vous voudrez peut-être vraiment repenser votre logique lorsque vous appliquez une fonction comme celle-ci à un grand raster. Conceptuellement, cela ne suit pas vraiment dans une application générale. Vous parlez de ce que l'on appelle traditionnellement une statistique globale. Cependant, une statistique de bloc est par nature commençant à un coin du raster et remplaçant des blocs de valeurs, dans une taille de fenêtre spécifiée, par un opérateur. Normalement, ce type d'opérateur sert à l'agrégation de données. Il serait beaucoup plus facile à utiliser si vous envisagiez d'utiliser des conditions pour calculer la valeur centrale d'une matrice. De cette façon, vous pouvez facilement utiliser une fonction focale.

Gardez simplement à l'esprit que la fonction focale raster lit des blocs de données qui représentent les valeurs focales dans le voisinage défini en fonction de la matrice passée à l'argument w. Le résultat est un vecteur pour chaque quartier et le résultat de l'opérateur focal est affecté uniquement à la cellule focale et non au quartier entier. Considérez-le comme saisissant une matrice entourant une valeur de cellule, agissant dessus, attribuant une nouvelle valeur à la cellule puis se déplaçant vers la cellule suivante.

Si vous vous assurez que na.rm = FALSE, le vecteur représentera toujours le voisinage exact (c'est-à-dire le même vecteur de longueur) et sera contraint en un objet matriciel qui peut être opéré dans une fonction. Pour cette raison, vous pouvez simplement écrire une fonction qui prend le vecteur attendu, contraint dans une matrice, applique votre logique de notation de voisinage et attribue ensuite une seule valeur comme résultat. Cette fonction peut ensuite être passée à la fonction raster :: focal.

Voici ce qui se passerait dans chaque cellule sur la base d'une simple contrainte et d'une évaluation de la fenêtre focale. L'objet "w" serait essentiellement la même définition de matrice que l'on passerait l'argument w en focale. C'est ce qui définit la taille du vecteur de sous-ensemble dans chaque évaluation focale.

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) 

Maintenant, créez une fonction qui peut être appliquée à la focale applique la logique ci-dessus. Dans ce cas, vous pouvez affecter l'objet se comme valeur ou l'utiliser comme condition dans quelque chose comme "ifelse" pour attribuer une valeur basée sur une évaluation. J'ajoute l'instruction ifelse pour illustrer comment on évaluerait plusieurs conditions du voisinage et appliquerait une condition de position de matrice (notation de voisinage). Dans cette fonction factice, la coercition de x sur une matrice est complètement inutile et il suffit d'illustrer comment cela serait fait. On peut appliquer des conditions de notation de voisinage directement au vecteur, sans coercition matricielle, car la position dans le vecteur s'appliquerait à son emplacement dans la fenêtre focale et resterait fixe.

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)   
}  

Et appliquez-le à un raster

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
la source
2

Vous pouvez facilement mettre à jour les valeurs raster en sous-configurant le raster en utilisant la notation [row, col]. Notez simplement que la ligne et la colonne commencent à partir du coin supérieur gauche du raster; r [1,1] est l'indice de pixel supérieur gauche et r [2,1] est celui sous r [1,1].

entrez la description de l'image ici

# 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
la source