在 python 中将 ee.Image.stratifiedSample 与 .smileRandomForest、.train 和 .classify 一起使用?

问题描述 投票:0回答:1

我想使用 .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]>.

python random-forest google-earth-engine geemap
1个回答
0
投票

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
,或在采样前删除这些条带。

© www.soinside.com 2019 - 2024. All rights reserved.