• 如何使用GDAL重采样图像


        在编写重采样图像时,可以使用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插件粘贴代码的时候,发现会在汉字后面加一个“?”号,我懒得修改了,大家就凑合看看吧!

  • 相关阅读:
    SQLServer提取日期中的年月日及其他格式
    大白话解说,半分钟就懂 --- 分布式与集群是什么 ? 区别是什么?
    VS2015 Git 源码管理工具简单入门
    Web.Config配置文件中customErrors元素的使用方法
    C#发起Http请求,调用接口
    如何停止和禁用Linux系统中的不需要的服务
    QtCreator调试传入运行参数
    gSOAP 在windows下的安装与使用(mingw32)
    MinGW 使用 mintty 终端替代默认终端以解决界面上复制与粘贴的问题
    在windows下执行./configure,make,makeinstall源码安装程序spice-gtk
  • 原文地址:https://www.cnblogs.com/xiaowangba/p/6314058.html
Copyright © 2020-2023  润新知