Terra的 `ifel()` 在多条件逻辑下会产生不一致的像素

编程语言 2026-07-11

我正在尝试为一个森林监测项目设计样本空间,使用一批生物测量、地貌和遥感栅格数据集,具体包括:通过数字航拍测绘得到的冠层高度、来自四波段航空影像的归一化差异植被指数、坡度、热负荷指数,以及来自激光雷达数字地形模型的高程;以及基于Landsat的 Pseudotsuga menziesii基面积覆盖百分比估算。这些数据集来自不同来源、具有多种空间分辨率。在对齐各栅格的范围、分辨率和原点后,我使用 "terra" 中的 ifel() 函数应用条件逻辑,以屏蔽掉那些不符合下列条件、因此不进入样本空间的像元:

  • 冠层高度 > 30英尺
  • 斜率 < 80%(0.8)
  • Pseudotsuga menziesii的基面积覆盖百分比 < 50%

虽然该函数在无错误地运行,但我检查输出时,栅格的波段似乎被不一致地屏蔽(见图)。

Example of inconsist inconsistently masked pixels

我是否把条件逻辑错误地应用到了 ifel()?在运行条件逻辑之前我是不是错过了某一步?这是不是重新采样到更高分辨率的产物?以下是我的可复现示例:

library(terra)

##Pseudotsuga menziesii basal area percent##
set.seed(71)
PSME<-rast(xmin=-122.5, xmax=-122, ymin=44.5, ymax=45.5, nrow=5, ncol=5, crs="epsg:4326")
values(PSME)<-runif(25, 0, 100)
rmv<-sample( 1:25, 11)
PSME[rmv]<-NA

##Heat Load Index#
set.seed(24)
HLI<-rast(xmin=-122.5, xmax=-122, ymin=44.5, ymax=45.5, nrow=8, ncol=8, crs="epsg:4326")
values(HLI)<-runif(64, -1, 1)

##Elevation##
set.seed(56)
ELEV<-rast(xmin=-122.5, xmax=-122, ymin=44.5, ymax=45.5, nrow=8, ncol=8, crs="epsg:4326")
values(ELEV)<-runif(64, 0, 5000)

##Slope percent##
set.seed(18)
SLOPE<-rast(xmin=-122.5, xmax=-122, ymin=44.5, ymax=45.5, nrow=8, ncol=8, crs="epsg:4326")
values(SLOPE)<-runif(64, 0, 1.5)

##NDVI##
set.seed(33)
NDVI<-rast(xmin=-122.5, xmax=-122, ymin=44.5, ymax=45.5, nrow=10, ncol=10, crs="epsg:4326")
values(NDVI)<-runif(100, -1, 1)

##Canopy Height##
set.seed(48)
CANOPY<-rast(xmin=-122.5, xmax=-122, ymin=44.5, ymax=45.5, nrow=10, ncol=10, crs="epsg:4326")
values(CANOPY)<-runif(100, 15, 30)

##Resampling Physiographic Data to resolution of tree canopy data##
TERRAIN<-c(SLOPE, ELEV, HLI)
TREES<-c(CANOPY, NDVI)
names(TREES)<-c("canopy", "ndvi")
TREES<-ifel(TREES$canopy<15|TREES$ndvi<0.2, NA, TREES)

TERRAIN_ds<-resample(TERRAIN, TREES)

##Resampling Biometric Data to resolution of tree canopy data#
PSME_ds<-resample(PSME, TREES)

####Concatenating the rasters##
SNC<-c(TREES, TERRAIN_ds, PSME_ds)
names(SNC)<-c("CANOPY", "NDVI", "SLOPE", "ELEV", "HLI", "PSME")

##Inspecting the input raster##
X11()
plot(SNC)

##Applying the conditional logic##
out<-ifel(SNC$CANOPY<30&SNC$PSME>0.5&SNC$SLOPE<0.8, SNC, NA)
names(out)<-c("CANOPY", "NDVI", "SLOPE", "ELEV", "HLI", "PSME")

##Inspecting the output##
X11()
plot(out)

解决方案

Sure enough, my musing in the comment above was the answer. It appears that existing NA values in a particular band are simply ignored in the conditional logic of ifel() so if the other band meet the criteria of the conditional statement, their pixel values will populated even if there is an NA for one of the bands that is part of the conditional statement that doesn't explicitly require the band to not be an NA. The code works as expected when the call to ifel() is changed to out<-ifel(SNC$CANOPY<30&SNC$PSME>0.5&SNC$SLOPE<0.8&not.na(SNC$PSME)&not.na(SNC$CANOPY)&not.na(SNC$NDVI), SNC, NA) Here is the correct output:

Correct Pixel Masking

以下是修正后的完整可复现示例:

# Source - https://stackoverflow.com/q/79905693
# Posted by Sean McKenzie
# Retrieved 2026-03-12, License - CC BY-SA 4.0

library(terra)

##Pseudotsuga menziesii basal area percent##
set.seed(71)
PSME<-rast(xmin=-122.5, xmax=-122, ymin=44.5, ymax=45.5, nrow=5, ncol=5, crs="epsg:4326")
values(PSME)<-runif(25, 0, 100)
rmv<-sample( 1:25, 11)
PSME[rmv]<-NA

##Heat Load Index#
set.seed(24)
HLI<-rast(xmin=-122.5, xmax=-122, ymin=44.5, ymax=45.5, nrow=8, ncol=8, crs="epsg:4326")
values(HLI)<-runif(64, -1, 1)

##Elevation##
set.seed(56)
ELEV<-rast(xmin=-122.5, xmax=-122, ymin=44.5, ymax=45.5, nrow=8, ncol=8, crs="epsg:4326")
values(ELEV)<-runif(64, 0, 5000)

##Slope percent##
set.seed(18)
SLOPE<-rast(xmin=-122.5, xmax=-122, ymin=44.5, ymax=45.5, nrow=8, ncol=8, crs="epsg:4326")
values(SLOPE)<-runif(64, 0, 1.5)

##NDVI##
set.seed(33)
NDVI<-rast(xmin=-122.5, xmax=-122, ymin=44.5, ymax=45.5, nrow=10, ncol=10, crs="epsg:4326")
values(NDVI)<-runif(100, -1, 1)

##Canopy Height##
set.seed(48)
CANOPY<-rast(xmin=-122.5, xmax=-122, ymin=44.5, ymax=45.5, nrow=10, ncol=10, crs="epsg:4326")
values(CANOPY)<-runif(100, 15, 30)

##Resampling Physiographic Data to resolution of tree canopy data##
TERRAIN<-c(SLOPE, ELEV, HLI)
TREES<-c(CANOPY, NDVI)
names(TREES)<-c("canopy", "ndvi")
TREES<-ifel(TREES$canopy<15|TREES$ndvi<0.2, NA, TREES)

TERRAIN_ds<-resample(TERRAIN, TREES)

##Resampling Biometric Data to resolution of tree canopy data#
PSME_ds<-resample(PSME, TREES)

####Concatenating the rasters##
SNC<-c(TREES, TERRAIN_ds, PSME_ds)
names(SNC)<-c("CANOPY", "NDVI", "SLOPE", "ELEV", "HLI", "PSME")

##Inspecting the input raster##
X11()
plot(SNC)

##Applying the conditional logic##
out<-ifel(SNC$CANOPY<30&SNC$PSME>0.5&SNC$SLOPE<0.8&not.na(SNC$PSME)&not.na(SNC$CANOPY)&not.na(SNC$NDVI), SNC, NA)
names(out)<-c("CANOPY", "NDVI", "SLOPE", "ELEV", "HLI", "PSME")

##Inspecting the output##
X11()
plot(out)
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章