Romi-知行合一

轻轻的风轻轻的梦,轻轻的晨晨昏昏, 淡淡的云淡淡的泪,淡淡的年年岁岁。
  博客园  :: 首页  :: 新随笔  :: 订阅 订阅  :: 管理

GDAL RasterIO读取波段数据

Posted on 2012-03-29 20:02  romi  阅读(19942)  评论(0编辑  收藏  举报

前面写了用GDAL读取数据集和波段信息,使用GDAL最重要的就是读取图像的波段数据,因为对图像的处理就是对数据(也可以说是像素点)的处理。这里讨论下gdal读取波段数据。

参考文章:http://www.gdal.org/gdal_tutorial.html

这里有个中文翻译版,翻译的还是可以的:http://opencv-extension-library.googlecode.com/svn/doc/gdal-doc/gdal_tutorial.html

读取波段数据

gdal读取波段数据的接口为RasterIO,这是一个及其重要的函数,GDALDataset和GDALRasterBand类都有这个函数,利用GDALDataset类中的RasterIO时可以按指定波段数并按一定的波段序读取数据,GDALRasterBand类中的RasterIO可以读取该波段的数据,读数据时可以全部读取、读取某一块或抽样读取。用的多的是GDALRasterBand类的RaterIO函数,下面就说下这个函数,函数原型如下:

CPLErr GDALRasterBand::RasterIO    (    
GDALRWFlag eRWFlag, //读写标志。GF_Read:读取数据到缓存 GF_Write:将缓存中数据写入数据集的波段
int nXOff, //起始X方向像素位置
int nYOff, //起始Y方向像素位置
int nXSize, //数据的X方向像素大小
int nYSize, //数据的Y方向像素大小 注:以上四个参数制定了要读取数据的位置和大小
void * pData, //缓存
int nBufXSize, //缓存的X方向像素大小
int nBufYSize, //缓存的Y方向像素大小
GDALDataType eBufType, //数据类型,指定缓存中的数据类型
int nPixelSpace, //读取每个像素的字节偏移量,即下一个读取的的像素与此时读取的像素的字节距离,默认为0
int  nLineSpace     //读取每一行像素的字节偏移量,默认为0
)    

参数意义见注释,

nPixelSpace为0时,表示偏移的字节量为eBufType大小的字节数

nLineSpace为0时,表示偏移的字节量为eBufType * nBufXSize字节数

采样实现:设置最后两个参数,设置nPixelSpace指定每行隔几个像素点进行读取,设置nLineSpace指定每隔几行读取,注意缓存的大小。

对数据全部读取示例:

//数据集注册及对象获取这里不赘述,见上篇
int sizeX = poDataset->GetRasterXSize();

int sizeY = poDataset->GetRasterYSize();
unsigned char *pMemData1;
pMemData = (unsigned char*)CPLMalloc(sizeX * sizeY);
poBand = poDataset->GetRasterBand(1);
poBand->RasterIO(GF_Read,
0,0,
sizeX,sizeY,
pMemData,
sizeX,sizeY,
GDT_Byte,
0,0);
CPLFree(pMemData);

有时,需要每行进行字节对齐,即每行的字节数为8的倍数,即位数为32的倍数(32位系统一个内存单元是32位),对于上面的情况,如下:

bytePerLine=(sizeX*8=31)/32*4     即pMemData每行的位数就是32的倍数了(为什么这样计算,自个体会吧)

每行的字节对齐后,pMemData每行就不是sizeX了,应该是bytePerLine,对应上面的代码也要改变。

分块读取:

这里,如果图像很大,一般遥感图像,特别是高分辨率图像数据量都很大,直接全部读取对于内存开销会很大,这时可以采取分块读取的方法,比如每100为一个数据块进行读取,这样可以减小内现存开销。分块的例子(以每100行为一块为例):

int sizeX = poDataset->GetRasterXSize();
int sizeY = poDataset->GetRasterYSize();
unsigned char *pMemData1;
//100行一块
pMemData = (unsigned char*)CPLMalloc(sizeX * 100);

poBand = poDataset->GetRasterBand(1);
for(int i=0;i<sizeY/100;i++)
{
poBand->RasterIO(GF_Read,
0,i*100,
sizeX,100,
pMemData,
sizeX,100,
GDT_Byte,
0,0);
}
CPLFree(pMemData);

注意:上面的代码中还有最后剩下的不到100行的数据没有读,这里只为了说明怎么分块,剩下的数据就不管了。实际中千万要加上。

读取完后申请的内存要记得释放掉。
GDALRasterBand类的RasterIO函数可以满足大部分要求,也比较容易理解,波段多时大不了多用几次。GDALDataset类的RasterIO目前没怎么用,只是多了几个参数,功能更强大,需要时再去用吧。