您的位置:首页 > 其它

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

2013-10-25 09:10 357 查看
今天在使用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?

/**
* @brief 创建金字塔
* @param pszFileName 输入的栅格文件
* @param pProgress 进度条指针
* @return 成功返回0
*/
int CreatePyramids(const char* pszFileName, LT_Progress *pProgress) { if (pProgress != NULL) { pProgress->SetProgressCaption("创建金字塔"); pProgress->SetProgressTip("正在创建金字塔..."); }
GDALAllRegister(); CPLSetConfigOption("USE_RRD","YES"); //创建Erdas格式的字塔文件

/* -------------------------------------------------------------------- */
/* Open data file. */
/* -------------------------------------------------------------------- */

GDALDatasetH hDataset; hDataset = GDALOpen( pszFileName, GA_ReadOnly );
GDALDriverH hDriver = GDALGetDatasetDriver(hDataset); const char* pszDriver = GDALGetDriverShortName(hDriver); if (EQUAL(pszDriver, "HFA") || EQUAL(pszDriver, "PCIDSK")) { GDALClose(hDataset); //如果文件是Erdas的img或者PCI的pix格式,创建内金字塔,其他的创建外金字塔
hDataset = GDALOpen( pszFileName, GA_Update ); }
if( hDataset == NULL ) { if (pProgress != NULL) pProgress->SetProgressTip("打开图像失败,请检查图像是否存在或文件是否是图像文件!");
return RE_NOFILE; }
/* -------------------------------------------------------------------- */
/* Get File basic infomation */
/* -------------------------------------------------------------------- */
int iWidth = GDALGetRasterXSize(hDataset); int iHeigh = GDALGetRasterYSize(hDataset);
int iPixelNum = iWidth * iHeigh; //图像中的总像元个数
int iTopNum = 4096; //顶层金字塔大小,64*64
int iCurNum = iPixelNum / 4;
int anLevels[1024] = { 0 }; int nLevelCount = 0; //金字塔级数

do //计算金字塔级数,从第二级到顶层
{ anLevels[nLevelCount] = static_cast<int>(pow(2.0, nLevelCount+2)); nLevelCount ++; iCurNum /= 4; } while (iCurNum > iTopNum);
const char *pszResampling = "nearest"; //采样方式
GDALProgressFunc pfnProgress = GDALProgress;//进度条

/* -------------------------------------------------------------------- */
/* Generate overviews. */
/* -------------------------------------------------------------------- */
if (nLevelCount > 0 && GDALBuildOverviews( hDataset,pszResampling, nLevelCount, anLevels, 0, NULL, pfnProgress, pProgress ) != CE_None ) { if (pProgress != NULL) pProgress->SetProgressTip("创建金字塔失败!");
return RE_FAILD; }
/* -------------------------------------------------------------------- */
/* Cleanup */
/* -------------------------------------------------------------------- */
GDALClose(hDataset); GDALDestroyDriverManager();
if (pProgress != NULL) pProgress->SetProgressTip("创建金字塔完成!");
return RE_SUCCESS; }

需要说明的是,这段代码创建img格式和pix格式的金字塔会创建内金字塔,Erdas的img格式和PCI的pix格式可以把金字塔存放在文件内部。
PS:在给img文件创建内金字塔后,使用除ArcGIS9.2以外的软件打开后,都正常,但是使用ArcGIS9.2打开后会出现图层偏移的问题,不知道是否ArcGIS9.2的bug。ArcGIS10正常!ArcGIS9.3没有测试。
测试代码:
[cpp] view plaincopyprint?

void main() { LT_ConsoleProgress *pProgress = new LT_ConsoleProgress();
int f = CreatePyramids("C://Work//Data//ttttt.img", pProgress);
if (f == RE_SUCCESS) printf("计算成功/n"); else
printf("计算失败/n");
delete pProgress; }

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



运行测试代码:



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




如何使用GDAL重采样图像
在编写重采样图像时,可以使用GDAL来读写图像,然后自己编写重采样算法(最邻近像元法,双线性内插法,三次立方卷积法等)【关于这采样算法有时间我会单独写一篇文章来说明原理的】将计算的结果写入图像中来实现。
在GDAL的算法中,已经提供了五种重采样算法,其定义如下(位置gdalwarper.h 的46行):
[cpp] view plaincopyprint?

/*! 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来编写一个重采样的接口,代码如下:
[cpp] view plaincopyprint?

/**
* 重采样函数(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; }
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: