如何使用GDAL重采样图像

本文介绍如何使用GDAL库进行图像重采样,并提供了一个详细的重采样函数示例,包括参数设置与调用流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

    在编写重采样图像时,可以使用GDAL来读写图像,然后自己编写重采样算法(最邻近像元法,双线性内插法,三次立方卷积法等)【关于这采样算法有时间我会单独写一篇文章来说明原理的】将计算的结果写入图像中来实现。

    在GDAL的算法中,已经提供了五种重采样算法,其定义如下(位置gdalwarper.h 的46行):

/*! Warp Resampling Algorithm */
typedef enum {
  /*! Nearest neighbour (select on one input pixel) */ GRA_NearestNeighbour=0,
  /*! Bilinear (2x2 kernel) */                         GRA_Bilinear=1,
  /*! Cubic Convolution Approximation (4x4 kernel) */  GRA_Cubic=2,
  /*! Cubic B-Spline Approximation (4x4 kernel) */     GRA_CubicSpline=3,
  /*! Lanczos windowed sinc interpolation (6x6 kernel) */ GRA_Lanczos=4
} GDALResampleAlg;

    在查看Gdalwarp的源代码发现,warp的功能非常强大,可以用来做投影转换,重投影,投影定义,重采样,镶嵌,几何精校正和影像配准等。一句话,很好很强大。下面就看看其中的一点点皮毛,使用warp来编写一个重采样的接口,代码如下:

/**
* 重采样函数(GDAL)
* @param pszSrcFile        输入文件的路径
* @param pszOutFile        写入的结果图像的路径
* @param fResX             X转换采样比,默认大小为1.0,大于1图像变大,小于1表示图像缩小
* @param fResY             Y转换采样比,默认大小为1.0
* @param nResampleMode     采样模式,有五种,具体参见GDALResampleAlg定义,默认为双线性内插
* @param pExtent           采样范围,为NULL表示计算全图
* @param pBandIndex        指定的采样波段序号,为NULL表示采样全部波段
* @param pBandCount        采样的波段个数,同pBandIndex一同使用,表示采样波段的个数
* @param pszFormat         写入的结果图像的格式
* @param pProgress         进度条指针
* @return 成功返回0,否则为其他值
*/
int ResampleGDAL(const char* pszSrcFile, const char* pszOutFile, float fResX , float fResY, LT_ResampleMode nResampleMode,
    LT_Envelope* pExtent, int* pBandIndex, int *pBandCount, const char* pszFormat,  LT_Progress *pProgress)
{
    if(pProgress != NULL)
    {
        pProgress->SetProgressCaption("重?采?样?");
        pProgress->SetProgressTip("正?在?执?行?重?采?样?...");
    }

    GDALAllRegister();
    GDALDataset *pDSrc = (GDALDataset *)GDALOpen(pszSrcFile, GA_ReadOnly);
    if (pDSrc == NULL)
    {
        if(pProgress != NULL)
            pProgress->SetProgressTip("指?定?的?文?件?不?存?在?,?或?者?该?格?式?不?被?支?持?!?");

        return RE_NOFILE;
    }

    GDALDriver *pDriver = GetGDALDriverManager()->GetDriverByName(pszFormat);
    if (pDriver == NULL)
    {
        if(pProgress != NULL)
            pProgress->SetProgressTip("不?能?创?建?该?格?式?的?文?件?!?");

        GDALClose((GDALDatasetH) pDSrc);
        return RE_CREATEFILE;
    }

    int iBandCount = pDSrc->GetRasterCount();
    string strWkt = pDSrc->GetProjectionRef();
    GDALDataType dataType = pDSrc->GetRasterBand(1)->GetRasterDataType();

    double dGeoTrans[6] = {0};
    pDSrc->GetGeoTransform(dGeoTrans);

    int iNewBandCount = iBandCount;
    if (pBandIndex != NULL && pBandCount != NULL)
    {
        int iMaxBandIndex = pBandIndex[0];    //找?出?最?大?的?波?段?索?引?序?号?
        for (int i=1; i<*pBandCount; i++)
        {
            if (iMaxBandIndex < pBandIndex[i])
                iMaxBandIndex = pBandIndex[i];
        }

        if(iMaxBandIndex > iBandCount)
        {
            if(pProgress != NULL)
                pProgress->SetProgressTip("指?定?的?波?段?序?号?超?过?图?像?的?波?段?数?,?请?检?查?输?入?参?数?!?");

            GDALClose((GDALDatasetH) pDSrc);
            return RE_PARAMERROR;
        }
        
        iNewBandCount = *pBandCount;
    }

    LT_Envelope enExtent;
    enExtent.setToNull();

    if (pExtent == NULL)    //全?图?计?算?
    {
        double dPrj[4] = {0};    //x1,x2,y1,y2
        ImageRowCol2Projection(dGeoTrans, 0, 0, dPrj[0], dPrj[2]);
        ImageRowCol2Projection(dGeoTrans, pDSrc->GetRasterXSize(), pDSrc->GetRasterYSize(), dPrj[1], dPrj[3]);
        enExtent.init(dPrj[0], dPrj[1], dPrj[2], dPrj[3]);

        pExtent = &enExtent;
    }
    
    dGeoTrans[0] = pExtent->getMinX();
    dGeoTrans[3] = pExtent->getMaxY();
    dGeoTrans[1] = dGeoTrans[1] / fResX;
    dGeoTrans[5] = dGeoTrans[5] / fResY;

    int iNewWidth  = static_cast<int>( (pExtent->getMaxX() - pExtent->getMinX() / ABS(dGeoTrans[1]) + 0.5) );
    int iNewHeight = static_cast<int>( (pExtent->getMaxX() - pExtent->getMinX() / ABS(dGeoTrans[5]) + 0.5) );

    GDALDataset *pDDst = pDriver->Create(pszOutFile, iNewWidth, iNewHeight, iNewBandCount, dataType, NULL);
    if (pDDst == NULL)
    {
        if(pProgress != NULL)
            pProgress->SetProgressTip("创?建?输?出?文?件?失?败?!?");

        GDALClose((GDALDatasetH) pDSrc);
        return RE_CREATEFILE;
    }

    pDDst->SetProjection(strWkt.c_str());
    pDDst->SetGeoTransform(dGeoTrans);

    GDALResampleAlg eResample = (GDALResampleAlg) nResampleMode;

    if(pProgress != NULL)
    {
        pProgress->SetProgressTip("正?在?执?行?重?采?样?...");
        pProgress->SetProgressTotalStep(iNewBandCount*iNewHeight);
    }

    int *pSrcBand = NULL;
    int *pDstBand = NULL;
    int iBandSize = 0;
    if (pBandIndex != NULL && pBandCount != NULL)
    {
        iBandSize = *pBandCount;
        pSrcBand = new int[iBandSize];
        pDstBand = new int[iBandSize];

        for (int i=0; i<iBandSize; i++)
        {
            pSrcBand[i] = pBandIndex[i];
            pDstBand[i] = i+1;
        }
    }
    else
    {
        iBandSize = iBandCount;
        pSrcBand = new int[iBandSize];
        pDstBand = new int[iBandSize];

        for (int i=0; i<iBandSize; i++)
        {
            pSrcBand[i] = i+1;
            pDstBand[i] = i+1;
        }
    }
    
    void *hTransformArg = NULL, *hGenImgPrjArg = NULL;
    hTransformArg = hGenImgPrjArg = GDALCreateGenImgProjTransformer2((GDALDatasetH) pDSrc, (GDALDatasetH) pDDst, NULL);
    if (hTransformArg == NULL)
    {
        if(pProgress != NULL)
            pProgress->SetProgressTip("转?换?参?数?错?误?!?");

        GDALClose((GDALDatasetH) pDSrc);
        GDALClose((GDALDatasetH) pDDst);
        return RE_PARAMERROR;
    }
    
    GDALTransformerFunc pFnTransformer = GDALGenImgProjTransform;
    GDALWarpOptions *psWo = GDALCreateWarpOptions();

    psWo->papszWarpOptions = CSLDuplicate(NULL);
    psWo->eWorkingDataType = dataType;
    psWo->eResampleAlg = eResample;

    psWo->hSrcDS = (GDALDatasetH) pDSrc;
    psWo->hDstDS = (GDALDatasetH) pDDst;

    psWo->pfnTransformer = pFnTransformer;
    psWo->pTransformerArg = hTransformArg;

    psWo->pfnProgress = GDALProgress;
    psWo->pProgressArg = pProgress;

    psWo->nBandCount = iNewBandCount;
    psWo->panSrcBands = (int *) CPLMalloc(iNewBandCount*sizeof(int));
    psWo->panDstBands = (int *) CPLMalloc(iNewBandCount*sizeof(int));
    for (int i=0; i<iNewBandCount; i++)
    {
        psWo->panSrcBands[i] = pSrcBand[i];
        psWo->panDstBands[i] = pDstBand[i];
    }

    RELEASE(pSrcBand);
    RELEASE(pDstBand);

    GDALWarpOperation oWo;
    if (oWo.Initialize(psWo) != CE_None)
    {
        if(pProgress != NULL)
            pProgress->SetProgressTip("转?换?参?数?错?误?!?");

        GDALClose((GDALDatasetH) pDSrc);
        GDALClose((GDALDatasetH) pDDst);

        return RE_PARAMERROR;
    }

    oWo.ChunkAndWarpImage(0, 0, iNewWidth, iNewHeight);
    
    GDALDestroyGenImgProjTransformer(psWo->pTransformerArg);
    GDALDestroyWarpOptions( psWo );
    GDALClose((GDALDatasetH) pDSrc);
    GDALClose((GDALDatasetH) pDDst);

    if(pProgress != NULL)
        pProgress->SetProgressTip("重?采?样?完?成?!?");

    return RE_SUCCESS;
}

    PS:在使用Windows Live Writer来写博客,使用VSPaste插件粘贴代码的时候,发现会在汉字后面加一个“?”号,我懒得修改了,大家就凑合看看吧!

### C++ 中使用 GDAL 进行重采样的方法 在 C++ 编程环境中,GDAL 提供了一组强大的工具来处理地理空间数据集的操作,其中包括图像重采样功能。以下是关于如何通过 C++ 使用 GDAL 实现重采样的详细介绍。 #### 1. 配置环境并加载必要的库 为了能够成功运行基于 GDAL 的程序,首先需要确保已安装 GDAL 库及其开发头文件,并将其链接到项目中[^2]。通常情况下,在 Linux 或 macOS 上可以通过包管理器完成此操作;而在 Windows 平台上则可能需要用到预编译二进制版本或者自行构建源码。 #### 2. 初始化 GDAL 和打开目标数据集 在实际编写代码之前,先要初始化 GDAL 并注册所有的驱动程序以便支持多种格式的数据读写。接着可以利用 `GDALOpen` 函数打开输入影像作为待处理对象[^3]。 ```cpp #include "gdal_priv.h" #include "cpl_conv.h" // Initialize GDAL. GDALAllRegister(); const char* pszFilename = "/path/to/input_file.tif"; GDALDatasetH hSrcDS = GDALOpen(pszFilename, GA_ReadOnly); if (hSrcDS == nullptr) { std::cerr << "Failed to open dataset." << std::endl; } ``` #### 3. 定义输出参数以及设置重采样算法 创建一个新的虚拟内存中的临时栅格文件用于存储结果,并指定其大小、像素类型以及其他元信息等内容。同时还需要决定采用哪种具体的重采样技术(例如最近邻法 Nearest Neighbor、双线性插值 Bilinear 等),这一步骤可通过调用特定函数实现[^4]。 ```cpp int nXSizeOut = ...; // Set desired output width here. int nYSizeOut = ...; // Set desired height accordingly. GDALDriverH hMemDriver = GDALGetDriverByName("MEM"); GDALDatasetH hDstDS = GDALCreate(hMemDriver, "", nXSizeOut, nYSizeOut, GDALGetRasterCount(hSrcDS), GDT_Float32, nullptr); double adfGeoTransform[6]; GDALGetGeoTransform(hSrcDS, adfGeoTransform); adfGeoTransform[1] *= static_cast<double>(nXSizeIn)/static_cast<double>(nXSizeOut); adfGeoTransform[5] *= static_cast<double>(nYSizeIn)/static_cast<double>(nYSizeOut); GDALSetGeoTransform(hDstDS, adfGeoTransform); char **papszWarpOptions = CSLSetNameValue(nullptr,"RESAMPLE_ALG","bilinear"); GDALWarpOptions *psWOpts = GDALCreateWarpOptions(); psWOpts->hDestDS = hDstDS; psWOpts->pszDestAlphaBand = nullptr; psWOpts->pfnProgress = GDALTermProgress; psWOpts->papszDSTOption = papszWarpOptions; GDALWarpOperation oWarper; oWarper.Initialize(psWOpts); oWarper.ChunkAndWarpImage(GDALGetRasterXSize(hSrcDS), GDALGetRasterYSize(hSrcDS)); GDALDestroyGenImgProjTransformer(psWOpts->pTransformerArg, psWOpts->pfnTransformer); GDALDeinitWarpOptions(psWOpts); CSLDestroy(papszWarpOptions); ``` 以上片段展示了完整的流程框架,其中包含了几个重要部分:定义输出尺寸与坐标变换关系;选择合适的重采样策略并通过 API 调用来执行具体任务。 #### 4. 导出最终成果至磁盘或其他媒介上保存下来 当完成了上述所有步骤之后,就可以考虑将得到的新图层导出成常规格式存档起来以备后续分析之需了。这里我们再次运用到了先前提到过的某些概念和技术手段[^5]。 --- ### 总结说明 综上所述,借助于 GDAL 提供给开发者的一系列接口和服务,可以在 C++ 环境下高效便捷地达成对遥感图片或者其他形式的空间数据实施重采样的目的。不过需要注意的是,实际应用过程中可能会遇到各种复杂情况,因此建议深入学习官方文档及相关资料进一步提升技能水平。
评论 77
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值