gdal重采样深度讲解(前后不改变数据总量算法)(比arcgis好用)

从本科学习arcgis开始,就一直没有离开过重采样,arcgis里重采样方法大概有一下4种:

  • NEAREST— The fastest resampling method; it minimizes changes to pixel values. Suitable for discrete data, such as land cover.
  • BILINEAR— Calculates the value of each pixel by averaging (weighted for distance) the values of the surrounding 4 pixels. Suitable for continuous data.
  • CUBIC— Calculates the value of each pixel by fitting a smooth curve based on the surrounding 16 pixels. Produces the smoothest image but can create values outside of the range found in the source data. Suitable for continuous data.
  • MAJORITY— Determines the value of each pixel based on the most popular value within a 3 by 3 window. Suitable for discrete data

但是可以很容易发现这4种方法其实都对改变了原始数据计算的结果:比如本来有这样一个4*4网格,如果网格的值代表了NPP(g/m2),每个网格1m2,这块土地的NPP总量为15+10=25g,当采用Nearest的方法重采样到5*5的网格,得到的结果如下:

此时NPP的总量为24*0.64+10*0.64=21.76g,和之前有3.24g的区别,这个误差还是值得考虑的。所以真正的无误差算法应该是计算新网格内旧网格值对应面积的加权值,arcgis里的4种方法都不是这样的,但是最近发现gdal函数里有一个Average方法,这个函数可以完全实现总量不变:

计算后的NPP总量:0.64*(10+3.25*2+1.5625+21)=25,每个网格的值相当于把5*5的网格放在4*4的网格上,再计算出的平均值,十分适合这种需要总量不变的情况。

当然啦,重采样的方法还是要看你处理数据的需要了,如果处理土地利用数据,当然要用Nearest方法啦。另外还有Bilinear、Cubic等各种重采样方法,我这里就不详细展开了。

最后附上我的测试代码(只要更改路径就可以直接运行):

import numpy as np
import gdal
import gdalconst
#---------------------更改输入路径----------------------------------
pathin = ''
#------------------------------------------------------------------
proj_ori = 'GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AXIS["Latitude",NORTH],AXIS["Longitude",EAST],AUTHORITY["EPSG","4326"]]'
gt_ori = (0.0, 0.25, 0.0, 0.0, 0.0, -0.25)
#-----------------创建实验mask 4*4-----------------------------------------
out_ds = gdal.GetDriverByName('GTiff').Create(pathin+'test.tif' ,4,4,1,gdalconst.GDT_Float32,
                                                 ['COMPRESS=LZW'])#path, im_width, im_height, im_bands, datatype
out_ds.SetProjection(proj_ori)
GetGeoTransform = [0,0.25,0,0,0,-0.25]
out_ds.SetGeoTransform(GetGeoTransform)
ra = np.ones((4,4))
ra[0,0]=10#给位于(1,1)位置的像元赋值10,方便后面解释算法
out_band = out_ds.GetRasterBand(1).WriteArray(ra)
del out_ds
#-----------------读取实验mask的参数以传递给重采样后的mask---------------------
#Nearest
ras_ori  = gdal.Open(pathin + 'test.tif')
proj_ori = ras_ori.GetProjection()
gt_ori   = ras_ori.GetGeoTransform()
gt_dst = list(gt_ori)
gt_dst[1] = 0.2#更改分辨率
gt_dst[5] = -0.2
gt_dst = tuple(gt_dst)                        #得到geotransform_dst
ras_dst = gdal.GetDriverByName('GTiff').Create(pathin+'Nearest.tif',5,5,
                                               1,gdalconst.GDT_Float32,
                                               ['COMPRESS=LZW'])
ras_dst.SetGeoTransform(gt_dst)
ras_dst.SetProjection(proj_ori)
gdal.ReprojectImage(ras_ori,ras_dst,proj_ori,proj_ori,gdalconst.GRA_NearestNeighbour)
del ras_ori
del ras_dst



#Average
ras_ori  = gdal.Open(pathin + 'test.tif')
proj_ori = ras_ori.GetProjection()
gt_ori   = ras_ori.GetGeoTransform()
gt_dst = list(gt_ori)
gt_dst[1] = 0.2#更改分辨率
gt_dst[5] = -0.2
gt_dst = tuple(gt_dst)                        #得到geotransform_dst
ras_dst = gdal.GetDriverByName('GTiff').Create(pathin+'average.tif',5,5,
                                               1,gdalconst.GDT_Float32,
                                               ['COMPRESS=LZW'])
ras_dst.SetGeoTransform(gt_dst)
ras_dst.SetProjection(proj_ori)
gdal.ReprojectImage(ras_ori,ras_dst,proj_ori,proj_ori,gdalconst.GRA_Average)
del ras_ori
del ras_dst

 

  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
您好!对于使用C++和GDAL库进行采样的问题,您可以按照以下步骤进行操作: 1. 首先,确保您已经安装了GDAL库,并将其包含在您的C++项目中。您可以从GDAL官方网站(https://gdal.org/)下载并安装GDAL。 2. 在您的C++代码中,包含GDAL的头文件: ```cpp #include <gdal_priv.h> ``` 3. 创建一个GDAL数据集对象,并打开源图像文件: ```cpp GDALAllRegister(); // 注册所有的GDAL驱动 // 打开源图像文件 GDALDataset* srcDataset = (GDALDataset*)GDALOpen("path_to_source_image", GA_ReadOnly); if (srcDataset == nullptr) { // 处理打开源图像文件失败的情况 } ``` 4. 定义目标图像的宽度、高度和波段数目,并创建一个新的GDAL数据集对象: ```cpp int targetWidth = 800; // 目标图像宽度 int targetHeight = 600; // 目标图像高度 int targetBands = srcDataset->GetRasterCount(); // 目标图像波段数目与源图像相同 // 创建新的目标图像数据GDALDriver* memDriver = GetGDALDriverManager()->GetDriverByName("MEM"); GDALDataset* targetDataset = memDriver->Create("", targetWidth, targetHeight, targetBands, GDT_Byte, nullptr); if (targetDataset == nullptr) { // 处理创建目标图像数据集失败的情况 } ``` 5. 使用GDAL库提供的采样方法,将源图像数据写入目标图像数据集中: ```cpp GDALResampleAlg resampleMethod = GRA_Bilinear; // 采样方法,这里使用双线性插值 // 采样 for (int band = 0; band < targetBands; ++band) { GDALRasterBand* srcBand = srcDataset->GetRasterBand(band + 1); // 获取源图像波段 GDALRasterBand* targetBand = targetDataset->GetRasterBand(band + 1); // 获取目标图像波段 // 执行采样 GDALReprojectImage(srcBand, nullptr, targetBand, nullptr, resampleMethod); } ``` 6. 完成采样后,您可以将目标图像保存到磁盘上: ```cpp GDALDriver* driver = GetGDALDriverManager()->GetDriverByName("GTiff"); // 指定保存为GeoTIFF格式 driver->CreateCopy("path_to_target_image", targetDataset, 0, nullptr, nullptr, nullptr); ``` 7. 最后,别忘记释放使用的内存和关闭数据集: ```cpp GDALClose(srcDataset); // 关闭源图像数据GDALClose(targetDataset); // 关闭目标图像数据集 ``` 这些步骤提供了一个基本的框架,您可以根据您的具体需求进行修改和扩展。希望能对您有所帮助!如果您还有其他问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值