【Earth Engine】协同Sentinel-1/2使用随机森林回归实现高分辨率相对财富(贫困)制图

目录

  • 1 简介与摘要
  • 2 思路
  • 3 效果预览
  • 4 代码思路
  • 5 完整代码
  • 6 后记

1 简介与摘要

最近在做一些课题,需要使用Sentinel-1/2进行机器学习制图。
然后想着总结一下相关数据和方法,就花半小时写了个代码。
然后再花半小时写下这篇博客记录一下。
因为基于多次拍脑袋而且花的时间很少,所以千万不要把这篇博客的实验流程当作完整的实验,
具体的科研实验还需要反复设计和多次试错!!!

这篇博客主要参考数据(相对贫困指数,RWI)来自这个GEE社区网站,有缺数据的可以直接在这上面找,要用的时候调用一下就行了。这是这个数据的一个交互地图预览。
工作完全是在GEE平台上写的,如上面所说,这个工作跟我的课题内容关系不大,纯粹是拍脑袋的需求然后拍脑袋写的代码。

2 思路

思路就是用Sentinel-1/2的一些波段作为自变量,对自变量在2400m进行采样(因为这个RWI数据的分辨率就是2400),
然后相对贫困指数RWI作为因变量,
最后在10m尺度使用随机森林回归进行相对贫困制图。

因为我没相关需求,求快,所以这里就简单随便弄弄。
因为是随便弄弄,我也不计算什么乱七八糟的指数了,就用VV和VH还有一些光学波段作为自变量。
因变量就直接用原数据的RWI。

研究区选的是坦桑尼亚的原首都达雷斯萨拉姆及其周边,选这个地方没啥特殊的原因,纯粹是点开那个交互地图映入眼帘的就是这个地方(好耳熟的名字,依稀记得当时所里好像有好多非洲老哥来自这个地方)。

所以总的来说,就是基于Sentinel-1/2做一个高分辨率的(10m)相对贫困地图。

这个博客主要还是展示如何用开源数据在GEE上快速实现机器学习制图,这个博客提供的思路太简单了,如果正经是搞科研论文或者做实验还涉及很多数据预处理步骤。
首先这个RWI数据就要咔咔一顿处理,在这个思路里直接在2400m采样肯定是行不通的。
所以这个博客主要还是提供一个参考,具体的一些流程还需要精心设计和反复试错。

3 效果预览

惯例,在代码前面先放效果预览。

我的兴趣区(roi):
在这里插入图片描述

控制台:
在这里插入图片描述
上图的意思是区域内有2578个样本点,我拿80%(2078个)的去训练,20%(500个)去验证。
散点图是观测值和预测值的散点图。
RMSE就是均方根误差了。看着效果还可以哈。

绘制结果:
在这里插入图片描述

红色的是RWI高值(有钱),蓝色绿色的是RWI低值(贫困)。

绘制结果的细节:
在这里插入图片描述
在这里插入图片描述

为什么看起来这么稀碎呢,因为我拿World Settlement Footprint, WSF掩膜了一下,常规操作,具体可看代码。

4 代码思路

首先我把我要用的数据拉进来。其中RWI数据我按我的ROI筛选一下,不然太多了。代码如下:

// Importing Built-up map
var wsf2019 = ee.ImageCollection('projects/sat-io/open-datasets/WSF/WSF_2019');

var wsf_01 = wsf2019.mosaic().eq(255);
var buildingup = wsf_01;


// Importing RWI
var rwi = ee.FeatureCollection("projects/sat-io/open-datasets/facebook/relative_wealth_index")
                            .filterBounds(roi.geometry());

print("sample size", rwi.size())

考虑到要调用Sentinel-1和2,所以也把这些数据写进来,然后也要写上一些预处理。代码如下:

// Importing S1 SAR images.
var sentinel1 = ee.ImageCollection('COPERNICUS/S1_GRD')
                    .filterDate("2019-01-01", "2024-01-01")
                    .filterBounds(roi.geometry());
// print(sentinel1)
// Filter the S1 collection by metadata properties.
var vvVhIw = sentinel1
  // Filter to get images with VV and VH dual polarization.
  .filter(ee.Filter.listContains('transmitterReceiverPolarisation', 'VV'))
  .filter(ee.Filter.listContains('transmitterReceiverPolarisation', 'VH'))
  // Filter to get images collected in interferometric wide swath mode.
  .filter(ee.Filter.eq('instrumentMode', 'IW'));
// Separate ascending and descending orbit images into distinct collections.
var vvVhIwAsc = vvVhIw.filter(
  ee.Filter.eq('orbitProperties_pass', 'ASCENDING'));
var vvVhIwDesc = vvVhIw.filter(
  ee.Filter.eq('orbitProperties_pass', 'DESCENDING'));


// Importing S2 images.
// Cloud mask function.
function maskS2clouds(image) {
  var qa = image.select('QA60');
  // Bits 10 and 11 are clouds and cirrus, respectively.
  var cloudBitMask = 1 << 10;
  var cirrusBitMask = 1 << 11;
  // Both flags should be set to zero, indicating clear conditions.
  var mask = qa.bitwiseAnd(cloudBitMask).eq(0)
      .and(qa.bitwiseAnd(cirrusBitMask).eq(0));
  return image.updateMask(mask).divide(10000);
}

var sentinel2 = ee.ImageCollection("COPERNICUS/S2_SR")
                  .filterDate("2019-01-01", "2024-01-01")
                  .filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE', 30))
                  .filterBounds(roi.geometry())
                  .map(maskS2clouds)
                  .mean();

再然后,把我要的波段挑出来,合并成一个image。简简单单搞一下子。代码如下:

// Indice.
var vv = vvVhIwAsc.merge(vvVhIwDesc).select('VV').mean();
var vh = vvVhIwAsc.merge(vvVhIwDesc).select('VH').mean();

var blue = sentinel2.select('B2');
var green = sentinel2.select('B3');
var red = sentinel2.select('B4');
var red_edge1 = sentinel2.select('B5');
var red_edge2 = sentinel2.select('B6');
var red_edge3 = sentinel2.select('B7');
var nir = sentinel2.select('B8');
var red_edge4 = sentinel2.select('B8A');
var SWIR1 = sentinel2.select('B11');
var SWIR2 = sentinel2.select('B12');

var image = ee.Image()
                      .addBands(vv)
                      .addBands(vh)
                      .addBands(blue)
                      .addBands(green)
                      .addBands(red)
                      .addBands(red_edge1)
                      .addBands(red_edge2)
                      .addBands(red_edge3)
                      .addBands(nir)
                      .addBands(red_edge4)
                      .addBands(SWIR1)
                      .addBands(SWIR2)
                      ;

var band_name = ee.List(['VV', 'VH', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7', 'B8', 'B8A', 'B11', 'B12'])

然后,就是用RWI数据对我选的这些波段(自变量进行采样)。考虑到RWI是2400m分辨率,所以我就在2400米采样。采样完把我们样本规模打印到控制台看看。代码如下:

// Sampling.
var samples = rwi.randomColumn('random'); // set a random field

var training_samples = samples.filter(ee.Filter.lt('random', 0.8)); // 80% training data
var training_samples = image.reduceRegions({collection: training_samples, reducer: ee.Reducer.mean(), scale: 2400}); // sampling


var testing_samples = samples.filter(ee.Filter.gte('random', 0.8)); // 20% testing data
var testing_samples = image.reduceRegions({collection: testing_samples, reducer: ee.Reducer.mean(), scale: 2400}); // sampling


print("training sample size", training_samples.size())
print("testing sample size", testing_samples.size())

接下来就是要正式的训练模型绘图。用刚才采样的训练集训练一个回归模型,并且用这个模型进行绘图,得到一张结果的图像rwi_map,然后再用WSF掩膜一下住区。代码如下:

// Regressing.
var regressor = ee.Classifier
            .smileRandomForest(50) // number of estimators/trees
            .setOutputMode('REGRESSION') // regression algorithm
            .train(training_samples, // training samples
                    "rwi", // regressing target
                    band_name); // regressor features


var rwi_map = image.unmask(0).clip(roi).classify(regressor).rename('rwi'); // regress
var rwi_map = rwi_map.updateMask(buildingup).clip(roi); // mask

建模画图完了,然后就是验证。用sampleRegions在画完的图上采样得到预测值,和一开始的观测值进行对比。验证包含散点图R2和RSME,都是必要常用的指标和表现形式。代码如下:

// Testing.
var testing_samples = rwi_map.rename('predicted').sampleRegions({
  collection: testing_samples,
  scale: 2400,
  geometries: true,
  projection: 'EPSG:4326'
});
var testing_samples = testing_samples.select(['rwi', 'predicted']);
// print(testing_samples)
// Scatter plot.
var chartTraining = ui.Chart.feature.byFeature({features: testing_samples, xProperty:'rwi', yProperties:['predicted']})
  .setChartType('ScatterChart')
  .setOptions({
    title: 'Predicted vs Observed - Training data ',
    hAxis: {
      'title': 'observed'
    },
    vAxis: {
      'title': 'predicted'
    },
    pointSize: 3,
    trendlines: {
      0: {
        showR2: true,
        visibleInLegend: true
      },
      1: {
        showR2: true,
        visibleInLegend: true
      }
    }
  });
print(chartTraining);
// Calculating RMSE.
var observation = ee.Array(testing_samples.aggregate_array('rwi'));
var prediction = ee.Array(testing_samples.aggregate_array('predicted'));
var residuals = observation.subtract(prediction);
var rmse = residuals.pow(2)
  .reduce('mean', [0])
  .sqrt();
print('RMSE', rmse);

最后是把刚才画的图,也就是绘图结果可视化。代码如下:

// Visualization.
Map.centerObject(roi, 8);
var palettes = ["#08525e", "#40d60e", "#b9e40e", "#f9c404", "e70000"]
Map.addLayer(rwi_map,
              {min: -0.5, max: 1.5, palette: palettes},
              'RWI');

5 完整代码

我的代码链接在这,可以直接使用。
完整代码如下(和链接中相同):

// Importing Built-up map
var wsf2019 = ee.ImageCollection('projects/sat-io/open-datasets/WSF/WSF_2019');

var wsf_01 = wsf2019.mosaic().eq(255);
var buildingup = wsf_01;


// Importing RWI
var rwi = ee.FeatureCollection("projects/sat-io/open-datasets/facebook/relative_wealth_index")
                            .filterBounds(roi.geometry());

print("sample size", rwi.size())


// Importing S1 SAR images.
var sentinel1 = ee.ImageCollection('COPERNICUS/S1_GRD')
                    .filterDate("2019-01-01", "2024-01-01")
                    .filterBounds(roi.geometry());
// print(sentinel1)
// Filter the S1 collection by metadata properties.
var vvVhIw = sentinel1
  // Filter to get images with VV and VH dual polarization.
  .filter(ee.Filter.listContains('transmitterReceiverPolarisation', 'VV'))
  .filter(ee.Filter.listContains('transmitterReceiverPolarisation', 'VH'))
  // Filter to get images collected in interferometric wide swath mode.
  .filter(ee.Filter.eq('instrumentMode', 'IW'));
// Separate ascending and descending orbit images into distinct collections.
var vvVhIwAsc = vvVhIw.filter(
  ee.Filter.eq('orbitProperties_pass', 'ASCENDING'));
var vvVhIwDesc = vvVhIw.filter(
  ee.Filter.eq('orbitProperties_pass', 'DESCENDING'));


// Importing S2 images.
// Cloud mask function.
function maskS2clouds(image) {
  var qa = image.select('QA60');
  // Bits 10 and 11 are clouds and cirrus, respectively.
  var cloudBitMask = 1 << 10;
  var cirrusBitMask = 1 << 11;
  // Both flags should be set to zero, indicating clear conditions.
  var mask = qa.bitwiseAnd(cloudBitMask).eq(0)
      .and(qa.bitwiseAnd(cirrusBitMask).eq(0));
  return image.updateMask(mask).divide(10000);
}

var sentinel2 = ee.ImageCollection("COPERNICUS/S2_SR")
                  .filterDate("2019-01-01", "2024-01-01")
                  .filter(ee.Filter.lt('CLOUDY_PIXEL_PERCENTAGE', 30))
                  .filterBounds(roi.geometry())
                  .map(maskS2clouds)
                  .mean();



// Indice.
var vv = vvVhIwAsc.merge(vvVhIwDesc).select('VV').mean();
var vh = vvVhIwAsc.merge(vvVhIwDesc).select('VH').mean();

var blue = sentinel2.select('B2');
var green = sentinel2.select('B3');
var red = sentinel2.select('B4');
var red_edge1 = sentinel2.select('B5');
var red_edge2 = sentinel2.select('B6');
var red_edge3 = sentinel2.select('B7');
var nir = sentinel2.select('B8');
var red_edge4 = sentinel2.select('B8A');
var SWIR1 = sentinel2.select('B11');
var SWIR2 = sentinel2.select('B12');

var image = ee.Image()
                      .addBands(vv)
                      .addBands(vh)
                      .addBands(blue)
                      .addBands(green)
                      .addBands(red)
                      .addBands(red_edge1)
                      .addBands(red_edge2)
                      .addBands(red_edge3)
                      .addBands(nir)
                      .addBands(red_edge4)
                      .addBands(SWIR1)
                      .addBands(SWIR2)
                      ;

var band_name = ee.List(['VV', 'VH', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7', 'B8', 'B8A', 'B11', 'B12'])




// Sampling.
var samples = rwi.randomColumn('random'); // set a random field

var training_samples = samples.filter(ee.Filter.lt('random', 0.8)); // 80% training data
var training_samples = image.reduceRegions({collection: training_samples, reducer: ee.Reducer.mean(), scale: 2400}); // sampling


var testing_samples = samples.filter(ee.Filter.gte('random', 0.8)); // 20% testing data
var testing_samples = image.reduceRegions({collection: testing_samples, reducer: ee.Reducer.mean(), scale: 2400}); // sampling


print("training sample size", training_samples.size())
print("testing sample size", testing_samples.size())


// Regressing.
var regressor = ee.Classifier
            .smileRandomForest(50) // number of estimators/trees
            .setOutputMode('REGRESSION') // regression algorithm
            .train(training_samples, // training samples
                    "rwi", // regressing target
                    band_name); // regressor features


var rwi_map = image.unmask(0).clip(roi).classify(regressor).rename('rwi'); // regress
var rwi_map = rwi_map.updateMask(buildingup).clip(roi); // mask


// Testing.
var testing_samples = rwi_map.rename('predicted').sampleRegions({
  collection: testing_samples,
  scale: 2400,
  geometries: true,
  projection: 'EPSG:4326'
});
var testing_samples = testing_samples.select(['rwi', 'predicted']);
// print(testing_samples)
// Scatter plot.
var chartTraining = ui.Chart.feature.byFeature({features: testing_samples, xProperty:'rwi', yProperties:['predicted']})
  .setChartType('ScatterChart')
  .setOptions({
    title: 'Predicted vs Observed - Training data ',
    hAxis: {
      'title': 'observed'
    },
    vAxis: {
      'title': 'predicted'
    },
    pointSize: 3,
    trendlines: {
      0: {
        showR2: true,
        visibleInLegend: true
      },
      1: {
        showR2: true,
        visibleInLegend: true
      }
    }
  });
print(chartTraining);
// Calculating RMSE.
var observation = ee.Array(testing_samples.aggregate_array('rwi'));
var prediction = ee.Array(testing_samples.aggregate_array('predicted'));
var residuals = observation.subtract(prediction);
var rmse = residuals.pow(2)
  .reduce('mean', [0])
  .sqrt();
print('RMSE', rmse);




// Visualization.
Map.centerObject(roi, 8);
var palettes = ["#08525e", "#40d60e", "#b9e40e", "#f9c404", "e70000"]
Map.addLayer(rwi_map,
              {min: -0.5, max: 1.5, palette: palettes},
              'RWI');

6 后记

可能有些地方不太专业不太科学,希望诸位同行前辈不吝赐教或者有什么奇妙的想法可以和我共同探讨一下。可以在csdn私信我或者联系我邮箱(chinshuuichi@qq.com),不过还是希望大家邮箱联系我,csdn私信很糟糕而且我上csdn也很随缘。
如果对你有帮助,还望支持一下~点击此处施舍或扫下图的码。
-----------------------分割线(以下是乞讨内容)-----------------------
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/265208.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

学校和老师如何制作自己免费的成绩查询系统

在当今数字化的时代&#xff0c;许多学校都采用信息技术来管理和提高工作效率。其中&#xff0c;成绩查询系统是一个非常实用的工具&#xff0c;它可以让老师和学生们快速、方便地查询成绩。那么&#xff0c;学校和老师如何制作自己免费的成绩查询系统呢&#xff1f;本文将为你…

【Amazon 实验①】使用 Amazon CloudFront加速Web内容分发

文章目录 实验架构图1. 准备实验环境2. 创建CloudFront分配、配置动、静态资源分发2.1 创建CloudFront分配&#xff0c;添加S3作为静态资源源站2.2 为CloudFront分配添加动态源站 在本实验——使用CloudFront进行全站加速中&#xff0c;将了解与学习Amazon CloudFront服务&…

Python办公自动化Day1

目录 文章声明⭐⭐⭐让我们开始今天的学习吧&#xff01;xlwt创建Excelxlrd读取Excelxlutils修改Excelxlwt设置样式常见的字体样式单元格宽高内容对齐方式设置单元格边框设置背景颜色样式整合起来的写法 文章声明⭐⭐⭐ 该文章为我&#xff08;有编程语言基础&#xff0c;非编…

RabbitMQ笔记(高级篇)

RabbitMQ笔记_高级篇 问题代码准备1. 新建生产者2. 新建消费者 RabbitMQ 高级特性1. 消息的可靠投递☆1.1 两种模式1.2 测试confirm 确认模式1.3 测试return 退回模式1.4 小结 2. Consumer ACK☆2.1 三种ACK2.2 测试手动ACK2.3 小结2.4 消息可靠性总结 3. 消费端限流测试消费端…

旅游海报图怎么做二维码展示?扫码即可查看图片

现在旅游攻略的海报可以做成二维码印刷在宣传单单页或者分享给用户来了解目的地的实际情况&#xff0c;出行路线、宣传海报等。用户只需要扫描二维码就可以查看内容&#xff0c;更加的方便省劲&#xff0c;那么旅游海报的图片二维码制作的技巧有哪些呢&#xff1f;使用图片二维…

【算法设计与分析】——动态规划算法

&#x1f383;个人专栏&#xff1a; &#x1f42c; 算法设计与分析&#xff1a;算法设计与分析_IT闫的博客-CSDN博客 &#x1f433;Java基础&#xff1a;Java基础_IT闫的博客-CSDN博客 &#x1f40b;c语言&#xff1a;c语言_IT闫的博客-CSDN博客 &#x1f41f;MySQL&#xff1a…

关于“Python”的核心知识点整理大全36

目录 13.4.4 向下移动外星人群并改变移动方向 game_functions.py alien_invasion.py 13.5 射杀外星人 13.5.1 检测子弹与外星人的碰撞 game_functions.py alien_invasion.py 13.5.2 为测试创建大子弹 13.5.3 生成新的外星人群 game_functions.py alien_invasion.py …

【github】github设置项目为私有

点击setting change to private 无脑下一步

为什么c++的开源库那么少?

为什么c的开源库那么少&#xff1f; 在开始前我有一些资料&#xff0c;是我根据自己从业十年经验&#xff0c;熬夜搞了几个通宵&#xff0c;精心整理了一份「c的资料从专业入门到高级教程工具包」&#xff0c;点个关注&#xff0c;全部无偿共享给大家&#xff01;&#xff01;&…

热部署 和 热加载

本文主要讲热部署和热加载的区别、原理&#xff0c;以及常用的热部署的方式实践心得&#xff0c;其中包括HotSwap、Spring-loaded、Spring-boot-devtools、HotCode2和JRebel&#xff0c;诸多方式任你选择&#xff0c;希望能为你的开发进一步提效 1 热部署和热加载 开篇先说下热…

在Linux系统中安装MySQL数据库

目录 一、MySQL简介 二、MySQL安装步骤 1、下载MySQL的YUM仓库文件 2、安装MySQL源 3、解决密钥异常问题 4、安装MySQL服务器 5、开启MySQL服务 6、查看MySQL服务器中root用户的初始密码 7、使用初始密码登录MySQL服务器 8、修改root用户登录MySQL服务器的密码 三、…

使用Java语言判断一个年度是不是闰年

一、 代码说明 引入Scanner函数&#xff0c;将类命名为Judge类&#xff0c;使用try语句和catch语句将整体代码包围起来&#xff0c;使用if语句来判断是否为闰年&#xff0c;输入年份&#xff0c;然后得到相应的结论。 二、代码 import java.util.Scanner; public class Judg…

ElementUI中修改el-table的滚动条样式

注意&#xff1a;本文仅基于webkit引擎浏览器&#xff1b; 如果是火狐浏览器&#xff0c;则是-moz-&#xff1b; 部分webkit引擎浏览器&#xff1a;Google Chrome谷歌浏览器、Safari浏览器、搜狗高速浏览器、QQ浏览器、360极速浏览器等… 当内容超出容器时会出现滚动条&#…

HarmonyOS4.0系统性深入开发01应用模型的构成要素

应用模型的构成要素 应用模型是HarmonyOS为开发者提供的应用程序所需能力的抽象提炼&#xff0c;它提供了应用程序必备的组件和运行机制。有了应用模型&#xff0c;开发者可以基于一套统一的模型进行应用开发&#xff0c;使应用开发更简单、高效。 HarmonyOS应用模型的构成要…

Spring基础-IOC-DI-AOP

第一部分:Spring基础 文章目录 第一部分:Spring基础一、核心概念1.什么是Spring?2.Spring架构3.Spring优势 二、控制反转1.为什么要控制反转?2.组件化方式编程案例(Test01_di)3.采用组件化思维,装配打印机(Test01_di) 三、面向切面编程(AOP)方面编程1.什么是AOP?2.如何实现A…

AI时代Python量化交易实战:ChatGPT引领新时代

文章目录 《AI时代Python量化交易实战&#xff1a;ChatGPT让量化交易插上翅膀》关键点内容简介作者简介购买链接 《AI时代架构师修炼之道&#xff1a;ChatGPT让架构师插上翅膀》关键点内容简介作者简介 赠书活动 《AI时代Python量化交易实战&#xff1a;ChatGPT让量化交易插上翅…

MATLAB - 读取双摆杆上的 IMU 数据

系列文章目录 前言 本示例展示了如何从安装在双摆杆上的两个 IMU 传感器生成惯性测量单元 (IMU) 读数。双摆使用 Simscape Multibody™ 进行建模。有关使用 Simscape Multibody™ 构建简易摆的分步示例&#xff0c;请参阅简易摆建模&#xff08;Simscape Multibody&#xff09…

设计模式(4)--对象行为(2)--命令

1. 意图 将一个请求封装为一个对象&#xff0c;从而使你可用不同的请求对客户进行参数化&#xff1b;对请求排队或记录请 求日志&#xff0c;以及支持可撤销的操作。 2. 四种角色 接收者(Receiver)、抽象命令(Command)、具体命令(Concrete Command)、请求者(Invoker) 3. 优点…

【NI-RIO入门】使用其他文本语言开发CompactRIO

1.FPGA 接口Python API Getting Started — FPGA Interface Python API 19.0.0 documentation 2.FPGA接口C API FPGA 接口 C API 是用于 NI 可重配置 I/O (RIO) 硬件&#xff08;例如 NI CompactRIO、NI Single-Board RIO、NI 以太网 RIO、NI FlexRIO、NI R 系列多功能 RIO 和…

Python生成圣诞节贺卡-代码案例剖析【第18篇—python圣诞节系列】

文章目录 ❄️Python制作圣诞节贺卡&#x1f42c;展示效果&#x1f338;代码&#x1f334;代码剖析 ❄️Python制作圣诞树贺卡&#x1f42c;展示效果&#x1f338;代码&#x1f334;代码剖析&#x1f338;总结 &#x1f385;圣诞节快乐&#xff01; ❄️Python制作圣诞节贺卡 …