GDAL使用(三)
GDALWarp的功能比较强大,可用于影像投影/重投影、图像镶嵌、重采样、规则裁切、图像校正等。
GDALWarp API定义在头文件gdalwarper.h中。主要有两部分构成:
GDALWarpOptions和 GDALWarpOperation
如字面意思,GDALWarpOperation主要用来执行变换操作,GDALWarpOptions主要是对变换的一些选项进行设置。
1、GDALWarpOptions
这是个结构体,在头文件中的定义如下:
点击查看结构体
/************************************************************************/ /* GDALWarpOptions */ /************************************************************************/ /** Warp control options for use with GDALWarpOperation::Initialize() */ typedef struct { char **papszWarpOptions; /*! In bytes, 0.0 for internal default */ double dfWarpMemoryLimit; /*! Resampling algorithm to use */ GDALResampleAlg eResampleAlg; /*! data type to use during warp operation, GDT_Unknown lets the algorithm select the type */ GDALDataType eWorkingDataType; /*! Source image dataset. */ GDALDatasetH hSrcDS; /*! Destination image dataset - may be NULL if only using GDALWarpOperation::WarpRegionToBuffer(). */ GDALDatasetH hDstDS; /*! Number of bands to process, may be 0 to select all bands. */ int nBandCount; /*! The band numbers for the source bands to process (1 based) */ int *panSrcBands; /*! The band numbers for the destination bands to process (1 based) */ int *panDstBands; /*! The source band so use as an alpha (transparency) value, 0=disabled */ int nSrcAlphaBand; /*! The dest. band so use as an alpha (transparency) value, 0=disabled */ int nDstAlphaBand; /*! The "nodata" value real component for each input band, if NULL there isn't one */ double *padfSrcNoDataReal; /*! The "nodata" value imaginary component - may be NULL even if real component is provided. This value is not used to flag invalid values. Only the real component is used. */ double *padfSrcNoDataImag; /*! The "nodata" value real component for each output band, if NULL there isn't one */ double *padfDstNoDataReal; /*! The "nodata" value imaginary component - may be NULL even if real component is provided. Note that warp operations only use real component for flagging invalid data.*/ double *padfDstNoDataImag; /*! GDALProgressFunc() compatible progress reporting function, or NULL if there isn't one. */ GDALProgressFunc pfnProgress; /*! Callback argument to be passed to pfnProgress. */ void *pProgressArg; /*! Type of spatial point transformer function */ GDALTransformerFunc pfnTransformer; /*! Handle to image transformer setup structure */ void *pTransformerArg; /** Unused. Must be NULL */ GDALMaskFunc *papfnSrcPerBandValidityMaskFunc; /** Unused. Must be NULL */ void **papSrcPerBandValidityMaskFuncArg; /** Unused. Must be NULL */ GDALMaskFunc pfnSrcValidityMaskFunc; /** Unused. Must be NULL */ void *pSrcValidityMaskFuncArg; /** Unused. Must be NULL */ GDALMaskFunc pfnSrcDensityMaskFunc; /** Unused. Must be NULL */ void *pSrcDensityMaskFuncArg; /** Unused. Must be NULL */ GDALMaskFunc pfnDstDensityMaskFunc; /** Unused. Must be NULL */ void *pDstDensityMaskFuncArg; /** Unused. Must be NULL */ GDALMaskFunc pfnDstValidityMaskFunc; /** Unused. Must be NULL */ void *pDstValidityMaskFuncArg; /** Unused. Must be NULL */ CPLErr (*pfnPreWarpChunkProcessor)( void *pKern, void *pArg ); /** Unused. Must be NULL */ void *pPreWarpProcessorArg; /** Unused. Must be NULL */ CPLErr (*pfnPostWarpChunkProcessor)( void *pKern, void *pArg); /** Unused. Must be NULL */ void *pPostWarpProcessorArg; /*! Optional OGRPolygonH for a masking cutline. */ void *hCutline; /*! Optional blending distance to apply across cutline in pixels, default is zero. */ double dfCutlineBlendDist; } GDALWarpOptions;
下面对结构体的成员进行说明:
papszWarpOptions
char** 类型,控制warp操作,是格式为“name=value”的字符串数组,可以使用CSLSetNameValue()来构造该字符数组。选项的具体说明见如下链接:https://www.osgeo.cn/gdal/api/gdalwarp_cpp.html#_CPPv4N15GDALWarpOptions16papszWarpOptionsE
dfMemoryLimit
double 类型,用于指定图像变换时使用的内存大小,单位为字节,为0.0时系统内部自动分配
eResampleAlg
GDALResampleAlg 类型,指示变换时的重采样方法,包含了大部分常用的重采样方法,具体方法见以下链接:
https://www.osgeo.cn/gdal/api/gdalwarp_cpp.html?highlight=gdalwarpoptions#_CPPv415GDALResampleAlg
eWorkingDataType
GDALDataType 类型,指示在图像变换时使用的数据类型。设置为GDT_Unknown时算法自动选择数据类型。类型的具体说明见以下链接:
https://www.osgeo.cn/gdal/api/raster_c_api.html#_CPPv412GDALDataType
hSrcDS
GDALDatasetH 格式,原始影像数据集。
hDstDS
GDALDatasetH格式,目标数据集。
nBandCount
int 类型,要处理的波段数目,如果为0,将处理所有波段。
panSrcBands
int* 类型,指定要处理的原始图像的波段序号,序号从1开始。
panDstBands
int* 类型,指定要处理的原结果图像的波段序号,序号从1开始。
nSrcAlphaBand
int 类型,指定原始图像所 使用的Alpha 通道( 透明 通道)序号, 默认值为0,表示 没有。
nDstAlphaBand
int 类型,指定结果图像所使用的 Alpha 通道( 透明 通道)序号,默认值 为 0,表示没有。
padfSrcNoDataReal
double* 类型,该变量指定原始图像中实部的NoData值,NULL表示没有(对于复数图像来说)。
padfSrcNoDataImag
double* 类型,该变量指定原始图像中虚部的NoData值,NULL表示没有(对于复数图像来说)。
padfDstNoDataReal
double* 类型,该变量指定结果图像中实部的NoData值,NULL表示没有(对于复数图像来说)。
padfDstNoDataImag
double* 类型,该变量指定结果图像中虚部的NoData值,NULL表示没有(对于复数图像来说)。
pfnProgress
GDALProgressFunc 类型,进度条信息函数指针
pProgressArg
void* 类型,进度条函数的参数指针。
pfnTransformer
GDALTransformerFunc 类型,图像坐标变换函数指针,这是核心函数,用来确定图像变换的方式。
pTransformerArg
void* 类型,图像坐标变换函数所需要的结构体指针参数。
hCutline
void* 类型,该变量使用OGRPolygonH指定 一个裁切范围,作为掩码区域。默认为 NULL,表示 处理全图。
dfCutlineBlendDist
double 类型,该变量指定在使用hCutline作为掩码区域时的羽化距离。默认为0。
最后,这个结构体指针可以使用GDALCreateWarpOption()函数进行创建,这个函数的返回值直接就是GDALWarpOptions*类型。
2、GDALWarpOperation
是负责对图像进行读取、分块和写入操作的类。
函数:Initialize
原型:CPLErr Initialize(constGDALWarpOptions *psNewOptions)
参数:psNewOptions:constGDALWarpOptions *类型,就是上面一节说的结构体指针。
返回值:是否初始化成功
函数:GetOptions
原型:const GDALWarpOptions *GetOptions()
返回值:返回上一节说的结构体指针
函数:ChunkAndWarpImage
原型:CPLErr ChunkAndWarpImage(int nDstXOff, int nDstYOff, int nDstXSize, int nDstYSize)
参数:nDstXOff:结果数据X起始坐标,字面意思就是X方向的偏移量,nDstYOff:结果数据Y起始坐标,nDstXSize:结果数据宽度,nDstYSize:结果数据高度
返回值:是否执行成功
函数:ChunkAndWarpMulti
原型:CPLErr ChunkAndWarpMulti(int nDstXOff, int nDstYOff, int nDstXSize, int nDstYSize)
参数与返回值与第三条中的一样,功能也相同,不过内部是多线程操作的
其它函数参考下面链接:
https://www.osgeo.cn/gdal/api/gdalwarp_cpp.html#classGDALWarpOperation
3、重投影代码
这里的例子是将一幅未投影影像投影到投影坐标下。
原始数据:海洋一号C卫星(HY-1C)L1C数据,此原始数据为WGS84坐标系,一共4个波段。
目标数据:这里目标是将原始数据投影到投影坐标系下,目标空间参考为 Asia North Albers Equal Area Conic,此坐标系为WGS84椭球下的等积圆锥投影,且数据的分辨率约为50m,这里让GDAL自己计算合适的分辨率。
#include <iostream> #include "gdal_priv.h" #include "cpl_conv.h" #include <cpl_string.h> #include <gdalwarper.h> int main() { clock_t start = clock(); GDALAllRegister(); GDALDriverH hDriver; GDALDataType eDT; GDALDatasetH hDstDS; GDALDatasetH hSrcDS; // 打开源文件 hSrcDS = GDALOpen("E:\testdata\CZIOrigin.tiff", GA_ReadOnly); CPLAssert(hSrcDS != NULL); // 获取数据类型 eDT = GDALGetRasterDataType(GDALGetRasterBand(hSrcDS, 1)); // 获取输入数据的栅格驱动 (GeoTIFF格式) hDriver = GDALGetDriverByName("GTiff"); CPLAssert(hDriver != NULL); // 获取源数据坐标系统 const char* pszSrcWKT; char* pszDstWKT = NULL; pszSrcWKT = GDALGetProjectionRef(hSrcDS); CPLAssert(pszSrcWKT != NULL && strlen(pszSrcWKT) > 0); // 设置输出坐标系为 OGRSpatialReference oSRS; oSRS.importFromProj4("+proj=aea +lat_1=15 +lat_2=65 +lat_0=30 +lon_0=95 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs"); oSRS.exportToWkt(&pszDstWKT); printf("%s ", pszDstWKT); // Create a transformer that maps from source pixel/line coordinates // to destination georeferenced coordinates (not destination // pixel line). We do that by omitting the destination dataset // handle (setting it to NULL). void* hTransformArg = GDALCreateGenImgProjTransformer(hSrcDS, pszSrcWKT, NULL, pszDstWKT, FALSE, 0, 1); CPLAssert(hTransformArg != NULL); //计算大概的范围和分辨率 double adfDstGeoTransform[6]; int nPixels = 0, nLines = 0; CPLErr eErr; eErr = GDALSuggestedWarpOutput(hSrcDS, GDALGenImgProjTransform, hTransformArg, adfDstGeoTransform, &nPixels, &nLines); CPLAssert(eErr == CE_None); // 创建输出文件 hDstDS = GDALCreate(hDriver, "O:\CZIproject.tif", nPixels, nLines, GDALGetRasterCount(hSrcDS), eDT, NULL); CPLAssert(hDstDS != NULL); //设置投影 GDALSetProjection(hDstDS, pszDstWKT); //设置地理变换参数 GDALSetGeoTransform(hDstDS, adfDstGeoTransform); //如果需要的话,复制颜色表 GDALColorTableH hCT; hCT = GDALGetRasterColorTable(GDALGetRasterBand(hSrcDS, 1)); if (hCT != NULL) GDALSetRasterColorTable(GDALGetRasterBand(hDstDS, 1), hCT); //设置warp选项 GDALWarpOptions* psWarpOptions = GDALCreateWarpOptions(); psWarpOptions->hSrcDS = hSrcDS;//设置源数据集 psWarpOptions->hDstDS = hDstDS;//设置目的数据集 psWarpOptions->nBandCount = 0;//要处理的波段数,0的话是选择所有波段 psWarpOptions->pfnProgress = GDALTermProgress;//控制台进度条函数 //建立重投影变换 psWarpOptions->pTransformerArg = GDALCreateGenImgProjTransformer(hSrcDS, GDALGetProjectionRef(hSrcDS), hDstDS, GDALGetProjectionRef(hDstDS), FALSE, 0.0, 1); psWarpOptions->pfnTransformer = GDALGenImgProjTransform; //初始化并执行warp操作 GDALWarpOperation oOperation; oOperation.Initialize(psWarpOptions); oOperation.ChunkAndWarpImage(0, 0, GDALGetRasterXSize(hDstDS), GDALGetRasterYSize(hDstDS));//这是实际执行warp的函数 //释放资源 GDALDestroyGenImgProjTransformer(hTransformArg); GDALClose(hDstDS); GDALClose(hSrcDS); clock_t end = clock(); double endtime = (double)(end - start) / CLOCKS_PER_SEC; printf("time elapse: %f ", endtime); system("pause"); return 0; }
下面的是投影前后的空间参考信息,可以看到GDAL自己计算出的像元大小约为46.2250m
以上部分内容参考:
[1] 李民录. GDAL源码剖析与开发指南(异步图书). 人民邮电出版社. Kindle 版本.
[2] https://www.osgeo.cn/gdal/index.html