GEE利用哨兵1号数据进行水体监测

今天来简单分享下如何在GEE中利用哨兵1号数据进行水体动态监测

1.SAR数据介绍:

SAR 的工作原理是发射电磁脉冲并监听回波,这些回波被称为反向散射。反向散射的相位和振幅均被记录下来。

20afcc16db2a53ffa796a733d5451e78.png

相位:反向散射的相位用于确定传感器与目标之间的距离。这是因为波的相位与其传播的距离有关。通过比较发射波的相位与接收波的相位,传感器可以计算出波传播的距离,从而计算出与目标之间的距离。

振幅:反向散射的振幅表示返回传感器的发射信号量。SAR 图像像素振幅的高数字 (DN) 表示强反向散射,而低 DN 表示弱反向散射。振幅测量提供有关目标粗糙度、几何形状、湿度和介电常数的信息。

2.Sentinel-1数据介绍:

Sentinel-1是一项卫星任务,它使用合成孔径雷达 (SAR) 来捕捉地球表面的图像。它工作在 C 波段,即电磁波谱微波部分内4 至 8 GHz 的标称频率范围。Sentinel-1 SAR 系统支持单极化(HH 或 VV)和双极化(HH+HV 或 VV+VH)操作,通过一个发射链(可切换到 H 或 V)和两个用于 H 和 V 极化的并行接收链实现。

VV(垂直-垂直):雷达信号垂直发射并垂直接收。这通常用于检测水体,因为水面提供强大的 VV 响应。它也常用于洪水测绘。

HH(水平-水平):雷达信号水平发射并水平接收。这通常用于检测人造结构,因为这些结构往往会提供强大的 HH 响应。它通常用于城市地区的建筑物检测。

VH(垂直-水平)和 HV(水平-垂直):这些是交叉极化。雷达信号以一种极化(垂直或水平)发射并以另一种极化接收。这些通常用于检测植被,因为植被冠层内的多次散射通常会导致强烈的交叉极化响应。

不同的极化组合提供了有关表面特征的不同且互补的信息。例如,线性定向结构(如建筑物或沙中的涟漪)往往会反射并保持极化信号的相干性(相同的线性方向)。随机定向结构(如树叶)会在信号多次反射时散射并使信号去极化

在 Sentinel-1 的背景下,主要的无冲突模式是干涉宽幅 (IW)扫描带,在陆地上采用 VV+VH 极化,以及波浪 (WV) 扫描带,在公海上采用 VV 极化。超宽幅 (EW) 扫描带模式主要用于广域沿海监测,包括船舶交通、漏油和海冰监测。

Sentinel-1 SAR数据的优势

  1. 全天候成像: Sentinel-1 可以在所有天气条件下(白天或夜晚)获取数据。这是因为它在不受云层或照明不足影响的波长下运行。

  2. 高分辨率:根据成像模式的不同,Sentinel-1 提供不同的分辨率(低至 5 米)和覆盖范围(高达 400 公里)。

  3. 变化检测: Sentinel-1可以检测地球表面随时间的变化,可用于监测环境变化、自然灾害和人类活动。

  4. 穿透深度:根据频率,SAR 信号可以穿透地面表层,从而可用于地质和考古应用。

  5. 多功能性: Sentinel-1数据可用于各种应用,包括环境监测、灾害管理、天气预报、军事和情报、保险业和海事当局。

  6. 干涉合成孔径雷达(InSAR):该技术利用两个合成孔径雷达图像之间的相位差来测量地球表面变形,可用于地质学、地震学和土木工程。

  7. 可靠、重复的广域监测: Sentinel-1 及其 C-SAR 仪器可以提供可靠、重复的广域监测。

  8. 重访时间短、产品交付快: Sentinel-1 的修订时间合理 - S1A 和 S1B 卫星的重复周期总和为 6 天,同时为地面测距产品提供每像素 20 米的高分辨率

    8c00a49e719e0ebdd6544d5bb1ec5d27.png

2.GEE实现代码:

首先确定研究区和使用的数据集

我选择的研究区为小浪底水库的部分区域,使用的数据集为COPERNICUS/S1_GRD

目标是小浪底水库的部分区域水体的动态监测

以下是实现代码:

var s1 =  ee.ImageCollection('COPERNICUS/S1_GRD')
.filter(ee.Filter.listContains('transmitterReceiverPolarisation', 'VV'))
.filter(ee.Filter.eq('instrumentMode', 'IW'))
.filter(ee.Filter.eq('orbitProperties_pass', 'ASCENDING'))
.filterBounds(roi)
//.filterBounds(Map.getBounds(true))
.filterDate('2020-01-01','2020-12-31')
// Filter partial S1-Images of AOI
//.map(function(image){return image.clip(Map.getBounds(true))})
.map(function(image){return image.addBands(image.select('VV').focal_median(parseFloat('50'),'circle','meters').rename('VV_smoothed'))})// Smooth S1-Images
.map(function(image){
    return image.clip(roi)
  });
print(s1);


// 返回 S1 波段(区域内)类间方差最大的 DN。
var otsu = function(histogram) {
  var counts = ee.Array(ee.Dictionary(histogram).get('histogram'));
  var means = ee.Array(ee.Dictionary(histogram).get('bucketMeans'));
  var size = means.length().get([0]);
  var total = counts.reduce(ee.Reducer.sum(), [0]).get([0]);
  var sum = means.multiply(counts).reduce(ee.Reducer.sum(), [0]).get([0]);
  var mean = sum.divide(total);
  
  var indices = ee.List.sequence(1, size);
  
// 计算每个均值分割数据的平方和。
  var bss = indices.map(function(i) {
    var aCounts = counts.slice(0, 0, i);
    var aCount = aCounts.reduce(ee.Reducer.sum(), [0]).get([0]);
    var aMeans = means.slice(0, 0, i);
    var aMean = aMeans.multiply(aCounts)
        .reduce(ee.Reducer.sum(), [0]).get([0])
        .divide(aCount);
    var bCount = total.subtract(aCount);
    var bMean = sum.subtract(aCount.multiply(aMean)).divide(bCount);
    return aCount.multiply(aMean.subtract(mean).pow(2)).add(
           bCount.multiply(bMean.subtract(mean).pow(2)));
  });
  
// 返回与最大 BSS 对应的平均值。
  return means.sort(bss).get([-1]);
};


// 返回带水掩膜作为附加波段的图像
var add_waterMask = function(image){
  // Compute histogram
  var histogram = image.select('VV').reduceRegion({
    reducer: ee.Reducer.histogram(255, 2)
      .combine('mean', null, true)
      .combine('variance', null, true), 
    geometry: roi, 
    scale: 10,
    bestEffort: true
  });
  // 通过 otsu 计算阈值
  var threshold = otsu(histogram.get('VV_histogram'));
  
  // 获取 Watermask
  var waterMask = image.select('VV_smoothed').lt(threshold).rename('waterMask');
  waterMask = waterMask.updateMask(waterMask); //Remove all pixels equal to 0
  return image.addBands(waterMask);
};


s1 = s1.map(add_waterMask);


//计算出水量
var min_occurence = 10;
var water_sum = s1.select('waterMask').reduce(ee.Reducer.sum());
var water_frequency = water_sum.divide(s1.select('waterMask').size()).multiply(100);
var water_frequency_masked = water_frequency.updateMask(water_frequency.gt(min_occurence));


function makeLegend(lowLine, midLine, highLine,lowText, midText, highText, palette) {
  var  labelheader = ui.Label('调查期间出现的水量',{margin: '5px 17px', textAlign: 'center', stretch: 'horizontal', fontWeight: 'bold'});
  var labelLines = ui.Panel(
      [
        ui.Label(lowLine, {margin: '-4px 21px'}),
        ui.Label(midLine, {margin: '-4px 0px', textAlign: 'center', stretch: 'horizontal'}),
        ui.Label(highLine, {margin: '-4px 21px'})
],
      ui.Panel.Layout.flow('horizontal'));
      var labelPanel = ui.Panel(
      [
        ui.Label(lowText, {margin: '0px 14.5px'}),
        ui.Label(midText, {margin: '0px 0px', textAlign: 'center', stretch: 'horizontal'}),
        ui.Label(highText, {margin: '0px 1px'})
],
      ui.Panel.Layout.flow('horizontal'));
    return ui.Panel({
      widgets: [labelheader, ColorBar(palette), labelLines, labelPanel], 
      style: {position:'bottom-left'}});
}
Map.add(makeLegend('|', '|', '|', "0 %", '50 %', '100%', ['orange','yellow','lightblue','darkblue']));
Map.addLayer(s1.median(),{bands: ['VV','VV','VV'],min: -20,max: 0,},'S1-image [median]');
Map.addLayer(water_frequency_masked,{min:min_occurence,max:100,palette:['orange','yellow','lightblue','darkblue']},'Percentage of annual water occurence');
Map.add(animation);
print(ui.Thumbnail({image: s1, params: timelapse}));
var ClassChart = ui.Chart.image.series({
  imageCollection: s1.select('waterMask'),
  region: roi,
  reducer: ee.Reducer.sum(),
  scale: 100,
})
  .setOptions({
      title: '确定的水掩模区域',
      vAxis: {'title': 'area'},
      lineWidth: 1.5,
      pointSize: 2
    });
ClassChart.style().set({
    position: 'bottom-right',
    width: '492px',
    height: '300px'
  });


Map.add(ClassChart);
//创建回调函数,在地图上添加与点击的图表数据点相对应的图像
ClassChart.onClick(function(xValue, yValue, seriesName) {
    if (!xValue) return;  // Auswahl zurücksetzen
  
    // Show the image for the clicked date.
    var equalDate = ee.Filter.equals('system:time_start', xValue);
    //Find image coresponding with clicked data and clip water classification to aoi 
    var classification = ee.Image(s1.filter(equalDate).first()).clip(roi).select('waterMask'); 
    var SARimage = ee.Image(s1.filter(equalDate).first());
        var date_string = new Date(xValue).toLocaleString('de-DE', {dateStyle: 'full', timeStyle: 'short' });
    //Make map layer based on SAR image, reset the map layers, and add this new layer
    var S1Layer = ui.Map.Layer(SARimage, {
      bands: ['VV'],
      max: 0,
      min: -20
    },'S1-Image ['+ new Date(xValue).toLocaleString('de-DE')+']');
    Map.layers().reset([S1Layer]);
    var visParamsS1Layer = {
      min: 0,
      max: 1,
      palette: ['#FFFFFF','#0000FF']
    };
    
    //Add water classification on top of SAR image
    Map.addLayer(classification,visParamsS1Layer,'water mask ['+date_string+']');
});
}

结果显示:

dac45c630ba2b3c253d3f629dbb440a1.png

研究区S1_GRD显示

e54d18037ff203ff5bd3baf5a7e58182.png

调查期间水量显示

3efb51ff9f2c34ef743d90728f2cab5c.png

2020年研究区水体面积

cd45bdacfba9c1d32ce1284efb923f6d.gif

水域动态监测

感谢关注,欢迎转发!

声明:仅供学习使用!

希望关注的朋友们转发,如果对你有帮助的话记得给小编点个赞或者在看

### 使用 GEE API 下载 Sentinel-1 卫星数据 要通过 Google Earth Engine (GEE) API 下载 Sentinel-1 数据,可以按照以下方式实现。这种方法无需手动下载每张图像,而是利用 GEE 的云计算能力来处理和导出所需的数据。 #### 初始化 GEE 并加载 Sentinel-1 集合 首先,确保已安装 `earthengine-api` 库,并完成身份验证。以下是初始化代码: ```python import ee ee.Authenticate() ee.Initialize() ``` 接着定义感兴趣区域(AOI),这可以通过 GeoJSON 文件或其他地理空间格式指定。例如: ```python aoi = ee.Geometry.Rectangle([longitude_min, latitude_min, longitude_max, latitude_max]) ``` 或者从 Shapefile 加载 AOI: ```python shapefile_url = 'path_to_your_shapefile.shp' aoi = ee.FeatureCollection(ee.Algorithms.GeoJSONToFeatureCollection(shapefile_url)) ``` #### 过滤 Sentinel-1 数据集 使用 `ee.ImageCollection` 来访问 Sentinel-1 GRD 数据集,并过滤时间范围和地理位置: ```python sentinel1_collection = ee.ImageCollection('COPERNICUS/S1_GRD') \ .filterBounds(aoi) \ .filterDate('2023-01-01', '2023-12-31') \ .filter(ee.Filter.listContains('transmitterReceiverPolarisation', 'VV')) \ .filter(ee.Filter.eq('instrumentMode', 'IW')) ``` 上述代码中: - `'COPERNICUS/S1_GRD'` 是 Sentinel-1 地面射频退化(GRD)产品的 ID[^2]。 - `.filterBounds(aoi)` 限定影像覆盖的地理范围。 - `.filterDate()` 设置时间范围。 - `.filter(ee.Filter.listContains())` 和 `.filter(ee.Filter.eq())` 分别用于选择极化模式(如 VV 或 VH)以及成像模式(如 IW 表示干涉宽幅模式)。 #### 可视化与预览 为了确认所选数据的质量,在浏览器中可视化部分结果: ```python url = sentinel1_collection.first().select('VV').getThumbURL({ 'min': -25, 'max': 0, 'palette': ['black', 'white'] }) print(url) ``` 此代码生成一张缩略图 URL,便于快速检查数据质量。 #### 导出至 Google Drive 或资产目录 最后一步是将选定的影像导出到 Google Drive 或 GEE 资产目录。以下是一个完整的导出命令: ```python task = ee.batch.Export.image.toDrive( image=.sentinel1_collection.mean(), description='Sentinel1_Export', folder='gee_exports', region=aoi.bounds().getInfo()['coordinates'], scale=10, crs='EPSG:4326', maxPixels=1e13 ) task.start() ``` 参数说明: - `image`: 输入为经过均值计算后的合成影像。 - `description`: 输出文件名前缀。 - `folder`: 存储在 Google Drive 中的目标文件夹名称。 - `region`: 定义裁剪范围的几何坐标。 - `scale`: 像素分辨率(单位:米)。对于 Sentinel-1,默认分辨率为 10 米。 - `crs`: 投影系统,通常为 WGS84 (`EPSG:4326`)。 - `maxPixels`: 允许的最大像素数,防止因尺寸过大而导致失败。 以上流程涵盖了从加载、筛选到最终导出的过程。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

生态遥感监测笔记

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值