【数据修复指南】手把手教你使用线性插值填补各类遥感数据缺失——Modis、Landsat和Sentinel

1. 写在前面

  之前我写了使用年内均值或者中值来填补数据控制的方法,这种方法较为简单,不够精确。因此,我在这里结合所学知识提供一种线性插值的方法。线性插值假设在两个已知数据点之间的数据变化是均匀的,通过直线连接这两个点,并据此估算中间点的值。这种方法在数据缺失较少且缺失点两侧都有有效数据时效果较好。
  本研究以成都市成华区作为感兴趣区,选择MODIS和Landsat8数据进行线性插值。

研究区:
在这里插入图片描述

2. MODIS数据插值

  MOD09Q1产品只有红光(sur_refl_b01)和近红外(sur_refl_b02)两个波段的地表反射率数据。但是空间分辨率为250m,相对较高。
  这种方法是从相关公众号学到的,代码如下:

// GS(2024)0650号========================================================================================
var china_provinces = ee.FeatureCollection("projects/ee-tilmacatanla/assets/boundry/china_provinces");
var china_city = ee.FeatureCollection("projects/ee-tilmacatanla/assets/boundry/china_city");
var china_county = ee.FeatureCollection("projects/ee-tilmacatanla/assets/boundry/china_county");
var sichuan = china_provinces.filter(ee.Filter.eq('name','四川省'))
var chengdu = china_city.filter(ee.Filter.eq('name','成都市'))
var chenhuaqu = china_county.filter(ee.Filter.eq('name','成华区'))

Map.addLayer(sichuan.style({fillColor:'00000000',color:'red'}),{},"四川省", 0) //ff0000
Map.addLayer(chengdu.style({fillColor:'00000000',color:'blue'}),{},"成都市", 1) //ffff00
Map.addLayer(chenhuaqu.style({color:"black"}),{},"成华区")
Map.centerObject(chenhuaqu, 11.7);

var colorizedVis = {
  min: -1.0,
  max: 1.0,
  palette: [
    '0000ff','0000ee','0000dd','0000cc','0000bb','0000aa','000099',
    '000088','000077','000066','000055','000044','ce7e45', 'df923d', 
    'f1b555', 'fcd163', '99b718','74a901', '66a000',  '207401', '012e01',
    '262600', '0e0e00'
  ]
};

//参数设置;==============================================================================================
var mod_sr = ee.ImageCollection("MODIS/061/MOD09Q1"); //2000-02-18T00:00:00Z–2024-09-05T00:00:00Z
var startDate = ee.Date("2023-06-01");
var endDate = ee.Date("2023-09-01");
var roi = chenhuaqu
function replace_mask(img, newimg, nodata) {
    nodata   = nodata || 0;
    var mask = img.mask();
    img = img.unmask(nodata);
    img = img.where(mask.not(), newimg);
    img = img.updateMask(img.neq(nodata));
    return img;
}
/** Interpolation not considering weights */
function addTimeBand(img) {
    /** make sure mask is consistent */
    var mask = img.mask();
    var time = img.metadata('system:time_start').rename("time").mask(mask);
    return img.addBands(time);
}
var getQABits = function(image, start, end) {
    var pattern = 0;
    for (var i = start; i <= end; i++) {
       pattern += 1 << i;
    }
    // Return a single band image of the extracted QA bits
    return image.bitwiseAnd(pattern).rightShift(start);
};
function linearInterp(imgcol, frame, nodata){
    frame  = frame  || 32;
    nodata = nodata || 0;

    var time   = 'system:time_start';
    imgcol = imgcol.map(addTimeBand);

    var maxDiff = ee.Filter.maxDifference(frame * (1000*60*60*24), time, null, time);
    var cond    = {leftField:time, rightField:time};
    
    // Images after, sorted in descending order (so closest is last).
    var f1 = ee.Filter.and(maxDiff, ee.Filter.lessThanOrEquals(cond));
    var c1 = ee.Join.saveAll({matchesKey:'after', ordering:time, ascending:false})
        .apply(imgcol, imgcol, f1);
    
    // Images before, sorted in ascending order (so closest is last).
    var f2 = ee.Filter.and(maxDiff, ee.Filter.greaterThanOrEquals(cond));
    var c2 = ee.Join.saveAll({matchesKey:'before', ordering:time, ascending:true})
        .apply(c1, imgcol, f2);
    
    var interpolated = ee.ImageCollection(c2.map(function(img) {
        img = ee.Image(img);
        var before = ee.ImageCollection.fromImages(ee.List(img.get('before'))).mosaic();
        var after  = ee.ImageCollection.fromImages(ee.List(img.get('after'))).mosaic();
        img = img.set('before', null).set('after', null);
        // constrain after or before no NA values, confirm linear Interp having result
        before = replace_mask(before, after, nodata);
        after  = replace_mask(after , before, nodata);
        
        // Compute the ratio between the image times.
        var x1 = before.select('time').double();
        var x2 = after.select('time').double();
        var now = ee.Image.constant(img.date().millis()).double();
        var ratio = now.subtract(x1).divide(x2.subtract(x1));  // this is zero anywhere x1 = x2
        // Compute the interpolated image.
        before = before.select(0); //remove time band now;
        after  = after.select(0);
        img    = img.select(0); 
        
        var interp = after.subtract(before).multiply(ratio).add(before).toFloat();
        
        var qc = img.mask().not().rename('qc');
        interp = replace_mask(img, interp, nodata).rename('MOD_NDVI_INTER');
        return interp.addBands(qc).copyProperties(img, img.propertyNames());
    }));
    return interpolated;
}
function main(){
  var mod_ndvi = mod_sr.filterDate(startDate,endDate).filterBounds(roi)
   .map(function(image){return image.clip(roi)})
   .map(function(image) {
   var ndvi = image.normalizedDifference(['sur_refl_b02', 'sur_refl_b01']);  //calculate Landsat NDVI
   var Q = image.select('State');
   var masknum = getQABits(Q, 0, 2);
   var mask = masknum.eq(ee.Image(0)).or(masknum.eq(ee.Image(3)));
   var ndvi_masked = ndvi.updateMask(mask);   //generate MODIS cloud mask from state band (0:clear;1: cloud/shadow/mixed)
   return ndvi_masked.rename(['MOD_NDVI']).copyProperties(image, image.propertyNames())});
  var nodata = -9999;
  var frame = 4*4;
  var mod_ndvi_interp = linearInterp(mod_ndvi,frame,nodata);
  mod_ndvi = mod_ndvi.toList(100)
  mod_ndvi_interp = mod_ndvi_interp.select('MOD_NDVI_INTER').toList(100);
  print('mod_ndvi_interp',mod_ndvi_interp)
  Map.addLayer(ee.Image(mod_ndvi.get(5)),colorizedVis,'mod_ndvi')
  Map.addLayer(ee.Image(mod_ndvi_interp.get(5)),colorizedVis,'mod_ndvi_interp')
}
main();

结果对比:
在这里插入图片描述

在这里插入图片描述

3. Landsat数据插值

  在这里我在MODIS数据插值的基础上进行了修改和调整,并且添加了注释以便读者阅读。我这里使用了Landsat8数据为例,并且我会提供如何修改这份代码的方法,使得读者能够实现对其他类型的遥感数据进行插值,如sentinel卫星数据。
  代码如下:

//*********************************************************************************************************
//*********************************************************************************************************
// GS(2024)0650号========================================================================================
var china_provinces = ee.FeatureCollection("projects/ee-tilmacatanla/assets/boundry/china_provinces");
var china_city = ee.FeatureCollection("projects/ee-tilmacatanla/assets/boundry/china_city");
var china_county = ee.FeatureCollection("projects/ee-tilmacatanla/assets/boundry/china_county");
var sichuan = china_provinces.filter(ee.Filter.eq('name','四川省'))
var chengdu = china_city.filter(ee.Filter.eq('name','成都市'))
var chenhuaqu = china_county.filter(ee.Filter.eq('name','成华区'))

Map.addLayer(sichuan.style({fillColor:'00000000',color:'red'}),{},"四川省", 0) //ff0000
Map.addLayer(chengdu.style({fillColor:'00000000',color:'blue'}),{},"成都市", 1) //ffff00
Map.addLayer(chenhuaqu.style({color:"black"}),{},"成华区")
Map.centerObject(chenhuaqu, 11.7);

var colorizedVis = {
  min: -1.0,
  max: 1.0,
  palette: [
    '0000ff','0000ee','0000dd','0000cc','0000bb','0000aa','000099',
    '000088','000077','000066','000055','000044','ce7e45', 'df923d', 
    'f1b555', 'fcd163', '99b718','74a901', '66a000',  '207401', '012e01',
    '262600', '0e0e00'
  ]
};

var colorizedVis1 = {
  min: -1.0,
  max: 1.0,
  palette: ['#d7191c','#fdae61','#ffffbf','#a6d96a','#1a9641']
};

// 参数设置================================================================================================
var startDate = ee.Date("2023-03-01");
var endDate = ee.Date("2023-08-01");

//函数定义=================================================================================
// Applies scaling factors.
function applyScaleFactors(image) {
  var opticalBands = image.select('SR_B.').multiply(0.0000275).add(-0.2);
  var thermalBands = image.select('ST_B.*').multiply(0.00341802).add(149.0);
  return image.addBands(opticalBands, null, true)
              .addBands(thermalBands, null, true);
}
function rmCloudNew(image) {
  var cloudShadowBitMask = (1 << 4); 
  var cloudsBitMask = (1 << 3); 
  var qa = image.select('QA_PIXEL'); 
  var mask = qa.bitwiseAnd(cloudShadowBitMask).eq(0) 
                 .and(qa.bitwiseAnd(cloudsBitMask).eq(0)); 
  return image.updateMask(mask)
              .copyProperties(image)
              .copyProperties(image, ["system:time_start"]);
}


// Landsat8===================================================================================
var mod_sr = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2')
                .filterBounds(chenhuaqu)
                .filter(ee.Filter.calendarRange(2014,2023,'year'))
                .filter(ee.Filter.calendarRange(1,12,'month'))
                .map(applyScaleFactors)
                .map(rmCloudNew);

// 将一幅图像的掩膜区域用另一幅图像的对应区域替换,同时确保所有 nodata 值的像素都被掩膜====================
function replace_mask(img, newimg, nodata) {
    nodata   = nodata || 0;
    var mask = img.mask();
    img = img.unmask(nodata);
    img = img.where(mask.not(), newimg);
    img = img.updateMask(img.neq(nodata));
    return img;
}
/** Interpolation not considering weights */
function addTimeBand(img) {
    /** make sure mask is consistent */
    var mask = img.mask();
    var time = img.metadata('system:time_start').rename("time").mask(mask);
    return img.addBands(time);
}
var getQABits = function(image, start, end) {
    var pattern = 0;
    for (var i = start; i <= end; i++) {
      pattern += 1 << i;
    }
    // Return a single band image of the extracted QA bits
    return image.bitwiseAnd(pattern).rightShift(start);
};
function linearInterp(imgcol, Interp_range, nodata){
    Interp_range  = Interp_range  || 30;
    nodata = nodata || 0;
    
    var time   = 'system:time_start';
    imgcol = imgcol.map(addTimeBand);
    print("imgcol:", imgcol)
    
    //选择图像集合中时间差异不超过 Interp_range 天(转换为毫秒数)的图像
    var maxDiff = ee.Filter.maxDifference(Interp_range * (1000*60*60*24), time, null, time);//Interp_range 通常以天为单位, 这里将天数转换为毫秒数
    var cond    = {leftField:time, rightField:time};
    
    // Images after, sorted in descending order (so closest is last).
    var f1 = ee.Filter.and(maxDiff, ee.Filter.lessThanOrEquals(cond)); // 比较图像自身的时间字段,用于确保图像是按照时间顺序排列
    var c1 = ee.Join.saveAll({
      matchesKey:'after',  //寻找时间上在当前图像之后的图像
      ordering:time,       //定义匹配图像时的排序字段,这里是time,即按照图像获取的时间进行排序
      ascending:false      //定义了排序的方向,false表示按降序排序,意味着最接近当前图像时间的图像将被排在最后
    }).apply(imgcol, imgcol, f1);
    print("c1:", c1)
    
    // Images before, sorted in ascending order (so closest is last).
    var f2 = ee.Filter.and(maxDiff, ee.Filter.greaterThanOrEquals(cond)); 
    var c2 = ee.Join.saveAll({
      matchesKey:'before',   //寻找时间上在当前图像之前的图像
      ordering:time,         //定义匹配图像时的排序字段,这里是time,即按照图像获取的时间进行排序
      ascending:true         //定义了排序的方向,true表示按升序排序
    }).apply(c1, imgcol, f2);
    print("c2:", c2)
    
    var interpolated = ee.ImageCollection(
      c2.map(function(img) {
        img = ee.Image(img);
        
        // 获取roi图像缺失数据点前后最接近的图像,以便根据这些图像来估计缺失数据点的值
        var before = ee.ImageCollection.fromImages(ee.List(img.get('before'))).mosaic();// mosaic获取的是最后一个有值的像素,然后生成一张影像;
        var after  = ee.ImageCollection.fromImages(ee.List(img.get('after'))).mosaic();
        
        // 属性初始化
        img = img.set('before', null).set('after', null);
        // constrain after or before no NA values, confirm linear Interp having result
        // 更新 before 图像,使其掩膜区域被 after 图像的对应区域替换,同时确保所有 nodata 值的像素都被掩膜
        before = replace_mask(before, after, nodata);
        after  = replace_mask(after , before, nodata);
        
        // Compute the ratio between the image times.
        var x1 = before.select('time').double();
        var x2 = after.select('time').double();
        var now = ee.Image.constant(img.date().millis()).double();
        var ratio = now.subtract(x1).divide(x2.subtract(x1));  // this is zero anywhere x1 = x2
        // Compute the interpolated image.
        before = before.select(0); //remove time band now; 选择 before 图像的第一个波段
        after  = after.select(0);
        img    = img.select(0); 
        
        var interp = after.subtract(before).multiply(ratio).add(before).toFloat();
        
        var qc = img.mask().not().rename('qc');
        interp = replace_mask(img, interp, nodata).rename('Landsat_NDVI_INTER');
        return interp.addBands(qc).copyProperties(img, img.propertyNames());
    }));
    return interpolated;
}

function main(){
  var Landsat_NDVI = mod_sr.filterDate(startDate,endDate).filterBounds(chenhuaqu)
   .map(function(image){return image.clip(chenhuaqu)})
   .map(function(image) {
   var ndvi = image.normalizedDifference(['SR_B5', 'SR_B4']);  //calculate Landsat NDVI
   var Q = image.select('QA_PIXEL'); // Pixel quality
   // 从原始图像中筛选出无云或云状态未设置的像素
   // 提取第8-11位(不可行)===============================================================
   // Bit 0: Fill; Bit 1: Dilated Cloud; Bit 2: Cirrus (high confidence);
   // Bit 3: Cloud; Bit 4: Cloud Shadow; Bit 5: Snow; Bit 6: Clear
   // Bits 8-9:Cloud Confidence:云层置信度,两位用来表示云层存在的可能性,从无到高
   // Bits 10-11: Cloud Shadow Confidence:云阴影置信度,两位用来表示云阴影存在的可能性,从无到高
   var masknum = getQABits(Q, 0, 4); 
   var mask = masknum.eq(ee.Image(0)).or(masknum.eq(ee.Image(64))); // 0001000000 = 64~[2*(7-1)=64]
   var ndvi_masked = ndvi.updateMask(mask);   //generate Landsat cloud mask from QA_PIXEL band (0:clear;1: cloud/shadow/mixed)
   
   return ndvi_masked.rename(['Landsat_NDVI']).copyProperties(image, image.propertyNames())
   });
   
   //=====================================================================================
  var imgTiles = ee.FeatureCollection(Landsat_NDVI.map(function(img){
    var tmpFootprint = ee.Image(img).geometry();
    var WRS_PATH = ee.Number(ee.Image(img).get("WRS_PATH"));
    var WRS_ROW =  ee.Number(ee.Image(img).get("WRS_ROW"));
    return ee.Feature(tmpFootprint,null).set("WRS_PATH",WRS_PATH).set("WRS_ROW",WRS_ROW);
  })).distinct(["WRS_PATH",'WRS_ROW']);
  var styling = {color:'red',fillColor:'00000000'};
  print("imgTiles size",imgTiles);
  Map.addLayer(imgTiles.style(styling), {}, 'imgTiles');
  
  // 计算每个图像的研究区像元数并添加为属性=============================================
  var withPixelCount = Landsat_NDVI.map(function(image) {
  // 假设我们的NDVI波段名为'NDVI'
  var pixelCount = image.reduceRegion({
    reducer: ee.Reducer.count(),
    geometry: chenhuaqu,
    scale: 900, // 根据实际需要调整分辨率
    maxPixels: 1e9
  });
  // 使用波段名称作为键来获取计数
  return image.set('pixelCount', pixelCount.get('Landsat_NDVI'));
  });
  
  // 根据像元数对图像集合进行排序
  var sortedCollection = withPixelCount.sort('pixelCount', true);
  // 展示排序后的图像集合。
  var count = sortedCollection.size().getInfo();
  for (var i = 0; i < count; i++) {
    var image = ee.Image(sortedCollection.toList(count).get(i));
    var dateString = image.get('system:index').getInfo();
    var pixelCount = image.get('pixelCount').getInfo();
    Map.addLayer(image.clip(chenhuaqu), colorizedVis1, 'Image: ' + dateString + ', Pixels: ' + pixelCount, 0);
  }

  var nodata = -9999;
  var Interp_range = 60; //*******************************此处可以修改为你自己的天数***************************
  var Landsat_NDVI_interp = linearInterp(Landsat_NDVI,Interp_range,nodata);
  Landsat_NDVI = Landsat_NDVI.toList(100)
  var numberOfImagesInList = Landsat_NDVI.size();
  print('Number of images in list:', numberOfImagesInList);
  
  // 计算每个图像的研究区像元数并添加为属性=============================================
  var withPixelCount_Inter = Landsat_NDVI_interp.map(function(image) {
  // 假设我们的NDVI波段名为'NDVI'
  var pixelCount = image.reduceRegion({
    reducer: ee.Reducer.count(),
    geometry: chenhuaqu,
    scale: 900, // 根据实际需要调整分辨率
    maxPixels: 1e9
  });
  // 使用波段名称作为键来获取计数
  return image.set('pixelCount', pixelCount.get('Landsat_NDVI_INTER'));
  });
  
  // 根据像元数对图像集合进行排序
  var sortedCollection_Inter = withPixelCount_Inter.sort('pixelCount', true);
  // 展示排序后的图像集合。
  var count_Inter = sortedCollection_Inter.size().getInfo();
  for (var j = 0; j < count_Inter; j++) {
    var image_Inter = ee.Image(sortedCollection_Inter.toList(count_Inter).get(j));
    var dateString_Inter = image_Inter.get('system:index').getInfo();
    var pixelCount_Inter = image_Inter.get('pixelCount').getInfo();
    Map.addLayer(image_Inter.select('Landsat_NDVI_INTER').clip(chenhuaqu), colorizedVis, 'Inter_Image: ' + dateString_Inter + ', Pixels: ' + pixelCount_Inter, 0);
    
    Export.image.toDrive({
      image: image_Inter,
      description: 'Landsat_NDVI_Interp_' + dateString_Inter,
      folder: 'NDVI_Export',
      scale: 30,
      region: chenhuaqu,
      maxPixels: 1e9,
    });
  }
  
  Landsat_NDVI_interp = Landsat_NDVI_interp.select('Landsat_NDVI_INTER').toList(100);
  print('Landsat_NDVI_interp',Landsat_NDVI_interp)
}
main();

结果对比:

在这里插入图片描述

在这里插入图片描述
  由此可见插值前后发生了巨大变化。

在这里插入图片描述

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

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

  在原有的基础上,我增加了显示遥感数据条带号的函数,这里可以结合我之前写个一篇博客进行学习:GEE26:遥感数据可用数据源计算及条带号制作

结果如下:
在这里插入图片描述

3.1 参数修改以适应其他类型的遥感数据

  这里我将介绍如何修改以上代码参数来增加代码的可用性。首先,我们需要对数据源进行修改:

var mod_sr = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2')
                .filterBounds(chenhuaqu)
                .filter(ee.Filter.calendarRange(2014,2023,'year'))
                .filter(ee.Filter.calendarRange(1,12,'month'))
                .map(applyScaleFactors)
                .map(rmCloudNew);

  此外,你需要修改function main()函数。首先,这里需要调整用于计算NDVI的波段以及质量评价波段,Landsat使用的是SR_B5和SR_B4,并且使用QA_PIXEL波段评价数据质量:

function main(){
  var Landsat_NDVI = mod_sr.filterDate(startDate,endDate).filterBounds(chenhuaqu)
   .map(function(image){return image.clip(chenhuaqu)})
   .map(function(image) {
   var ndvi = image.normalizedDifference(['SR_B5', 'SR_B4']);  //calculate Landsat NDVI
   var Q = image.select('QA_PIXEL'); // Pixel quality
   // 从原始图像中筛选出无云或云状态未设置的像素
   // 提取第8-11位(不可行)===============================================================
   // Bit 0: Fill; Bit 1: Dilated Cloud; Bit 2: Cirrus (high confidence);
   // Bit 3: Cloud; Bit 4: Cloud Shadow; Bit 5: Snow; Bit 6: Clear
   // Bits 8-9:Cloud Confidence:云层置信度,两位用来表示云层存在的可能性,从无到高
   // Bits 10-11: Cloud Shadow Confidence:云阴影置信度,两位用来表示云阴影存在的可能性,从无到高
   var masknum = getQABits(Q, 0, 4); 
   var mask = masknum.eq(ee.Image(0)).or(masknum.eq(ee.Image(64))); // 0001000000 = 64~[2*(7-1)=64]
   var ndvi_masked = ndvi.updateMask(mask);   //generate Landsat cloud mask from QA_PIXEL band (0:clear;1: cloud/shadow/mixed)
   
   return ndvi_masked.rename(['Landsat_NDVI']).copyProperties(image, image.propertyNames())
   });

QA_PIXEL介绍:

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

  这里我使用了第7位,即Bit6来构建无云天气的掩膜数据,即0001000000 = 64。

  再来看上面的MOD09Q1数据,使用的是:

   var masknum = getQABits(Q, 0, 2);
   var mask = masknum.eq(ee.Image(0)).or(masknum.eq(ee.Image(3)));

  即00000011=3,而其对应的质量评估字段名称为state:

在这里插入图片描述

3.2 Landsat数据汇总

最后,我汇中了所有的Landsat数据,读者可以选择满足自己条件的数据进行以上操作:

在这里插入图片描述

3.3 Sentinel卫星介绍

  • 哨兵-1卫星是全天时、全天候雷达成像任务,用于陆地和海洋观测,首颗哨兵-1A卫星已于2014年4月3日发射。
  • 哨兵-2卫星是多光谱高分辨率成像任务,用于陆地监测,可提供植被、土壤和水覆盖、内陆水路及海岸区域等图像,还可用于紧急救援服务。
  • 哨兵-3卫星携带多种有效载荷,用于高精度测量海面地形、海面和地表温度、海洋水色和土壤特性,还将支持海洋预报系统及环境与气候监测。
  • 哨兵-4载荷专用于大气化学成分监测,将搭载在第三代气象卫星-S(MTG-S)上。
  • 哨兵-5载荷用于监测大气环境,将搭载在欧洲第二代“气象业务”(MetOp)卫星上。
  • 哨兵-5P卫星用于减小欧洲“环境卫星”(Envisat)和哨兵-5载荷之间的数据缺口。
  • 哨兵-6卫星是贾森-3(Jason-3)海洋卫星的后续任务,将携带雷达高度计,用于测量全球海面高度,主要用于海洋科学和气候研究。
    在这里插入图片描述
    在这里插入图片描述

数据对比:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Jackson的生态模型

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

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

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

打赏作者

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

抵扣说明:

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

余额充值