我想使用 .stratifiedSample 从具有四个类别(标记为 0-3,表示光谱索引一致)的集成层创建训练数据,然后使用该输出来训练 .smileRandomForest 分类器并对输入图像进行分类。
代码运行,但 .classify 步骤生成一个我无法可视化且难以检查的图像对象(.bandNames() 和 .display() 对其不起作用)。因此,虽然可视化会产生错误,但我认为问题可能来自于我误用了采样或分类器。
有人可以建议如何纠正我使用 .stratifiedSample 准备输入以便与 .smileRandomForest 一起使用的方式吗?
提前致谢。
可视化误差为: EEException:Classifier.train,参数“inputProperties”:类型无效。 预期类型:列表。 实际类型:图像<[NDWI_water, MNDWI_water, AWEI_water, B8A, B12, NDWI_reclass, MNDWI_reclass, AWEI_reclass, B8A_NIR_reclass, B12_SWIR_reclass, Ensemble_Vote]>.
我的代码如下:
#Imports
import numpy
import ee
import geemap
ee.Authenticate()
ee.Initialize()
#Constants
i_date = '2024-02-10'
f_date = '2024-03-01'
lon = -80.205595
lat = 25.748059
geometry = ee.Geometry({
'type': 'Polygon',
'coordinates': [[ #lat, lon
[-80.267610, 25.796023], #Top left,
[-80.263518, 25.730725], #Lower left,
[-80.121574, 25.730725], #Lower right,
[-80.121574, 25.810281], #Top right
]],
})
geometry_bounds = geometry.bounds()
point_centroid= geometry.centroid(maxError=1)
# Define functions
def addNDWI(image):
ndwi = (image.select('B3').subtract(image.select('B8A'))).divide(image.select('B3').add(image.select('B8A'))).rename('NDWI_water')
return image.addBands(ndwi)
def addMNDWI(image):
mndwi = (image.select('B3').subtract(image.select('B11'))).divide(image.select('B3').add(image.select('B11'))).rename('MNDWI_water')
return image.addBands(mndwi)
def addAWEI(image):
awei = (((image.select('B2').add(image.select('B3').multiply(ee.Number(2.5)))).subtract(
(image.select('B8A').add(image.select('B11'))).multiply(ee.Number(1.5))).subtract(
image.select('B12').multiply(ee.Number(.25)))).divide(
image.select('B2').add(image.select('B3')).add(image.select('B8A')).add(image.select('B11')).add(image.select('B12')))).rename('AWEI_water')
return image.addBands(awei)
def reclass_band(image, bandname, threshold, newname):
bandtoreclass = image.select(bandname)
reclassed = bandtoreclass.where(bandtoreclass.lt(threshold), 0).where(bandtoreclass.gte(threshold), 1).rename(newname)
return image.addBands(reclassed)
def tally(image):
tallied = (image.select('NDWI_reclass')).add(image.select('MNDWI_reclass')).add(image.select('AWEI_reclass')).toUint8().rename('Ensemble_Vote')
return image.addBands(tallied)
# Get imagery (Sentinel 2)
s2_filtered = ee.ImageCollection('COPERNICUS/S2_SR').filterBounds(geometry).filterDate(i_date, f_date)
s2_clipped_collection = ee.ImageCollection(s2_filtered.map(lambda image: image.clip(geometry)))
# Add spectral indices
s2_ndwi_added = s2_clipped_collection.map(addNDWI)
s2_mndwi_added = s2_ndwi_added.map(addMNDWI)
s2_just_ndwi_mndwi_awei = s2_mndwi_added.map(addAWEI)
# Reclass indices to binary
s2_ndwi_reclass_added = s2_just_ndwi_mndwi_awei.map(lambda image: reclass_band(image, 'NDWI_water', 0, 'NDWI_reclass'))
s2_mndwi_reclass_added = s2_ndwi_reclass_added.map(lambda image: reclass_band(image, 'MNDWI_water', 0, 'MNDWI_reclass'))
s2_awei_reclass_added = s2_mndwi_reclass_added.map(lambda image: reclass_band(image, 'AWEI_water', 0, 'AWEI_reclass'))
s2_B8A_reclass_added = s2_awei_reclass_added.map(lambda image: reclass_band(image, 'B8A', 850, 'B8A_NIR_reclass'))
s2_B12_reclass_added = s2_B8A_reclass_added.map(lambda image: reclass_band(image, 'B12', 800, 'B12_SWIR_reclass'))
# Calculate ensemble vote (0-3, how many indices agree a pixel is water)
s2_tallied = s2_B12_reclass_added.map(tally)
# Get one image to test the sampling method on.
s2_List_b=ee.ImageCollection(s2_tallied).toList(s2_tallied.size());
s2_single_Image_b=ee.Image(ee.List(s2_List_b).get(1));
s2_single_Image_b
### The following does not produce expected output:
# Collect stratified random points in the four ensemble classes (0-3)
stratified = s2_single_Image_b.stratifiedSample(
numPoints=1000,
classBand='Ensemble_Vote',
geometries=True
)
# Attempt to create classifier, train using points collected from the ensemble layer, and then classify an image using the trained classifier
RF_classifier = ee.Classifier.smileRandomForest(numberOfTrees=30)
Training_RF_classifier = RF_classifier.train(
features=stratified,
classProperty="Ensemble_Vote",
inputProperties=s2_single_Image_b,
)
classifiedImage = s2_single_Image_b.classify(Training_RF_classifier)
# none of these produce information:
band_names = classifiedImage.bandNames()
display('Band names:', band_names)
classifiedImage.propertyNames()
# View
m.addLayer(classifiedImage.select('Ensemble_Vote'), viz2, 'Classified')
m
#EEException: Classifier.train, argument 'inputProperties': Invalid type.
#Expected type: List<String>.
#Actual type: Image<[NDWI_water, MNDWI_water, AWEI_water, B8A, B12, NDWI_reclass, MNDWI_reclass, #AWEI_reclass, B8A_NIR_reclass, B12_SWIR_reclass, Ensemble_Vote]>.
inputProperties
的 stratifiedSample
参数应该是乐队列表,您当前拥有图像。您可以将 s2_single_Image_b
替换为 s2_single_Image_b.bandNames()
。
此外,您可能会考虑在分类时仅选择感兴趣的波段 - 您可能不想使用
'MSK_SNWPRB'
、'MSK_CLDPRB'
等波段。因此您甚至可以将 s2_single_Image_b.select('B.*', 'NDWI_reclass', 'MNDWI_reclass', 'AWEI_reclass', 'MNDWI_reclass', 'AWEI_reclass').bandNames()
作为 inputProperties
的输入。
您的
stratified
变量返回一个没有元素的特征集合。 dropNulls
上的 stratifiedSample
选项默认为 true,会丢弃任何波段被屏蔽的样本。对于该图像,您可能有一些空带,最终不会返回任何特征。将 dropNulls
设置为 False
,或在采样前删除这些条带。