zoukankan      html  css  js  c++  java
  • 如何使用GDAL进行AOI裁剪

        在工作中,会经常使用一个行政区的矢量图去裁剪一个遥感影像图,得到该行政区的影像图,一般的商业遥感软件都具有这个功能。今天就是用GDAL来实现这一个很实用的功能。首先用到的是GDAL中的gdalwarp,又是warp,呵呵,上一篇就是使用warp进行重采样的。

       首先需要用到gdal源码目录里面的app文件夹下的gdalwarp.cpp文件中的几个函数,大概行数是1651行,直到文件结尾,代码如下:

    /************************************************************************/
    /*                      GeoTransform_Transformer()                      */
    /*                                                                      */
    /*      Convert points from georef coordinates to pixel/line based      */
    /*      on a geotransform.                                              */
    /************************************************************************/
    
    class CutlineTransformer : public OGRCoordinateTransformation
    {
    public:
    
        void         *hSrcImageTransformer;
    
        virtual OGRSpatialReference *GetSourceCS() { return NULL; }
        virtual OGRSpatialReference *GetTargetCS() { return NULL; }
    
        virtual int Transform( int nCount, 
                               double *x, double *y, double *z = NULL ) {
            int nResult;
    
            int *pabSuccess = (int *) CPLCalloc(sizeof(int),nCount);
            nResult = TransformEx( nCount, x, y, z, pabSuccess );
            CPLFree( pabSuccess );
    
            return nResult;
        }
    
        virtual int TransformEx( int nCount, 
                                 double *x, double *y, double *z = NULL,
                                 int *pabSuccess = NULL ) {
            return GDALGenImgProjTransform( hSrcImageTransformer, TRUE, 
                                            nCount, x, y, z, pabSuccess );
        }
    };
    
    
    /************************************************************************/
    /*                            LoadCutline()                             */
    /*                                                                      */
    /*      Load blend cutline from OGR datasource.                         */
    /************************************************************************/
    
    static void
    LoadCutline( const char *pszCutlineDSName, const char *pszCLayer, 
                 const char *pszCWHERE, const char *pszCSQL, 
                 void **phCutlineRet )
    
    {
    #ifndef OGR_ENABLED
        CPLError( CE_Failure, CPLE_AppDefined, 
                  "Request to load a cutline failed, this build does not support OGR features./n" );
        exit( 1 );
    #else // def OGR_ENABLED
        OGRRegisterAll();
    
    /* -------------------------------------------------------------------- */
    /*      Open source vector dataset.                                     */
    /* -------------------------------------------------------------------- */
        OGRDataSourceH hSrcDS;
    
        hSrcDS = OGROpen( pszCutlineDSName, FALSE, NULL );
        if( hSrcDS == NULL )
            exit( 1 );
    
    /* -------------------------------------------------------------------- */
    /*      Get the source layer                                            */
    /* -------------------------------------------------------------------- */
        OGRLayerH hLayer = NULL;
    
        if( pszCSQL != NULL )
            hLayer = OGR_DS_ExecuteSQL( hSrcDS, pszCSQL, NULL, NULL ); 
        else if( pszCLayer != NULL )
            hLayer = OGR_DS_GetLayerByName( hSrcDS, pszCLayer );
        else
            hLayer = OGR_DS_GetLayer( hSrcDS, 0 );
    
        if( hLayer == NULL )
        {
            fprintf( stderr, "Failed to identify source layer from datasource./n" );
            exit( 1 );
        }
    
    /* -------------------------------------------------------------------- */
    /*      Apply WHERE clause if there is one.                             */
    /* -------------------------------------------------------------------- */
        if( pszCWHERE != NULL )
            OGR_L_SetAttributeFilter( hLayer, pszCWHERE );
    
    /* -------------------------------------------------------------------- */
    /*      Collect the geometries from this layer, and build list of       */
    /*      burn values.                                                    */
    /* -------------------------------------------------------------------- */
        OGRFeatureH hFeat;
        OGRGeometryH hMultiPolygon = OGR_G_CreateGeometry( wkbMultiPolygon );
    
        OGR_L_ResetReading( hLayer );
        
        while( (hFeat = OGR_L_GetNextFeature( hLayer )) != NULL )
        {
            OGRGeometryH hGeom = OGR_F_GetGeometryRef(hFeat);
    
            if( hGeom == NULL )
            {
                fprintf( stderr, "ERROR: Cutline feature without a geometry./n" );
                exit( 1 );
            }
            
            OGRwkbGeometryType eType = wkbFlatten(OGR_G_GetGeometryType( hGeom ));
    
            if( eType == wkbPolygon )
                OGR_G_AddGeometry( hMultiPolygon, hGeom );
            else if( eType == wkbMultiPolygon )
            {
                int iGeom;
    
                for( iGeom = 0; iGeom < OGR_G_GetGeometryCount( hGeom ); iGeom++ )
                {
                    OGR_G_AddGeometry( hMultiPolygon, 
                                       OGR_G_GetGeometryRef(hGeom,iGeom) );
                }
            }
            else
            {
                fprintf( stderr, "ERROR: Cutline not of polygon type./n" );
                exit( 1 );
            }
    
            OGR_F_Destroy( hFeat );
        }
    
        if( OGR_G_GetGeometryCount( hMultiPolygon ) == 0 )
        {
            fprintf( stderr, "ERROR: Did not get any cutline features./n" );
            exit( 1 );
        }
    
    /* -------------------------------------------------------------------- */
    /*      Ensure the coordinate system gets set on the geometry.          */
    /* -------------------------------------------------------------------- */
        OGR_G_AssignSpatialReference(
            hMultiPolygon, OGR_L_GetSpatialRef(hLayer) );
    
        *phCutlineRet = (void *) hMultiPolygon;
    
    /* -------------------------------------------------------------------- */
    /*      Cleanup                                                         */
    /* -------------------------------------------------------------------- */
        if( pszCSQL != NULL )
            OGR_DS_ReleaseResultSet( hSrcDS, hLayer );
    
        OGR_DS_Destroy( hSrcDS );
    #endif
    }
    
    /************************************************************************/
    /*                      TransformCutlineToSource()                      */
    /*                                                                      */
    /*      Transform cutline from its SRS to source pixel/line coordinates.*/
    /************************************************************************/
    static void
    TransformCutlineToSource( GDALDatasetH hSrcDS, void *hCutline,
                              char ***ppapszWarpOptions, char **papszTO_In )
    
    {
    #ifdef OGR_ENABLED
        OGRGeometryH hMultiPolygon = OGR_G_Clone( (OGRGeometryH) hCutline );
        char **papszTO = CSLDuplicate( papszTO_In );
    
    /* -------------------------------------------------------------------- */
    /*      Checkout that SRS are the same.                                 */
    /* -------------------------------------------------------------------- */
        OGRSpatialReferenceH  hRasterSRS = NULL;
        const char *pszProjection = NULL;
    
        if( GDALGetProjectionRef( hSrcDS ) != NULL 
            && strlen(GDALGetProjectionRef( hSrcDS )) > 0 )
            pszProjection = GDALGetProjectionRef( hSrcDS );
        else if( GDALGetGCPProjection( hSrcDS ) != NULL )
            pszProjection = GDALGetGCPProjection( hSrcDS );
    
        if( pszProjection != NULL )
        {
            hRasterSRS = OSRNewSpatialReference(NULL);
            if( OSRImportFromWkt( hRasterSRS, (char **)&pszProjection ) != CE_None )
            {
                OSRDestroySpatialReference(hRasterSRS);
                hRasterSRS = NULL;
            }
        }
    
        OGRSpatialReferenceH hCutlineSRS = OGR_G_GetSpatialReference( hMultiPolygon );
        if( hRasterSRS != NULL && hCutlineSRS != NULL )
        {
            /* ok, we will reproject */
        }
        else if( hRasterSRS != NULL && hCutlineSRS == NULL )
        {
            fprintf(stderr,
                    "Warning : the source raster dataset has a SRS, but the cutline features/n"
                    "not.  We assume that the cutline coordinates are expressed in the destination SRS./n"
                    "If not, cutline results may be incorrect./n");
        }
        else if( hRasterSRS == NULL && hCutlineSRS != NULL )
        {
            fprintf(stderr,
                    "Warning : the input vector layer has a SRS, but the source raster dataset does not./n"
                    "Cutline results may be incorrect./n");
        }
    
        if( hRasterSRS != NULL )
            OSRDestroySpatialReference(hRasterSRS);
    
    /* -------------------------------------------------------------------- */
    /*      Extract the cutline SRS WKT.                                    */
    /* -------------------------------------------------------------------- */
        if( hCutlineSRS != NULL )
        {
            char *pszCutlineSRS_WKT = NULL;
    
            OSRExportToWkt( hCutlineSRS, &pszCutlineSRS_WKT );
            papszTO = CSLSetNameValue( papszTO, "DST_SRS", pszCutlineSRS_WKT );
            CPLFree( pszCutlineSRS_WKT );
        }
    
    /* -------------------------------------------------------------------- */
    /*      Transform the geometry to pixel/line coordinates.               */
    /* -------------------------------------------------------------------- */
        CutlineTransformer oTransformer;
    
        /* The cutline transformer will *invert* the hSrcImageTransformer */
        /* so it will convert from the cutline SRS to the source pixel/line */
        /* coordinates */
        oTransformer.hSrcImageTransformer = 
            GDALCreateGenImgProjTransformer2( hSrcDS, NULL, papszTO );
    
        CSLDestroy( papszTO );
    
        if( oTransformer.hSrcImageTransformer == NULL )
            exit( 1 );
    
        OGR_G_Transform( hMultiPolygon, 
                         (OGRCoordinateTransformationH) &oTransformer );
    
        GDALDestroyGenImgProjTransformer( oTransformer.hSrcImageTransformer );
    
    /* -------------------------------------------------------------------- */
    /*      Convert aggregate geometry into WKT.                            */
    /* -------------------------------------------------------------------- */
        char *pszWKT = NULL;
    
        OGR_G_ExportToWkt( hMultiPolygon, &pszWKT );
        OGR_G_DestroyGeometry( hMultiPolygon );
    
        *ppapszWarpOptions = CSLSetNameValue( *ppapszWarpOptions, 
                                              "CUTLINE", pszWKT );
        CPLFree( pszWKT );
    #endif
    }

        需要将上面的代码稍微进行改造,也就是把exit(1)之类的去掉,换成返回错误代码,具体修改过的代码就不贴了,就那么几个,还有就是记得把函数的返回值void改成int,用于获取错误代码。下面就是我写的函数代码:

    /**
    * @brief AOI截图(GDAL)
    * @param pszInFile        	输入文件的路径
    * @param pszOutFile        	截图后输出文件的路径
    * @param pszAOIFile        	AOI文件路径
    * @param pszSQL            	指定AOI文件中的属性字段值来裁剪
    * @param pBandInex        	指定裁剪的波段,默认为NULL,表示裁剪所有波段
    * @param piBandCount    	指定裁剪波段的个数,同上一个参数同时使用
    * @param iBuffer        	指定AOI文件外扩范围,默认为0,表示不外扩
    * @param pszFormat        	截图后输出文件的格式
    * @param pProgress        	进度条指针
    * @return 成功返回
    */ 
    int CutImageByAOIGDAL(const char* pszInFile, const char* pszOutFile, const char* pszAOIFile, const char* pszSQL, 
        int *pBandInex, int *piBandCount, int iBuffer, const char* pszFormat, LT_Progress *pProgress)
    {
        if(pProgress != NULL)
        {
            pProgress->SetProgressCaption("AOI裁剪");
            pProgress->SetProgressTip("开始裁剪图像...");
        }
    
        GDALAllRegister();
        void *hCutLine = NULL;
    
        int iRev = LoadCutline( pszAOIFile, "", "", pszSQL, &hCutline );
    
        GDALDataset * pSrcDS = (GDALDataset*) GDALOpen(pszInFile, GA_ReadOnly);
        if (pSrcDS == NULL)
        {
            if (pProgress != NULL)
                pProgress->SetProgressTip("输入的栅格文件不能打开,请检查文件是否存在!");
    
            return RE_NOFILE;
        }
        
        int iBandCount = pSrcDS->GetRasterCount();
        const char* pszWkt = pSrcDS->GetProjectionRef();
        GDALDataType dT = pSrcDS->GetRasterBand(1)->GetRasterDataType();
    
        double adfGeoTransform[6] = {0};
        double newGeoTransform[6] = {0};
    
        pSrcDS->GetGeoTransform(adfGeoTransform);
        memcpy(newGeoTransform, adfGeoTransform, sizeof(double)*6);
    
        int *pSrcBand = NULL;
        int iNewBandCount = iBandCount;
        if (pBandInex != NULL && piBandCount != NULL)
        {
            int iMaxBandIndex = pBandInex[0];
            for (int i=1; i<*piBandCount; i++)
            {
                if (iMaxBandIndex < pBandInex[i])
                    iMaxBandIndex = pBandInex[i];
            }
    
            if (iMaxBandIndex > iBandCount)
            {
                if (pProgress != NULL)
                    pProgress->SetProgressTip("输入的波段序号没有指定的波段数!");
    
                GDALClose((GDALDatasetH) pSrcDS);
                return RE_PARAMERROR;
            }
    
            iNewBandCount = *piBandCount;
            pSrcBand = new int[iNewBandCount];
            for (int i=0; i<iNewBandCount; i++)
                pSrcBand[i] = pBandInex[i];
        }
        else
        {
            pSrcBand = new int[iNewBandCount];
            for (int i=0; i<iNewBandCount; i++)
                pSrcBand[i] = i+1;
        }
    
        OGRGeometryH hGeometry = (OGRGeometryH) hCutline;
        OGRGeometryH hMultiPoly = NULL;
        if (iBuffer > 0)
        {
            double dDistance = ABS(adfGeoTransform[1]*iBuffer);
            hMultiPoly = OGR_G_Buffer(hGeometry, dDistance, 30);
            OGR_G_AssignSpatialReference(hMultiPoly, OGR_G_GetSpatialReference(hGeometry));
            OGR_G_DestroyGeometry(hGeometry);
        }
        else
            hMultiPoly = hGeometry;
    
        OGREnvelope eRect;
        OGR_G_GetEnvelope(hMultiPoly, &eRect);
    
        int iNewWidth = 0, iNewHeigh = 0;
        int iBeginRow = 0, iBeginCol = 0;
    
        newGeoTransform[0] = eRect.MinX;
        newGeoTransform[3] = eRect.MaxY;
    
        iNewWidth = static_cast<int>((eRect.MaxX -eRect.MinX) / ABS(adfGeoTransform[1]));
        iNewHeigh = static_cast<int>((eRect.MaxY -eRect.MinY) / ABS(adfGeoTransform[5]));
    
        Projection2ImageRowCol(adfGeoTransform, newGeoTransform[0], newGeoTransform[3], iBeginCol, iBeginRow);
        ImageRowCol2Projection(adfGeoTransform, iBeginCol, iBeginRow, newGeoTransform[0], newGeoTransform[3]);
    
        GDALDriver *pDriver = GetGDALDriverManager()->GetDriverByName(pszFormat);
        if (pDriver == NULL)
        {
            if (pProgress != NULL)
                pProgress->SetProgressTip("不能创建指定类型的文件!");
    
            GDALClose((GDALDatasetH) pSrcDS);
            return RE_NOFILE;
        }
    
        GDALDataset* pDstDS = pDriver->Create(pszOutFile, iNewWidth, iNewHeigh, iNewBandCount, dT, NULL);
        if (pDstDS == NULL)
        {
            if (pProgress != NULL)
                pProgress->SetProgressTip("创建文件失败!");
    
            GDALClose((GDALDatasetH) pSrcDS);
            return RE_CREATEFILE;
        }
    
        pDstDS->SetGeoTransform(newGeoTransform);
        pDstDS->SetProjection(pszWkt);
    
        void *hTransformArg, *hGenImgProjArg=NULL;
        char **papszTO = NULL;
        /* -------------------------------------------------------------------- */
        /*      Create a transformation object from the source to               */
        /*      destination coordinate system.                                  */
        /* -------------------------------------------------------------------- */
        hTransformArg = hGenImgProjArg = 
            GDALCreateGenImgProjTransformer2( hSrcDS, (GDALDatasetH)pDstDS, papszTO );
    
        if( hTransformArg == NULL )
        {
            if (pProgress != NULL)
                pProgress->SetProgressTip("创建投影失败,请检查输入参数!");
    
            GDALClose((GDALDatasetH) pSrcDS);
            GDALClose((GDALDatasetH) pDstDS);
    
            RELEASE(pSrcBand);
            return RE_PARAMERROR;
        }
    
        GDALTransformerFunc pfnTransformer = GDALGenImgProjTransform;
        GDALWarpOptions *psWO = GDALCreateWarpOptions();
    
        psWO->papszWarpOptions = CSLDuplicate(NULL);
        psWO->eWorkingDataType = dT;
        psWO->eResampleAlg = GRA_Bilinear ;
    
        psWO->hSrcDS = (GDALDatasetH) pSrcDS;
        psWO->hDstDS = (GDALDatasetH) pDstDS;
    
        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] = i+1;
        }
    
        RELEASE(pSrcBand);
        
        psWO->hCutline = (void*) hMultiPoly;
        TransformCutlineToSource((GDALDatasetH) pSrcDS, (void*)hMultiPoly, &(psWO->papszWarpOptions), papszTO );
    
    
        GDALWarpOperation oWO;
        if (oWO.Initialize(psWO) != CE_None)
        {
            if(pProgress != NULL)
                pProgress->SetProgressTip("转换参数错误!");
    
            GDALClose((GDALDatasetH) pSrcDS);
            GDALClose((GDALDatasetH) pDstDS);
    
            return RE_PARAMERROR;
        }
    
        oWO.ChunkAndWarpImage(0, 0, iNewWidth, iNewHeigh);
    
        GDALDestroyGenImgProjTransformer(psWO->pTransformerArg);
        GDALDestroyWarpOptions( psWO );
        GDALClose((GDALDatasetH) pSrcDS);
        GDALClose((GDALDatasetH) pDstDS);
    
        if(pProgress != NULL)
            pProgress->SetProgressTip("图像裁剪完成!");
    
        return RE_SUCCESS;
    }

    裁剪后的效果图就不贴了,希望对大家有用。

    ………………………………………………分割线 下面更新于2013-5-2…………………………………………………………

    上面的代码中有两处粘贴错误,已经修改,同时有人问代码中有两个坐标转换的函数,就是行列号和投影坐标相互转换的函数,其实很简单,就是根据六参数计算各仿射变换就OK,下面把代码贴出来。

    bool Projection2ImageRowCol(double *adfGeoTransform, double dProjX, double dProjY, int &iCol, int &iRow)
    {
    	try
    	{
    		double dTemp = adfGeoTransform[1]*adfGeoTransform[5] - adfGeoTransform[2]*adfGeoTransform[4];
    		double dCol = 0.0, dRow = 0.0;
    		dCol = (adfGeoTransform[5]*(dProjX - adfGeoTransform[0]) - 
    			adfGeoTransform[2]*(dProjY - adfGeoTransform[3])) / dTemp + 0.5;
    		dRow = (adfGeoTransform[1]*(dProjY - adfGeoTransform[3]) - 
    			adfGeoTransform[4]*(dProjX - adfGeoTransform[0])) / dTemp + 0.5;
    
    		iCol = static_cast<int>(dCol);
    		iRow = static_cast<int>(dRow);
    		return true;
    	}
    	catch(...)
    	{
    		return false;
    	}
    }
    
    bool ImageRowCol2Projection(double *adfGeoTransform, int iCol, int iRow, double &dProjX, double &dProjY)
    {
    	//adfGeoTransform[6]  数组adfGeoTransform保存的是仿射变换中的一些参数,分别含义见下
    	//adfGeoTransform[0]  左上角x坐标 
    	//adfGeoTransform[1]  东西方向分辨率
    	//adfGeoTransform[2]  旋转角度, 0表示图像 "北方朝上"
    	//adfGeoTransform[3]  左上角y坐标 
    	//adfGeoTransform[4]  旋转角度, 0表示图像 "北方朝上"
    	//adfGeoTransform[5]  南北方向分辨率
    
    	try
    	{
    		dProjX = adfGeoTransform[0] + adfGeoTransform[1] * iCol + adfGeoTransform[2] * iRow;
    		dProjY = adfGeoTransform[3] + adfGeoTransform[4] * iCol + adfGeoTransform[5] * iRow;
    		return true;
    	}
    	catch(...)
    	{
    		return false;
    	}
    }

  • 相关阅读:
    Java 分布式系统 实现session共享
    MySQL 大数据量使用limit分页,随着页码的增大,查询效率越低下。
    Linux下安装Zookeeper
    Mysql Window 下安装
    Spring Boot 教程demo
    全文搜索引擎 Elasticsearch (三)logstash-input-jdbc同步数据 到elasticsearch
    全文搜索引擎 Elasticsearch (二) 使用场景
    67.基于nested object实现博客与评论嵌套关系
    66.基于共享锁和排他锁实现悲观锁并发控制
    65.基于document锁实现悲观锁并发控制
  • 原文地址:https://www.cnblogs.com/xiaowangba/p/6314057.html
Copyright © 2011-2022 走看看