|
GDAL的GDALDataset和GDALRasterBand类为我们提供了功能强大的RasterIO(…)函数,它可以把图像上 指定大小的矩形象素块 以缩放的形式 按指定的数据类型 输出或输入到 用户指定大小的缓冲区中。
原型:
CPLErr GDALDataset::RasterIO(
GDALRWFlag eRWFlag, //读写标记
int nXOff, int nYOff,//相对于图像左上角顶点(从零开始)的行列偏移量
int nXSize, int nYSize,//要读写的块在x方向的象素个数和y方向的象素列数
void * pData,//指向目标缓冲区的指针,由用户分配
int nBufXSize, int nBufYSize,//目标块在x方向上和y方向上的大小
GDALDataType eBufType, //目标缓冲区的数据类型,原类型会自动转换为目标类型
int nBandCount, //要处理的波段数
int * panBandMap,//记录要操作的波段的索引(波段索引从1开始)的数组,若为空,//则数组中存放的是前nBandCount个波段的索引
int nPixelSpace,//x方向上两个相邻象素之间的字节偏移,默认为0,则列间的实际//字节偏移由目标数据类型eBufType确定
int nLineSpace, //y方向上相邻两行之间的字节偏移, 默认为0,则行间的实际字节//偏移为eBufType * nBufXSize
int nBandSpace //相邻两波段之间的字节偏移,默认为0,则意味着波段是顺序结构//的,其间字节偏移为nLineSpace * nBufYSize
);
CPLErr GDALRasterBand::RasterIO(//各参数意义同上
GDALRWFlag eRWFlag,
int nXOff, int nYOff,
int nXSize, int nYSize,
void * pData,//
int nBufXSize, int nBufYSize,
GDALDataType eBufType,
int nBandCount,
int nPixelSpace,
int nLineSpace,
);
上述函数的区别在于前者是对同一数据集的多个波段操作,而后者是对单个波段的操作。
基于以上的GDALRasterBand::RasterIO()函数构建影像分块的类clsDOM,并在类中做了函数SmartRead()进行缩放读取dom,处理过程为:
//打开文件获得指向该文件的GDALDataset指针
clsDOM::OpenFile();
//指定分块的大小
clsDOM::SetBlockSize();
//循环处理每一块
{
//SmartRead()内部调用RasterIO(),此时动态分配当前块的内存
clsDOM::SmartRead();
//每一块处理完之后立即释放当前块
}
//所有块处理完后,释放GDALDataset指针
clsDOM::CloseFile();
跟踪以上过程发现读取各块时内存逐次增长,虽然每次循环都释放了当前块,但是仍无法回落到处理这一块之前的值,直到最终释放GDALDataset指针内存才会回落至打开文件前的值。内存的不断增长显然对处理大文件会产生致命问题!究其原因,每执行一次RasterIO内存都会(不太慢的)增长,以致于每一块处理完后内存不彻底回落。尝试每次处理完后删除当前的RasterBand指针也无法回落。最终解决办法是处理每一块时都执行一次打开文件和关闭文件释放GDALDataset指针的操作:
//指定分块的大小
clsDOM::SetBlockSize();
//循环处理每一块
{
//处理每一块之前打开文件获得指向该文件的GDALDataset指针
clsDOM::OpenFile();
//SmartRead()内部调用RasterIO(),此时动态分配当前块的内存
SmartRead();
//每一块处理完之后立即释放当前块
//…
//当前块处理完后,释放GDALDataset指针
CloseFile();
}
这样做内存的开销极小,但频繁的打开关闭文件总是不太好。
另外,如果是数据库连接,像下面这样反复连接更是不可取的:
GDALOpenInfo OpenInfo(szdbConnect , GA_ReadOnly);
GDALDataset poDataset=SDEDataset::Open(&OpenInfo);
关注此页的朋友,如有更好的解决办法,请联系我xuex_chen@126.com 或加入我的群46328427讨论。 |
|