Assegnazione condizionale dei valori alle celle raster adiacenti?


12

Ho un valore raster:

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)

Da questo raster, come posso assegnare valori (o modificare valori) alle 8 celle adiacenti della cella corrente secondo questa illustrazione? Ho inserito un punto rosso all'interno della cella corrente da questa riga di codice:

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

inserisci qui la descrizione dell'immagine

Qui, il risultato atteso sarà:

inserisci qui la descrizione dell'immagine

dove il valore della cella corrente (ovvero 5 nel valore raster) viene sostituito con 0.

Complessivamente, i nuovi valori per le 8 celle adiacenti devono essere calcolati come segue:

Nuovo valore = media dei valori di cella contenuti nel rettangolo rosso * distanza tra la cella corrente (punto rosso) e la cella adiacente (ovvero sqrt (2) per celle adiacenti in diagonale o 1 altrimenti)

Aggiornare

Quando i limiti per le celle adiacenti sono fuori dai limiti del raster, devo calcolare nuovi valori per le celle adiacenti che rispettano le condizioni. Le celle adiacenti che non rispettano le condizioni saranno uguali a "NA".

Ad esempio, se la posizione di riferimento è c (1,1) anziché c (5,5) utilizzando la notazione [riga, colonna], è possibile calcolare solo il nuovo valore nell'angolo in basso a destra. Pertanto, il risultato atteso sarà:

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

Ad esempio, se la posizione di riferimento è c (3,1), è possibile calcolare solo i nuovi valori negli angoli in alto a destra, a destra e in basso a destra. Pertanto, il risultato atteso sarà:

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

Ecco il mio primo tentativo in questo senso utilizzando la funzione focalma ho qualche difficoltà a creare un codice automatico.

Seleziona celle adiacenti

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)

se la cella adiacente si trova nell'angolo in alto a sinistra della cella corrente

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

se la cella adiacente si trova nell'angolo medio-alto della cella corrente

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

se la cella adiacente si trova nell'angolo in alto a sinistra della cella corrente

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

se la cella adiacente si trova nell'angolo sinistro della cella corrente

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

se la cella adiacente si trova nell'angolo destro della cella corrente

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

se la cella adiacente si trova nell'angolo in basso a sinistra della cella corrente

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

se la cella adiacente si trova nell'angolo in basso al centro della cella corrente

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

se la cella adiacente si trova nell'angolo in basso a destra della cella corrente

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

+1 Vorrei che tutte le domande fossero così ben inquadrate! Stai cercando un'operazione focale (spostare le statistiche della finestra)? Dai un'occhiata al rasterpacchetto di R e alla focal()funzione (p. 90 documentazione): cran.r-project.org/web/packages/raster/raster.pdf
Aaron

Grazie mille Aaron per il tuo consiglio! In effetti, la funzione focale sembra essere molto utile ma non ne ho familiarità. Ad esempio, per la cella adiacente = 8 (figura nell'angolo in alto a sinistra), ho testato 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)). Come posso ottenere il risultato solo per le 8 celle adiacenti della cella corrente e non per tutto il raster? Qui, il risultato dovrebbe essere: res <- matrix(c(7.42,0,0,0,0,0,0,0,0), nrow=3, ncol=3, byrow = T). Molte grazie !
Pierre,

@Pierre Devi calcolare i valori adiacenti solo per la riga di posizione 5, col 5? Oppure spostare questa posizione di riferimento ad esempio in una nuova posizione di riferimento riga 6, col 6?
Guzmán,

2
Puoi spiegarci di più (modificando la tua domanda) su come è necessario calcolare i valori adiacenti quando i limiti per le celle adiacenti sono fuori dai limiti raster? Ad esempio: riga 1, col 1.
Guzmán,

1
I tuoi esempi non hanno senso. Nel primo, se la posizione di riferimento è c (1,1), allora solo in basso a destra c (2,2) otterrà il nuovo valore, ma hai dimostrato che c (3,3) sta ottenendo il New_Value. Inoltre, c (1,1) diventerà 0 non c (2,2).
Farid Cheraghi,

Risposte:


4

La funzione AssignValuesToAdjacentRasterCellsseguente restituisce un nuovo oggetto RasterLayer con i valori desiderati assegnati dall'input raster originale . La funzione verifica se le celle adiacenti dalla posizione di riferimento si trovano all'interno dei limiti raster. Visualizza anche i messaggi se qualche limite è fuori. Se è necessario spostare la posizione di riferimento, è possibile semplicemente scrivere un'iterazione modificando la posizione di input in c ( i , j ).

Inserimento dati

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

Funzione

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

}

Esegui esempi

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

Traccia esempi

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

Figura esempio

exampleFigure

Nota: i globuli bianchi significano NAvalori


3

Per un operatore di matrice su una matrice di piccole dimensioni ciò ha senso ed è trattabile. Tuttavia, potresti voler ripensare davvero la tua logica quando applichi una funzione come questa a un grande raster. Concettualmente, questo in realtà non tiene traccia dell'applicazione generale. Stai parlando di quella che è stata tradizionalmente definita una statistica a blocchi. Tuttavia, una statistica a blocchi è per natura a partire da un angolo del raster e sostituisce blocchi di valori, all'interno di una dimensione di finestra specificata, con un operatore. Normalmente questo tipo di operatore serve per aggregare i dati. Sarebbe notevolmente più trattabile se si pensasse in termini di utilizzo delle condizioni per calcolare un valore centrale di una matrice. In questo modo potresti facilmente usare una funzione focale.

Basta tenere presente che la funzione focale raster sta leggendo in blocchi di dati che rappresentano i valori focali nel vicinato definito in base alla matrice passata all'argomento w. Il risultato è un vettore per ogni quartiere e il risultato dell'operatore focale è assegnato solo alla cella focale e non all'intero quartiere. Pensa a come afferrare una matrice che circonda un valore di cella, operando su di essa, assegnando un nuovo valore alla cella e spostandosi alla cella successiva.

Se ti assicuri che na.rm = FALSE, il vettore rappresenterà sempre il vicinato esatto (cioè lo stesso vettore di lunghezza) e sarà forzato in un oggetto matrice che può essere operato all'interno di una funzione. Per questo motivo, puoi semplicemente scrivere una funzione che accetta il vettore previsto, si coercita in una matrice, applica la logica della notazione di vicinato e quindi assegna un singolo valore come risultato. Questa funzione può quindi essere passata alla funzione raster :: focal.

Ecco cosa succederebbe in ogni cellula basandosi su una semplice coercizione e valutazione della finestra focale. L'oggetto "w" sarebbe essenzialmente la stessa definizione di matrice che si passerebbe l'argomento w in focale. Questo è ciò che definisce la dimensione del vettore del sottoinsieme in ciascuna valutazione 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) 

Ora crea una funzione che può essere applicata a focal applica la logica sopra. In questo caso è possibile assegnare l'oggetto se come valore o usarlo come condizione in qualcosa come "ifelse" per assegnare un valore basato su una valutazione. Sto aggiungendo la dichiarazione ifelse per illustrare come si valuterebbero più condizioni del vicinato e applicare una condizione di posizione della matrice (notazione del vicinato). In questa funzione fittizia la coercizione di x in una matrice è del tutto superflua e lì solo per illustrare come sarebbe stata fatta. Si possono applicare le condizioni di notazione di vicinato direttamente al vettore, senza coercizione di matrice, perché la posizione nel vettore si applicherebbe alla sua posizione nella finestra focale e rimarrebbe fissa.

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

E applicalo a 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)  

2

È possibile aggiornare facilmente i valori raster sottoponendo il raster alla notazione [riga, colonna]. Basta notare che riga e colonna iniziano dall'angolo in alto a sinistra del raster; r [1,1] è l'indice di pixel in alto a sinistra e r [2,1] è quello sotto r [1,1].

inserisci qui la descrizione dell'immagine

# 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)
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.