Atribuição condicional de valores para células raster adjacentes?

12

Eu tenho uma varredura 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)

A partir desta varredura, como posso atribuir valores (ou alterar valores) às 8 células adjacentes da célula atual, de acordo com esta ilustração? Coloquei um ponto vermelho dentro da célula atual a partir desta linha de código:

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

insira a descrição da imagem aqui

Aqui, o resultado esperado será:

insira a descrição da imagem aqui

onde o valor da célula atual (ou seja, 5 na varredura de valor) é substituído por 0.

No geral, os novos valores para as 8 células adjacentes devem ser calculados da seguinte maneira:

Novo valor = média dos valores das células contidas no retângulo vermelho * distância entre a célula atual (ponto vermelho) e a célula adjacente (por exemplo, sqrt (2) para células adjacentes na diagonal ou 1 caso contrário)

Atualizar

Quando os limites das células adjacentes estão fora dos limites da varredura, preciso calcular novos valores para as células adjacentes que respeitam as condições. As células adjacentes que não respeitam as condições serão iguais a "NA".

Por exemplo, se a posição de referência for c (1,1) em vez de c (5,5) usando a notação [linha, col], apenas o novo valor no canto inferior direito pode ser calculado. Assim, o resultado esperado será:

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

Por exemplo, se a posição de referência for c (3,1), apenas os novos valores nos cantos superior direito, direito e inferior direito poderão ser calculados. Assim, o resultado esperado será:

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

Aqui está minha primeira tentativa de fazer isso usando a função, focalmas tenho alguma dificuldade para criar um código automático.

Selecionar células 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)

se a célula adjacente estiver localizada no canto superior esquerdo da célula atual

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 a célula adjacente estiver localizada no canto médio superior da célula atual

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 a célula adjacente estiver localizada no canto superior esquerdo da célula atual

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 a célula adjacente estiver localizada no canto esquerdo da célula atual

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 a célula adjacente estiver localizada no canto direito da célula atual

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 a célula adjacente estiver localizada no canto inferior esquerdo da célula atual

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 a célula adjacente estiver localizada no canto inferior central da célula atual

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 a célula adjacente estiver localizada no canto inferior direito da célula atual

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
fonte
+1 Gostaria que todas as perguntas fossem bem estruturadas! Você está procurando uma operação focal (mover estatísticas da janela)? Confira de R rasterpacote e a focal()função: (p 90 documentação.) Cran.r-project.org/web/packages/raster/raster.pdf
Aaron
Muito obrigado Aaron pelo seu conselho! De fato, a função focal parece ser muito útil, mas não estou familiarizada com ela. Por exemplo, para a célula adjacente = 8 (figura no canto superior esquerdo), testei 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)). Como posso obter o resultado apenas das 8 células adjacentes da célula atual e não de toda a varredura? Aqui, o resultado deve ser: res <- matrix(c(7.42,0,0,0,0,0,0,0,0), nrow=3, ncol=3, byrow = T). Muito obrigado !
Pierre
@Pierre Você precisa calcular valores adjacentes apenas para a linha de posição 5, col 5? Ou mova esta posição de referência, por exemplo, para uma nova linha 6 da posição de referência , coluna 6?
Guzmán
2
Você pode explicar mais (editando sua pergunta) sobre como você precisa calcular os valores adjacentes quando os limites das células adjacentes estão fora dos limites de varredura? Por exemplo: linha 1, coluna 1.
Guzmán
1
Seus exemplos não fazem sentido. No primeiro, se a posição de referência for c (1,1), apenas o canto inferior direito c (2,2) receberá o novo valor, mas você mostrou que c (3,3) está obtendo o New_Value. Além disso, c (1,1) se tornará 0 e não c (2,2).
Farid Cheraghi

Respostas:

4

A função AssignValuesToAdjacentRasterCellsabaixo retorna um novo objeto RasterLayer com os valores desejados atribuídos a partir da entrada raster original . A função verifica se as células adjacentes da posição de referência estão dentro dos limites de varredura. Também exibe mensagens se algum limite estiver fora. Se você precisar mover a posição de referência, basta escrever uma iteração alterando a posição de entrada para c ( i , j ).

Entrada de dados

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

Função

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

}

Executar exemplos

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

Exemplos de plotagem

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

Exemplo de figura

exampleFigure

Nota:NA valores médios de células brancas

Guzmán
fonte
3

Para um operador de matriz em uma matriz pequena, isso faz sentido e é tratável. No entanto, convém repensar sua lógica ao aplicar uma função como essa a uma grande varredura. Conceitualmente, isso realmente não acompanha na aplicação geral. Você está falando sobre o que tradicionalmente é chamado de estatística de bloco. No entanto, uma estatística de bloco é por natureza iniciada em um canto da varredura e substituindo blocos de valores, dentro de um tamanho de janela especificado, por um operador. Normalmente esse tipo de operador é para agregar dados. Seria consideravelmente mais tratável se você pensasse em termos de condições para calcular o valor central de uma matriz. Dessa forma, você pode facilmente usar uma função focal.

Lembre-se de que a função focal de varredura está lendo em blocos de dados que representam os valores focais na vizinhança definida com base na matriz passada para o argumento w. O resultado é um vetor para cada vizinhança e o resultado do operador focal é atribuído apenas à célula focal e não à vizinhança inteira. Pense nisso como pegar uma matriz em torno de um valor de célula, operando nela, atribuindo um novo valor à célula e depois passando para a próxima célula.

Se você garantir que na.rm = FALSE, o vetor sempre representará a vizinhança exata (ou seja, o mesmo vetor de comprimento) e será coagido a um objeto de matriz que pode ser operado dentro de uma função. Por causa disso, você pode simplesmente escrever uma função que leva o vetor esperado, coage em uma matriz, aplica sua lógica de notação de vizinhança e depois atribui um único valor como resultado. Essa função pode ser passada para a função raster :: focal.

Aqui está o que estaria acontecendo em cada célula com base em uma simples coerção e avaliação da janela focal. O objeto "w" seria essencialmente a mesma definição de matriz que seria aprovada no argumento w em focal. É isso que define o tamanho do vetor de subconjunto em cada avaliação 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) 

Agora, crie uma função que possa ser aplicada ao focal e aplique a lógica acima. Nesse caso, você pode atribuir o objeto se como o valor ou usá-lo como uma condição em algo como "ifelse" para atribuir um valor com base em uma avaliação. Estou adicionando a declaração ifelse para ilustrar como alguém avaliaria várias condições da vizinhança e aplicaria uma condição de posição da matriz (notação da vizinhança). Nesta função fictícia, a coerção de x para uma matriz é completamente desnecessária e existe apenas para ilustrar como isso seria feito. Pode-se aplicar condições de notação de vizinhança diretamente ao vetor, sem coerção da matriz, porque a posição no vetor se aplicaria à sua localização na janela focal e permaneceria fixa.

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 aplicá-lo a uma varredura

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
fonte
2

Você pode atualizar facilmente os valores de varredura subconjuntos de varredura usando a notação [linha, col]. Observe que a linha e a coluna começam no canto superior esquerdo da varredura; r [1,1] é o índice de pixels superior esquerdo er [2,1] é o abaixo de r [1,1].

insira a descrição da imagem aqui

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