转自:http://blog.csdn.net/liminlu0314/article/details/8301585
首先说明一下GDALRasterBand的RasterIO函数,波段类的RasterIO函数相比GDALDataset类的RasterIO函数比较简单,先从这个简单的说起。图像还是以上面的图为例,我们只取第一个波段为例进行说明。第一个波段的图像如下图所示:
文章图片
图1:第一张波段示意
我们再把GDALRasterBand的RasterIO函数接口拿过来,形式如下:
CPLErr GDALRasterBand::RasterIO(GDALRWFlageRWFlag,int nXOff,int nYOff,int nXSize,int nYSize,void *pData,int nBufXSize,int nBufYSize,GDALDataTypeeBufType,int nPixelSpace,int nLineSpace)
第一个参数eRWFlag就是读写标记,用来指定你是读取图像还是写入图像,很简单。
接下来的四个参数是用来指定读写图像的范围的,其中前两个用来说明读取的位置,起始行列号,后两个是读写图像的宽度和高度,比如我们要在上面的图1中读取一个大小为300×200的矩形区域,从位置(100,200)开始读取,如图2所示:图中左上角红色的坐标(100,200)就是起始位置,分别对应于第二个参数nXOff和第三个参数nYOff,图中的Width=300就对应于第四个参数nXSize,图中的Height=200就对应于第五个参数nYSize。这样就确定了我们要读取或者写入图像的位置和大小了。
文章图片
图2:RasterIO参数说明 第六个参数void* pData就是用来存储图像的元素值的地方,如果是读取图像,那么读取出来的图像像素值就存储在这个pData中,如果是写入图像,那么这个pData中的数据会被写入到图像上指定的位置中去。那么这个pData的数组大小是多少呢?别急,这个pData的大小是有后面两个参数确定的,即nBufXSize和nBufYSize,这个pData的大小一定不能小于nBufXSize×nBufYSize,否则RasterIO的返回值是错误的(很多人可能都觉得RasterIO没有返回值,RasterIO是有返回值的,是一个int类型的枚举值,如果这个函数返回的不是CE_None,就是0,那么RasterIO就出错了,出错的意思就是读取的时候可能没读出数据,写入的时候没有写到图像中去)。这两个参数的意义不仅仅这么简单,他们还有更牛逼的功能,就是用来缩放图像。比如图2中,读取图像的范围是300×200,如果我要读取图像中的原始数据,那么这两个参数分别应该设置为nBufXSize=300和nBufYSize = 200。这样的用法是最常用的也是最简单的。如果我把这两个参数的值设置为nBufXSize=150和nBufYSize=100会发生什么情况呢?恭喜你,你会得到图3中矩形框的一个缩小的图像,也就是行和列都缩小一半,等等,什么意思,我好想没搞明白。缩小一半的意思就是自动把图2中的矩形区域中的灰度值重采样,重采样结果的大小就是你设定的这个150×100。那再比如说,把这两个参数的值设置为nBufXSize=600和nBufYSize=400,读出来的数据就是把图2中的矩形区域图像重采样至原来的两倍。当然了,这个都是GDAL内部自动实现的,重采样方式默认使用的是最邻近采样。如果设置的nBufXSize和nBufYSize与nXSize和nYSize不一样的话,同时图像没有金字塔的话,速度可能会慢,如果有金字塔的话,速度就会很快了。
图3是图2中矩形区域的图像,图4是设置nBufXSize=150和nBufYSize=100读取出来的图像,图5是设置nBufXSize=600和nBufYSize=400读出来的图像。
文章图片
图3 nBufXSize=300和nBufYSize=200读取图像
文章图片
图4 nBufXSize=150和nBufYSize=100读取图像
文章图片
图5 nBufXSize=600和nBufYSize=400读取图像
接下来是第九个参数nBufType,意思是将数据读取的数据类型,这个参数和pData有密切的关系(不过从pData开始,后面的参数都是和pData相关的),nBufType就是用来标记pData的类型,比如pData是char,那么nBufType就是GDT_Byte,如果pData是float类型,那么就是GDT_Float32,如果pData是double类型,那么就是GDT_Float64等等。这个参数和图像的数据类型没有多大关系,只要和pData的类型一致就不会出错。如果这个参数和图像的数据类型设置的不一致,不会报错,但是读出来的数据可能是错的,当然,这个是有规律的,具体的规律就是,如果图像的GDT_Byte类型的,那么这个参数设置任何类型都能把图像中的数据读出来。如果图像数据类型是GDT_Float32,这个参数设置为GDT_Byte,那么读出来的数据就是错的。那么这是为什么呢?主要的原因就是C/C++的数据类型转换的时候精度丢失的问题,开始图像是GDT_Byte类型,也就是图像里面的值都是用无符号的char来存的,那么后面不管你的pData类似是char,short,int,float还是double,都可以把无符号的char存进去;但是如果图像是float类型,你后面pData是个无符号char类型,那么在把一个float的数赋值给一个char肯定会丢失啊,假如这个float数是300.0,char是不可能存超过0~255,或者-127~128之外的数据的,这样就会造成数据截断。关于这部分可以参考《深入理解计算机系统》这本书。此外,关于这部分可以参考之前的那篇RasterIO博客。
到这里就剩下最后两个参数了,nPixelSpace和nLineSpace,这两个参数是用来控制参数pData中像元的存储顺序的,nPixelSpace表示的是当前像素值和下一个像素值之间的间隔,nLineSpace表示当前行和下一行的间隔,单位都是按照字节为单位计算。这两个值默认给0,表示的是,nPixelSpace=sizeof(DataType),nLineSpace=nBufXSize*sizeof(DataType),什么意思呢,意思就是,当前像素和下一个像素是紧接的;当前行和下一行的距离是一行像素。可能这个说法还是有些抽象,简单的说,就是默认读取出来的图像的像素值在pData这个数组中的顺序是按照从左到右,从上到下的顺序存储的。通过这两个参数,可以很容易的对pData中的数据进行排序,比如默认是是从左到右,从上到下的顺序存储,那么假如我要读取按照从上到下,从左到右的顺序存储的话,该怎么设置?OK,从上到下,从左到右,也就是第一个像素的下一个像素是在下一行,所以nPixelSpace应该等于一行像素的大小,即nBufXSize*sizeof(DataType),第一行和下一行的间隔就是最右边的呗,所以nLineSpace的值就是sizeof(DataType)。
至此,我们已经把GDALRasterBand类的RasterIO的函数做了一个详细的说明。下面开始对GDALDataset类的RasterIO做一个说明。GDALDataset类的RasterIO和GDALRasterBand类的RasterIO的接口基本一样,除了多了几个参数。除了多出来的参数我会在下面说明,没有多出来的意义和上面的一样,下面不再赘述。还是一样,我们先把GDALDataset类的RasterIO接口列出来,形式如下:
CPLErr GDALDataset::RasterIO(GDALRWFlag eRWFlag,int nXOff,int nYOff,int nXSize,int nYSize,void * pData,intnBufXSize,int nBufYSize,GDALDataType eBufType,int nBandCount,int * panBandMap,int nPixelSpace,intnLineSpace,int nBandSpace)
OK,我们从第一个参数开始,遇到和上面一样的,请直接回去看上面的说明。从第一个一直到第九个,和上面的一样,跳过。第十个参数nBandCount,这个参数用来指定读取的波段的个数,首先我们要有个背景知识,就是GDALDataset里面有很多个GDALRasterBand,比如一个普通的照片,至少有三个波段,即RGB。所以这个参数就是用来说明我要读取的波段的个数,比如TM的数据有7个波段,我只要读取其中的三个来进行显示,那么就把这个参数设置为3即可。到这里可能有人问了,我从7个波段选择3个波段,假如这七个波段的编号是1、2、3、4、5、6、7,那么我选择3个,怎么选择呢?很好,至于怎么指定选择的3个波段,就是下一个参数panBandMap要做的事情了。这个参数是一个int指针,也就是一个int的数组。还是上面的例子,TM的数据7个波段,4、3、2波段组合是假彩色图像,假如我们现在要读取这个4、3、2分别用来显示,那么只要把这个int panBandMap[3] = {4,3,2},把这个值设置进去就好了。如图6所示:
文章图片
接下来是nPixelSpace和nLineSpace以及nBandSpace这三个参数,前两个上面已经说明过了,这个nBandSpace是个神马东西啊?根据字面的意思就是当前波段和下一个波段之间的间隔,单位还是以字节为单位。这三个参数和上面一样,默认都可以设置为0,这样的结果就是,pData中存储图像像元的顺序是先是第一个波段,再是第二个波段,以此类推,每个波段里面按照从左到右,从上到下的顺序存储。假如是一个RGB的图像,那么读出来的顺序就是 RRRR…(一共有Width×Height个R)GGG…(一共有Width×Height个G)BBB…(一共有Width×Height个B)。这个默认的方式有时候可能就不太方便,比如用来构造BMP图像用来显示的时候,BMP中图像存储顺序是按照RGBRGBRGB…(一共有Width×Height个RGB对)排列的。要实现这种排列方式,就可以设置上面三个参数来达到这个目的。我们先来分析一下,RGB的话,第一个像素和第二个像素之间的间隔隔了两个像素,RGBR,中间有GB两个值,所以nPixelSpace的值就是sizeof(DataType)*3;第一行和下一行的间隔就是隔了原来的两行数据,所以nLineSpace的值就是sizeof(DataType)*3×width;第一个波段和下一个波段之间的距离就是一个像素,RGB,R是第一个波段G是第二个波段,中间间隔可不就是1个像素值么,所以nBandSpace的值就是sizeof(DataType)。
【深入解析GDAL库的RasterIO()函数】
推荐阅读
- MFC|gdal 图像金字塔
- GDAL功能模块列表
- GDAL关于圆形,多边形的创建以及如何判断点位是否与图形相交
- c++|gdal2.2.3关闭数据集失败的问题
- 初学者的领悟|百分比截断方法增加图像对比度的原理
- 初学者的领悟|c++实现使用GDAL实现大幅影像的快速读取
- GDAL|GDAL影像重采样
- gdal应用-gdalbuildvrt
- GDAL应用