【Earth Engine】基于GEE对季节性地物进行分类(多源数据叠图+监督分类)

1 简介与摘要

最近导师给了个新方向,其中要用到长时间和大空间的高分辨率遥感影像分类数据,其中有一类还是季节性池塘。。
这。。这么多要求。。实在没有免费的并且符合要求的数据。。
于是我寻思还是自己做吧,所以马上学习了下GEE。。。

在第一阶段,我使用landsat合成全年的影像,比如landsat5,只用到1-7波段,输入分类器的波段实在太少了,分类精度很低,而且根本提不出来季节性的地物。
第二阶段,我终于意识到用全年合成影像是不行的,于是乎我合成了春夏秋冬四季影像,每个季节影像分别包含1-7波段,再加上自己加的一些乱七八糟的产品,输入分类器的波段大概有50+,效果也很拔群。

下面就大概说说。

2 采样点的选取

因为是监督学习,肯定要监督,所以需要我们手动设置采样点作为数据集,当然不手动也可以,可以在asset导入你的点shp数据作为数据集。
我试过导入点shp训练,但是因为影像源不同,所以得到的精度也很差,所以这里主要将手动添加点。
首先,先把地图调到你的研究区为中心。打开地图左上角的Geometry Imports,点里面的new layer新建图层,一个分类建一个layer。可以看到图里我建了4个分类,也就是4个图层。
在这里插入图片描述
进到里面点这个Edit Layer Properties
在这里插入图片描述
然后把Name里面填上分类名,Import as改成Feature Collection
在这里插入图片描述
然后添加Property,出来一个窗口让你填properties参数,property对应字段,value对应值。比如我这里就设置点数据的名称叫water,字段value对应的值为1。调好这些参数后可以把颜色调一下方便看。
在这里插入图片描述
最后点OK即可。
然后可以根据这种方法创建几个分类。我这里就创建了4个分类。
在这里插入图片描述
分类都创建完就可以开始选点了。我的目标研究区是江苏,点了将近两千个点。对了,好像超过2000个点会报错,所以选点需要慎重。
在这里插入图片描述
当然,你也可以先随便选几个,再根据显示出来的图层再增加点以确保分类和图像的匹配。下面是我显示的图层,classifed是分类结果,fall是秋季影像,summer是夏季影像,spring是春季影像,winter是冬季影像。
在这里插入图片描述
关于这些影像,在下面的代码细说。

3 合成多季节多波段影像

首先,我要制作一个包含多波段的影像,每个波段作为随机森林分类器的一个feature输入,提升feature的丰富度以保证我们的分类精度。
甭管这个波段有用没用,我把这波段合成输进去就是赢了!

首先,我从GEE直接抄了个landsat5用的云掩膜函数,如下:

// cloud mask
var cloudMaskL457 = function(image) {
  var qa = image.select('pixel_qa');
  // If the cloud bit (5) is set and the cloud confidence (7) is high
  // or the cloud shadow bit is set (3), then it's a bad pixel.
  var cloud = qa.bitwiseAnd(1 << 5)
                  .and(qa.bitwiseAnd(1 << 7))
                  .or(qa.bitwiseAnd(1 << 3));
  // Remove edge pixels that don't occur in all bands
  var mask2 = image.mask().reduce(ee.Reducer.min());
  return image.updateMask(cloud.not()).updateMask(mask2);
};

然后我再写一些乱七八糟可能用得到的指数,比如NDWI、MNDWI、EWI什么的。
因为我主要是提取季节性池塘,所以我用到的水体指数可能会多点。
关于植被指数(NDWI)和建筑指数(NDBI),我的想法是有植被和建筑覆盖的地方肯定不会是池塘嘛,这两个就当作是反指标了。

// indicators
// landsat 5
function NDWI(img){
  var nir = img.select('B4');
  var green = img.select('B2');
  var ndwi = img.expression(
    '(B2-B4)/(B2+B4)',
    {
      'B4':nir,
      'B2':green
    });
    return ndwi;
}

function MNDWI(img){
  var swir1 = img.select('B5');
  var green = img.select('B2');
  var mndwi = img.expression(
    '(B2-B5)/(B2+B5)',
    {
      'B5':swir1,
      'B2':green
    });
    return mndwi;
}

function EWI(img){
  var swir1 = img.select('B5')
  var nir = img.select('B4');
  var green = img.select('B2');
  var ewi = img.expression(
    '(B2-B4-B5)/(B2+B4+B5)',
    {
      'B5':swir1,
      'B4':nir,
      'B2':green
    });
    return ewi;
}

function NDBI(img){
  var swir1 = img.select('B5');
  var nir = img.select('B4');
  var ndbi = img.expression(
    '(B5-B4)/(B5+B4)',
    {
      'B5':swir1,
      'B4':nir
    });
    return ndbi;
}

function NDVI(img){
  var nir = img.select('B4');
  var red = img.select('B3');
  var ndvi = img.expression(
    '(B4-B3)/(B4+B3)',
    {
      'B4':nir,
      'B3':red
    });
    return ndvi;
}

然后,选取我们的影像数据源,这里我用的是landsat5,如果更换数据源的话云掩膜函数和指标计算也要一并调整。影像源代码如下:

// satellite data
var l8_col = ee.ImageCollection("LANDSAT/LT05/C01/T1_SR");

然后,开始合成季节影像。这里我做的分类是1990年的,但是因为landsat的重返周期太长了,尺度稍微大点的话会碰上很多云,掩膜的话又都掩膜没了,所以我使用1989到1991三年的合成,其中冬是12月1日到3月1日、春是3月1日到6月1日、夏是6月1日到9月1日、秋是9月1日到12月1日,可以根据自己的需求调整。另外,为了避免云掩膜出现的孔洞,所以我用unmask函数把孔洞赋值为0以填补出现的孔洞。具体代码如下:

// winter
var img_winter = ee.List([])
for (var i=1989; i<1991; i++){
  var winter = ee.Image(l8_col.filterBounds(roi)
                              .filterDate(i+"-12-1", (i+1)+"-3-1")
                              .filter(ee.Filter.lt('CLOUD_COVER', 100))
                              .map(cloudMaskL457)
                              .mean());
}
img_winter = img_winter.add(winter);
img_winter = ee.ImageCollection(img_winter).mean().unmask(0);
// spring
var img_spring = ee.List([])
for (var i=1989; i<1991; i++){
  var spring = ee.Image(l8_col.filterBounds(roi)
                              .filterDate(i+"-3-1", i+"-6-1")
                              .filter(ee.Filter.lt('CLOUD_COVER', 100))
                              .map(cloudMaskL457)
                              .mean());
}
img_spring = img_spring.add(spring);
img_spring = ee.ImageCollection(img_spring).mean().unmask(0);
// summer
var img_summer = ee.List([])
for (var i=1989; i<1991; i++){
  var summer = ee.Image(l8_col.filterBounds(roi)
                              .filterDate(i+"-6-1", i+"-9-1")
                              .filter(ee.Filter.lt('CLOUD_COVER', 100))
                              .map(cloudMaskL457)
                              .mean());
}
img_summer = img_summer.add(summer);
img_summer = ee.ImageCollection(img_summer).mean().unmask(0);
// fall
var img_fall = ee.List([])
for (var i=1989; i<1991; i++){
  var fall = ee.Image(l8_col.filterBounds(roi)
                              .filterDate(i+"-9-1", i+"-12-1")
                              .filter(ee.Filter.lt('CLOUD_COVER', 100))
                              .map(cloudMaskL457)
                              .mean());
}
img_fall = img_fall.add(fall);
img_fall = ee.ImageCollection(img_fall).mean().unmask(0);

为了确保分类成功率,我引入GEE中现成的几个产品。这些产品可以根据需要灵活调整,这里就不多介绍了。依然地,使用unmask函数填补掩膜孔洞,代码如下:

// referring image data
var impervious = ee.Image("Tsinghua/FROM-GLC/GAIA/v10").clip(roi).unmask(-1);
var water = ee.Image('JRC/GSW1_2/GlobalSurfaceWater').clip(roi).unmask(-1);

之前合成了landsat5季节影像,别忘记上面我们写下了各种指数,这里就要使用这些合成影像计算指数生成各指数的波段,并进行命名,代码如下:

var ndwi_wi = NDWI(img_winter).rename('ndwi_wi');
var mndwi_wi = MNDWI(img_winter).rename('mndwi_wi');
var ewi_wi = EWI(img_winter).rename('ewi_wi');
var ndbi_wi = NDBI(img_winter).rename('ndbi_wi');
var ndvi_wi = NDVI(img_spring).rename('ndvi_wi');
var ndwi_sp = NDWI(img_spring).rename('ndwi_sp');
var mndwi_sp = MNDWI(img_spring).rename('mndwi_sp');
var ewi_sp = EWI(img_spring).rename('ewi_sp');
var ndbi_sp = NDBI(img_spring).rename('ndbi_sp');
var ndvi_sp = NDVI(img_spring).rename('ndvi_sp');
var ndwi_su = NDWI(img_summer).rename('ndwi_su');
var mndwi_su = MNDWI(img_summer).rename('mndwi_su');
var ewi_su = EWI(img_summer).rename('ewi_su');
var ndbi_su = NDBI(img_summer).rename('ndbi_su');
var ndvi_su = NDVI(img_summer).rename('ndvi_su');
var ndwi_fa = NDWI(img_fall).rename('ndwi_fa');
var mndwi_fa = MNDWI(img_fall).rename('mndwi_fa');
var ewi_fa = EWI(img_fall).rename('ewi_fa');
var ndbi_fa = NDBI(img_fall).rename('ndbi_fa');
var ndvi_fa = NDVI(img_fall).rename('ndvi_fa');

上面的指数是作为波段的形式。然后我们把引用的产品中的波段也提出并进行重命名,代码如下:

var imperchange = impervious.select('change_year_index').rename('imperchange');
var waterocc = water.select('occurrence').unmask(-1).rename('waterocc');
var waterchange = water.select('change_norm').unmask(-150).rename('waterchange');

然后,我们从每幅季节合成影像中提取波段1-7,并且加入同一幅影像,代码如下:

// add bands into images
var image = img_winter.addBands([ndwi_wi, mndwi_wi, ewi_wi, ndbi_wi, ndvi_wi,
                                  img_spring.select('B1').rename('B1_sp'), img_spring.select('B2').rename('B2_sp'), img_spring.select('B3').rename('B3_sp'), img_spring.select('B4').rename('B4_sp'), img_spring.select('B5').rename('B5_sp'),
                                  ndwi_sp, mndwi_sp, ewi_sp, ndbi_sp, ndvi_sp,
                                  img_summer.select('B1').rename('B1_su'), img_summer.select('B2').rename('B2_su'), img_summer.select('B3').rename('B3_su'), img_summer.select('B4').rename('B4_su'), img_summer.select('B5').rename('B5_su'),
                                  ndwi_su, mndwi_su, ewi_su, ndbi_su, ndvi_su,
                                  img_fall.select('B1').rename('B1_fa'), img_fall.select('B2').rename('B2_fa'), img_fall.select('B3').rename('B3_fa'), img_fall.select('B4').rename('B4_fa'), img_fall.select('B5').rename('B5_fa'),
                                  ndwi_fa, mndwi_fa, ewi_fa, ndbi_fa, ndvi_fa,
                                  imperchange, waterocc, waterchange]);

如果我没算错,现在我们得到了一个含有51波段的超级无敌厚的影像。

4 分类器参数设置

上面我们合成了一个超级无敌厚的影像,我们现在就需要选取我们分类器需要输入的波段了。
反正我尽量全输进来了(其他三个季节只输入波段1到5,省点笔墨,大家知道意思就行了),代码如下:

// select bands
var bands = ['B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7',
            'ndwi_wi', 'mndwi_wi', 'ewi_wi', 'ndbi_wi', 'ndvi_wi',
            'B1_sp', 'B2_sp', 'B3_sp', 'B4_sp', 'B5_sp',
            'ndwi_sp', 'mndwi_sp', 'ewi_sp', 'ndbi_sp', 'ndvi_sp',
            'B1_su', 'B2_su', 'B3_su', 'B4_su', 'B5_su',
            'ndwi_su', 'mndwi_su', 'ewi_su', 'ndbi_su', 'ndvi_su',
            'B1_fa', 'B2_fa', 'B3_fa', 'B4_fa', 'B5_fa',
            'ndwi_fa', 'mndwi_fa', 'ewi_fa', 'ndbi_fa', 'ndvi_fa',
            'imperchange', 'waterocc', 'waterchange'];

监督学习的分类器怎么能没用训练集呢?总之,我们把数据分割成训练集和测试集。首先第一步用merge函数把各分类合成一整个集合,然后它们的波段是value,然后把训练集和测试集按90%和10%分开。代码如下:

// set training data
var SP = Water.merge(Ponds).merge(Mud).merge(Others);
var training = image.select(bands).sampleRegions({
  collection: SP,
  properties:['value'],
  scale: 30
});
// set varified data
var withRandom = training.randomColumn('random');
var split = 0.9;
var trainingP = withRandom.filter(ee.Filter.lt('random', split)); // 90% training data
var testingP = withRandom.filter(ee.Filter.gte('random', split)); // 10% verified data

然后选择分类器,并且设置一下参数(这里用的是随机森林,树选100个,就不详细介绍其他分类器了)。代码如下:

// set classifier para
var classifier = ee.Classifier.smileRandomForest(100).train({ 
  features: trainingP, 
  classProperty: "value", 
  inputProperties: bands 
}); 

5 监督分类的实现与分类精度计算

OK,万事俱备,开始通过训练集训练模型。以下代码会得到一个分类后的影像。

// classification
var class_img = image.select(bands).classify(classifier);

光有分类结果不行,还需要知道分类精度。把测试集也分类一下,然后用GEE自带的函数求转移矩阵并且计算overall accuracy和kappa,这些会打印在console里,代码如下:

// testing
var test = testingP.classify(classifier);

// confusion matrix
var confusionMatrix = test.errorMatrix('value', 'classification')
print('confusionMatrix',confusionMatrix);//面板上显示混淆矩阵
print('overall accuracy', confusionMatrix.accuracy());//面板上显示总体精度
print('kappa accuracy', confusionMatrix.kappa());//面板上显示kappa值

最后,当然要显示季节影像和分类后的影像,RGB波段组合还是色带什么的可以根据需要自行调整。如果选择手点的话,可以先随便点几个点,然后再根据显示的季节影像和分类影像再增加数据集,慢慢达到精度,代码如下:

// show images
var class_color = {
  min: 0,
  max: 3,
  palette: ['ffffff', '0049ff', '00ffca', '97422c']
};

Map.addLayer(img_winter.clip(roi.geometry()), {bands: ["B4", "B3", "B2"], min:0, max:2000}, "winter");
Map.addLayer(img_spring.clip(roi.geometry()), {bands: ["B4", "B3", "B2"], min:0, max:2000}, "spring");
Map.addLayer(img_summer.clip(roi.geometry()), {bands: ["B4", "B3", "B2"], min:0, max:2000}, "summer");
Map.addLayer(img_fall.clip(roi.geometry()), {bands: ["B4", "B3", "B2"], min:0, max:2000}, "fall");
Map.addLayer(class_img.clip(roi.geometry()), class_color, 'classifed')

Map.centerObject(roi, 7)

最后是保存在云盘里,千篇一律,代码如下:

Export.image.toDrive({
        image:  class_img,//分类结果
        description: 'test_season_1990',//文件名
        folder: '111',
        scale: 30,//分辨率
        region: roi,//区域
        crs:"EPSG:4326",
        maxPixels:1e13//此处值设置大一些,防止溢出
      });

6 影像的显示与结果

下面是我合成的冬季影像,做了假彩色处理:
在这里插入图片描述
沿海那一块黑色了不要担心,是影像缺失所以代码用unmask把它补起来了。由于我们输入的波段特别多,所以问题不大,其他波段的信息丰富即可。
下面是我合成的秋季影像,同样的沿海地区也出现黑色,这种斑点状的一般是云掩膜后的unmask填补。
在这里插入图片描述
如果这种unmask填补的范围太大,大到影响分类结果,可以考虑拉长时间范围,即使用更多年份的影像进行合成。
下面是我跑出来的分类结果,不知道啥原因它others类好像不怎么显示,不过导入到GIS后是正常的。
在这里插入图片描述
最后我们看看console打印出的精度:

在这里插入图片描述
第一栏是混淆矩阵,第二栏是总体分类精度,第三栏是卡帕系数。通过混淆矩阵可以发现2容易给分到1里,总体上看还行,卡帕系数达到0.77。
最后在tasks里run到云盘里再下载即可。
在这里插入图片描述

7 后记

刚开始学习GEE,可能有些地方不太专业不太科学,希望诸位同行前辈不吝赐教或者有什么奇妙的想法可以和我共同探讨一下。可以在csdn私信我或者联系我邮箱(chinshuuichi@qq.com),不过还是希望大家邮箱联系我,csdn私信很糟糕而且我上csdn也很随缘。

如果觉得有帮助,希望大家能打赏支持一下(我的乞讨码在下面)~
-----------------------分割线(以下是乞讨内容)-----------------------
在这里插入图片描述

<think>好的,用户现在的问题是关于如何在使用Sentinel-2数据进行土地利用分类时增强显示效果。我需要先理解用户的需求和背景。用户可能已经有一定的遥感数据处理经验,但在像增强方面需要指导。他们可能在进行分类时遇到地物区分度不高的问题,或者希望提高分类的准确性。 首先,我得考虑Sentinel-2的数据特性。Sentinel-2有13个波段,包括可见光、近红外和短波红外,空间分辨率从10米到60米不等。用户可能需要知道如何有效利用这些波段来增强不同地物类型的显示差异。 接下来,用户提到的“增强显示”可能有种含义。可能是指视觉上的增强,比如通过波段组合或像拉伸使像更易于目视解译;也可能是处理上的增强,比如通过指数计算或主成分分析来提高分类模型的输入特征质量。 我需要分步骤来回答这个问题。首先,数据预处理是基础,确保辐射校正和大气校正已经完成,这样才能保证后续分析的准确性。然后,波段组合的选择,比如自然色、假彩色,这些常见的组合可以帮助突出植被、水体等地物。 接下来,光谱指数是非常有用的工具。比如NDVI用于植被,NDWI用于水体,NDBI用于建筑区域。这些指数能增强特定地物的表现,帮助分类。另外,像主成分分析(PCA)和纹理特征提取这些方法可以进一步减少数据冗余并增强空间特征。 时间序列分析也是Sentinel-2的优势,因为它有较高的重访周期。用户如果结合时相数据,可以捕捉地物的季节变化,提升分类精度,比如区分常绿和落叶植被。 在机器学习分类阶段,特征工程是关键。用户可能需要知道如何组合不同的指数和波段作为输入特征,以及如何调整分类器的参数。此外,后处理步骤如形态学滤波可以优化分类结果,去除噪声。 可视化方面,使用不同的颜色表来区分地类,加矢量边界或DEM数据也能帮助视觉判断。用户可能需要具体的工具推荐,比如QGIS或ArcGIS中的拉伸工具,以及如何在GEE平台上进行这些处理。 最后,注意事项部分需要提醒用户关于分辨率的一致性,云掩膜的重要性,以及样本数据的质量。这些都是实际应用中容易遇到的问题,提前指出可以帮助用户避免常见错误。 总结一下,用户的需求可能不仅限于显示增强,而是希望通过一系列预处理、特征增强和分类优化步骤来提高土地利用分类的准确性。因此,回答需要结构清晰,逐步引导用户从数据准备到后处理的整个流程,同时提供实用建议和工具推荐,确保他们能够有效应用这些方法。</think>以下是针对哨兵2号(Sententinel-2)数据进行土地利用分类时增强显示和分类效果的分步指南,结合波段组合、光谱指数和可视化技巧: --- ### **1. 数据预处理(增强基础)** - **辐射校正与大气校正** 使用Sen2Cor工具(ESA官方插件)或Google Earth EngineGEE)内置算法,将原始数据转换为地表反射率,消除大气干扰。 $$ \text{地表反射率} = \frac{\text{表观反射率}}{\text{大气衰减因子}} $$ - **空间分辨率统一** 将20m/60m波段(如短波红外SWIR、气溶胶波段)重采样至10m分辨率(双线性插值),保持数据一致性。 --- ### **2. 波段组合优化(目视增强)** - **自然色显示(True Color)** 组合波段:$B4$(红)、$B3$(绿)、$B2$(蓝) → 接近真实色彩,适合人工解译城乡边界。 - **假彩色显示(False Color)** 组合波段:$B8$(近红外)、$B4$(红)、$B3$(绿) → **植被高亮**(红色区域为植被)。 - **短波红外组合** 组合波段:$B12$(SWIR)、$B8A$(窄近红外)、$B4$(红) → 增强**水体、建筑、裸土**区分。 --- ### **3. 光谱指数增强(特征提取)** - **植被分类增强** - **NDVI**(归一化植被指数): $$ \text{NDVI} = \frac{B8 - B4}{B8 + B4} $$ 植被越茂密,值越接近$1$;裸土/水体接近$0$或负值。 - **NDWI**(归一化水体指数): $$ \text{NDWI} = \frac{B3 - B8}{B3 + B8} $$ 水体值>0.2,植被/裸土值较低。 - **建筑与裸土增强** - **NDBI**(归一化建筑指数): $$ \text{NDBI} = \frac{B11 - B8}{B11 + B8} $$ 建筑区域值>0,植被负值。 - **SAVI**(土壤调节植被指数): $$ \text{SAVI} = \frac{(B8 - B4)(1 + L)}{B8 + B4 + L} \quad (L=0.5) $$ 减少裸土背景干扰。 --- ### **4. 空间与纹理特征增强** - **主成分分析(PCA)** 对波段数据降维,保留主要信息,减少冗余噪声。 - **纹理特征提取** 使用灰度共生矩阵(GLCM)计算**对比度、熵、同质性**,增强农田、森林的纹理差异。 (工具推荐:QGIS的`Orfeo Toolbox`或GEE的`glcmTexture`函数) --- ### **5. 时间序列分析** - **时相数据融合** 利用哨兵2号5天重访周期,提取同一区域不同季节的NDVI/NDWI时序曲线,区分**常绿林、落叶林、农作物**。 - 示例:夏季高NDVI(作物生长期) vs. 冬季低NDVI(裸土)。 --- ### **6. 分类后处理(显示优化)** - **分类结果平滑** 使用形态学滤波(如数分析)消除细小噪声。 (工具:QGIS的`SAGA Morphological Filter`) - **伪彩色渲染** 为不同地类分配对比色(如植被=绿色,水体=蓝色,建筑=红色),加行政边界或DEM阴影辅助判读。 --- ### **7. 工具与平台推荐** - **Google Earth EngineGEE)** 直接调用哨兵2号数据,内置光谱指数计算和分类算法(如随机森林)。 ```javascript // GEE示例:NDVI计算与显示 var ndvi = image.normalizedDifference(['B8', 'B4']).rename('NDVI'); Map.addLayer(ndvi, {min:0, max:1, palette: ['white', 'green']}, 'NDVI'); ``` - **QGIS/ArcGIS** 使用`Semi-Automatic Classification Plugin`(QGIS)或`Image Analysis`工具箱(ArcGIS)进行拉伸和分类。 --- ### **注意事项** 1. **分辨率匹配**:融合不同分辨率数据时需对齐像元; 2. **云掩膜**:优先选择云量<10%的影像(可用`QA60`波段去云); 3. **样本质量**:训练样本需覆盖所有地类且分布均匀。 若需具体代码实现或参数调优细节,可进一步说明需求!
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值