关于GDAL打开hfa大文件的问题[转]

  今天在使用GDAL打开大的img文件的时候,(这里所谓的大文件指的是img文件太大,会将数据文件存放到ige格式raw文件中)。在讲img文件和ige文件重命名后,使用GDAL打开文件后,只能读取到文件信息,不能读取图像的数据文件。仔细查看GDAL源代码发现,在img文件中记录了对应的ige文件的名称,重命名后img文件中的记录ige文件名还是原来的,找不到ige文件,所以就打不开了。但是在使用Erdas和ArcGIS打开该文件时,会正常打开,于是查看GDAL代码,修改部分代码,能够使GDAL正常打开。

    修改的代码位置如下,gdal源代码目录/frmts/hfa/hfaband.cpp中 367行处的代码修改为下面的:

/* -------------------------------------------------------------------- */
/*      Open raw data file.                                             */
/* -------------------------------------------------------------------- */
    const char *pszRawFilename = poDMS->GetStringField( "fileName.string" );
    const char *pszFullFilename;

    pszFullFilename = CPLFormFilename( psInfo->pszPath, pszRawFilename, NULL );

    if( psInfo->eAccess == HFA_ReadOnly )
        fpExternal = VSIFOpenL( pszFullFilename, "rb" );
    else
        fpExternal = VSIFOpenL( pszFullFilename, "r+b" );

    if( fpExternal == NULL )
    {
        CPLString strFileName = psInfo->pszFilename;
        strFileName = strFileName.substr(strFileName.find_last_of('.')+1) + "ige";
        pszFullFilename = CPLFormFilename( psInfo->pszPath, strFileName.c_str(), NULL );

        if( psInfo->eAccess == HFA_ReadOnly )
            fpExternal = VSIFOpenL( pszFullFilename, "rb" );
        else
            fpExternal = VSIFOpenL( pszFullFilename, "r+b" );

        if( fpExternal == NULL )
        {
            CPLError( CE_Failure, CPLE_OpenFailed, 
                      "Unable to open external data file:/n%s/n", 
                      pszFullFilename );
            return CE_Failure;
        }

        psInfo->pszIGEFilename = const_cast<char*>(strFileName.c_str());
    }
   

希望对大家有用!

使用GDAL创建Erdas格式的金字塔.

在使用Erdas或者ArcGIS打开栅格图像的时候,会创建一个后缀名为rrd的金字塔文件,用于快速显示图像。那么在使用GDAL编写自己的图像算法后,像快速的在Erdas或者ArcGIS中显示,就需要自己创建rrd格式的金字塔文件,这样在打开该图像文件时,打开速度会非常快,在我的电脑上一个2G的img不到一秒钟可以全部加载进来。

    查看GDAL中,有个gdaladdo的工具,就是一个专门用于创建金字塔文件的,但是默认的创建的是一个后缀名为ovr的金字塔文件,该种格式的金字塔不能被Erdas或者ArcGIS使用,但是可以在QGIS等使用。为了能够在Erdas中使用,在创建的时候需要指定一个选项,那就是 USE_RRD=YES,使用该选项后,创建的金字塔格式是一个aux文件,虽然后缀名不是rrd,但是该文件是可以被Erdas或者ArcGIS中使用的。

    关于gdaladdo的使用帮助,可以参考网址:http://www.gdal.org/gdaladdo.html

    Erdas的金字塔是按照2的次方来采样,金字塔顶层的大小应该是小于等于64*64,创建金字塔的,于是按照gdaladdo中的说明,其命令行参数应该是:

   gdaladdo --config USE_RRD YES airphoto.img 2 4 8 16 ...

最后的...表示采样级别,一直到最顶层的像元个数小于等于64*64结束。有了上面的知识,下面就给出我写的一个函数,用于创建金字塔。

[cpp] view plaincopyprint?

  1. /**
  2. * @brief 创建金字塔
  3. * @param pszFileName        输入的栅格文件
  4. * @param pProgress          进度条指针
  5. * @return 成功返回0
  6. */
  7. int CreatePyramids(const char* pszFileName, LT_Progress *pProgress)  
  8. {  
  9. if (pProgress != NULL)  
  10.     {  
  11.         pProgress->SetProgressCaption("创建金字塔");  
  12.         pProgress->SetProgressTip("正在创建金字塔...");  
  13.     }  
  14.     GDALAllRegister();  
  15.     CPLSetConfigOption("USE_RRD","YES");    //创建Erdas格式的字塔文件
  16. /* -------------------------------------------------------------------- */
  17. /*      Open data file.                                                 */
  18. /* -------------------------------------------------------------------- */
  19.     GDALDatasetH     hDataset;  
  20.     hDataset = GDALOpen( pszFileName, GA_ReadOnly );  
  21.     GDALDriverH hDriver = GDALGetDatasetDriver(hDataset);  
  22. const char* pszDriver = GDALGetDriverShortName(hDriver);  
  23. if (EQUAL(pszDriver, "HFA") || EQUAL(pszDriver, "PCIDSK"))  
  24.     {  
  25.         GDALClose(hDataset);    //如果文件是Erdas的img或者PCI的pix格式,创建内金字塔,其他的创建外金字塔
  26.         hDataset = GDALOpen( pszFileName, GA_Update );  
  27.     }  
  28. if( hDataset == NULL )  
  29.     {  
  30. if (pProgress != NULL)  
  31.             pProgress->SetProgressTip("打开图像失败,请检查图像是否存在或文件是否是图像文件!");  
  32. return RE_NOFILE;  
  33.     }  
  34. /* -------------------------------------------------------------------- */
  35. /*      Get File basic infomation                                       */
  36. /* -------------------------------------------------------------------- */
  37. int iWidth = GDALGetRasterXSize(hDataset);  
  38. int iHeigh = GDALGetRasterYSize(hDataset);  
  39. int iPixelNum = iWidth * iHeigh;    //图像中的总像元个数
  40. int iTopNum = 4096;                 //顶层金字塔大小,64*64
  41. int iCurNum = iPixelNum / 4;  
  42. int anLevels[1024] = { 0 };  
  43. int nLevelCount = 0;                //金字塔级数
  44. do //计算金字塔级数,从第二级到顶层
  45.     {  
  46.         anLevels[nLevelCount] = static_cast<int>(pow(2.0, nLevelCount+2));  
  47.         nLevelCount ++;  
  48.         iCurNum /= 4;  
  49.     } while (iCurNum > iTopNum);  
  50. const char      *pszResampling = "nearest"; //采样方式
  51.     GDALProgressFunc pfnProgress = GDALProgress;//进度条
  52. /* -------------------------------------------------------------------- */
  53. /*      Generate overviews.                                             */
  54. /* -------------------------------------------------------------------- */
  55. if (nLevelCount > 0 &&  
  56.         GDALBuildOverviews( hDataset,pszResampling, nLevelCount, anLevels,  
  57.         0, NULL, pfnProgress, pProgress ) != CE_None )  
  58.     {  
  59. if (pProgress != NULL)  
  60.             pProgress->SetProgressTip("创建金字塔失败!");  
  61. return RE_FAILD;  
  62.     }  
  63. /* -------------------------------------------------------------------- */
  64. /*      Cleanup                                                         */
  65. /* -------------------------------------------------------------------- */
  66.     GDALClose(hDataset);  
  67.     GDALDestroyDriverManager();  
  68. if (pProgress != NULL)  
  69.         pProgress->SetProgressTip("创建金字塔完成!");  
  70. return RE_SUCCESS;  

  需要说明的是,这段代码创建img格式和pix格式的金字塔会创建内金字塔,Erdas的img格式和PCI的pix格式可以把金字塔存放在文件内部。

PS:在给img文件创建内金字塔后,使用除ArcGIS9.2以外的软件打开后,都正常,但是使用ArcGIS9.2打开后会出现图层偏移的问题,不知道是否ArcGIS9.2的bug。ArcGIS10正常!ArcGIS9.3没有测试。

测试代码:

[cpp] view plaincopyprint?

  1. void main()  
  2. {  
  3.     LT_ConsoleProgress *pProgress = new LT_ConsoleProgress();  
  4. int f = CreatePyramids("C://Work//Data//ttttt.img", pProgress);  
  5. if (f == RE_SUCCESS)  
  6.         printf("计算成功/n");  
  7. else
  8.         printf("计算失败/n");  
  9. delete pProgress;  

测试:在使用ArcGIS10打开没有金字塔的文件时,提示:

image

运行测试代码:

QEOPV7%QE]%DGHG~R7C)O19

再次打开刚才的文件,没有上面的提示对话框了,而且很快加载进来,说明已经有金字塔了,如果使用Erdas打开的话,可以看到详细的金字塔信息。不过可以试用QGIS查看金字塔信息。右侧的列表显示的是金字塔的级别,Erdas的金字塔是从第二级开始建立的,所以看到第一级的图标上有个红色的小叉叉。见下图:

image

 

 

如何使用GDAL重采样图像

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

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

[cpp] view plaincopyprint?

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

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

[cpp] view plaincopyprint?

  1. /**
  2. * 重采样函数(GDAL)
  3. * @param pszSrcFile        输入文件的路径
  4. * @param pszOutFile        写入的结果图像的路径
  5. * @param fResX             X转换采样比,默认大小为1.0,大于1图像变大,小于1表示图像缩小
  6. * @param fResY             Y转换采样比,默认大小为1.0
  7. * @param nResampleMode     采样模式,有五种,具体参见GDALResampleAlg定义,默认为双线性内插
  8. * @param pExtent           采样范围,为NULL表示计算全图
  9. * @param pBandIndex        指定的采样波段序号,为NULL表示采样全部波段
  10. * @param pBandCount        采样的波段个数,同pBandIndex一同使用,表示采样波段的个数
  11. * @param pszFormat         写入的结果图像的格式
  12. * @param pProgress         进度条指针
  13. * @return 成功返回0,否则为其他值
  14. */
  15. int ResampleGDAL(const char* pszSrcFile, const char* pszOutFile, float fResX , float fResY, LT_ResampleMode nResampleMode,  
  16.     LT_Envelope* pExtent, int* pBandIndex, int *pBandCount, const char* pszFormat,  LT_Progress *pProgress)  
  17. {  
  18. if(pProgress != NULL)  
  19.     {  
  20.         pProgress->SetProgressCaption("重?采?样?");  
  21.         pProgress->SetProgressTip("正?在?执?行?重?采?样?...");  
  22.     }  
  23.     GDALAllRegister();  
  24.     GDALDataset *pDSrc = (GDALDataset *)GDALOpen(pszSrcFile, GA_ReadOnly);  
  25. if (pDSrc == NULL)  
  26.     {  
  27. if(pProgress != NULL)  
  28.             pProgress->SetProgressTip("指?定?的?文?件?不?存?在?,?或?者?该?格?式?不?被?支?持?!?");  
  29. return RE_NOFILE;  
  30.     }  
  31.     GDALDriver *pDriver = GetGDALDriverManager()->GetDriverByName(pszFormat);  
  32. if (pDriver == NULL)  
  33.     {  
  34. if(pProgress != NULL)  
  35.             pProgress->SetProgressTip("不?能?创?建?该?格?式?的?文?件?!?");  
  36.         GDALClose((GDALDatasetH) pDSrc);  
  37. return RE_CREATEFILE;  
  38.     }  
  39. int iBandCount = pDSrc->GetRasterCount();  
  40.     string strWkt = pDSrc->GetProjectionRef();  
  41.     GDALDataType dataType = pDSrc->GetRasterBand(1)->GetRasterDataType();  
  42. double dGeoTrans[6] = {0};  
  43.     pDSrc->GetGeoTransform(dGeoTrans);  
  44. int iNewBandCount = iBandCount;  
  45. if (pBandIndex != NULL && pBandCount != NULL)  
  46.     {  
  47. int iMaxBandIndex = pBandIndex[0];    //找?出?最?大?的?波?段?索?引?序?号?
  48. for (int i=1; i<*pBandCount; i++)  
  49.         {  
  50. if (iMaxBandIndex < pBandIndex[i])  
  51.                 iMaxBandIndex = pBandIndex[i];  
  52.         }  
  53. if(iMaxBandIndex > iBandCount)  
  54.         {  
  55. if(pProgress != NULL)  
  56.                 pProgress->SetProgressTip("指?定?的?波?段?序?号?超?过?图?像?的?波?段?数?,?请?检?查?输?入?参?数?!?");  
  57.             GDALClose((GDALDatasetH) pDSrc);  
  58. return RE_PARAMERROR;  
  59.         }  
  60.         iNewBandCount = *pBandCount;  
  61.     }  
  62.     LT_Envelope enExtent;  
  63.     enExtent.setToNull();  
  64. if (pExtent == NULL)    //全?图?计?算?
  65.     {  
  66. double dPrj[4] = {0};    //x1,x2,y1,y2
  67.         ImageRowCol2Projection(dGeoTrans, 0, 0, dPrj[0], dPrj[2]);  
  68.         ImageRowCol2Projection(dGeoTrans, pDSrc->GetRasterXSize(), pDSrc->GetRasterYSize(), dPrj[1], dPrj[3]);  
  69.         enExtent.init(dPrj[0], dPrj[1], dPrj[2], dPrj[3]);  
  70.         pExtent = &enExtent;  
  71.     }  
  72.     dGeoTrans[0] = pExtent->getMinX();  
  73.     dGeoTrans[3] = pExtent->getMaxY();  
  74.     dGeoTrans[1] = dGeoTrans[1] / fResX;  
  75.     dGeoTrans[5] = dGeoTrans[5] / fResY;  
  76. int iNewWidth  = static_cast<int>( (pExtent->getMaxX() - pExtent->getMinX() / ABS(dGeoTrans[1]) + 0.5) );  
  77. int iNewHeight = static_cast<int>( (pExtent->getMaxX() - pExtent->getMinX() / ABS(dGeoTrans[5]) + 0.5) );  
  78.     GDALDataset *pDDst = pDriver->Create(pszOutFile, iNewWidth, iNewHeight, iNewBandCount, dataType, NULL);  
  79. if (pDDst == NULL)  
  80.     {  
  81. if(pProgress != NULL)  
  82.             pProgress->SetProgressTip("创?建?输?出?文?件?失?败?!?");  
  83.         GDALClose((GDALDatasetH) pDSrc);  
  84. return RE_CREATEFILE;  
  85.     }  
  86.     pDDst->SetProjection(strWkt.c_str());  
  87.     pDDst->SetGeoTransform(dGeoTrans);  
  88.     GDALResampleAlg eResample = (GDALResampleAlg) nResampleMode;  
  89. if(pProgress != NULL)  
  90.     {  
  91.         pProgress->SetProgressTip("正?在?执?行?重?采?样?...");  
  92.         pProgress->SetProgressTotalStep(iNewBandCount*iNewHeight);  
  93.     }  
  94. int *pSrcBand = NULL;  
  95. int *pDstBand = NULL;  
  96. int iBandSize = 0;  
  97. if (pBandIndex != NULL && pBandCount != NULL)  
  98.     {  
  99.         iBandSize = *pBandCount;  
  100.         pSrcBand = new int[iBandSize];  
  101.         pDstBand = new int[iBandSize];  
  102. for (int i=0; i<iBandSize; i++)  
  103.         {  
  104.             pSrcBand[i] = pBandIndex[i];  
  105.             pDstBand[i] = i+1;  
  106.         }  
  107.     }  
  108. else
  109.     {  
  110.         iBandSize = iBandCount;  
  111.         pSrcBand = new int[iBandSize];  
  112.         pDstBand = new int[iBandSize];  
  113. for (int i=0; i<iBandSize; i++)  
  114.         {  
  115.             pSrcBand[i] = i+1;  
  116.             pDstBand[i] = i+1;  
  117.         }  
  118.     }  
  119. void *hTransformArg = NULL, *hGenImgPrjArg = NULL;  
  120.     hTransformArg = hGenImgPrjArg = GDALCreateGenImgProjTransformer2((GDALDatasetH) pDSrc, (GDALDatasetH) pDDst, NULL);  
  121. if (hTransformArg == NULL)  
  122.     {  
  123. if(pProgress != NULL)  
  124.             pProgress->SetProgressTip("转?换?参?数?错?误?!?");  
  125.         GDALClose((GDALDatasetH) pDSrc);  
  126.         GDALClose((GDALDatasetH) pDDst);  
  127. return RE_PARAMERROR;  
  128.     }  
  129.     GDALTransformerFunc pFnTransformer = GDALGenImgProjTransform;  
  130.     GDALWarpOptions *psWo = GDALCreateWarpOptions();  
  131.     psWo->papszWarpOptions = CSLDuplicate(NULL);  
  132.     psWo->eWorkingDataType = dataType;  
  133.     psWo->eResampleAlg = eResample;  
  134.     psWo->hSrcDS = (GDALDatasetH) pDSrc;  
  135.     psWo->hDstDS = (GDALDatasetH) pDDst;  
  136.     psWo->pfnTransformer = pFnTransformer;  
  137.     psWo->pTransformerArg = hTransformArg;  
  138.     psWo->pfnProgress = GDALProgress;  
  139.     psWo->pProgressArg = pProgress;  
  140.     psWo->nBandCount = iNewBandCount;  
  141.     psWo->panSrcBands = (int *) CPLMalloc(iNewBandCount*sizeof(int));  
  142.     psWo->panDstBands = (int *) CPLMalloc(iNewBandCount*sizeof(int));  
  143. for (int i=0; i<iNewBandCount; i++)  
  144.     {  
  145.         psWo->panSrcBands[i] = pSrcBand[i];  
  146.         psWo->panDstBands[i] = pDstBand[i];  
  147.     }  
  148.     RELEASE(pSrcBand);  
  149.     RELEASE(pDstBand);  
  150.     GDALWarpOperation oWo;  
  151. if (oWo.Initialize(psWo) != CE_None)  
  152.     {  
  153. if(pProgress != NULL)  
  154.             pProgress->SetProgressTip("转?换?参?数?错?误?!?");  
  155.         GDALClose((GDALDatasetH) pDSrc);  
  156.         GDALClose((GDALDatasetH) pDDst);  
  157. return RE_PARAMERROR;  
  158.     }  
  159.     oWo.ChunkAndWarpImage(0, 0, iNewWidth, iNewHeight);  
  160.     GDALDestroyGenImgProjTransformer(psWo->pTransformerArg);  
  161.     GDALDestroyWarpOptions( psWo );  
  162.     GDALClose((GDALDatasetH) pDSrc);  
  163.     GDALClose((GDALDatasetH) pDDst);  
  164. if(pProgress != NULL)  
  165.         pProgress->SetProgressTip("重?采?样?完?成?!?");  
  166. return RE_SUCCESS;  
posted @ 2013-10-25 09:10  vstion  阅读(1564)  评论(0编辑  收藏  举报