为了能快速的显示大影像,最近一直在学习GDAL,GDAL确实是一个功能强大的开源库,其核心部分数据集和波段,下面这个图很详细的描述了它们之间的关系,还有其中的细节:
GDAL的RASTERIO功能非常强大,简短的一句话就能实现图像的显示,但也是这个简单函数,把我折腾的半死。在学习使用GDAL的过程中,非常感谢李林大哥和貟建明大哥,他们不厌其烦地解答我的疑问,提示关键性要点,使我在解决问题的过程中事半功倍。
我现在要把最近学习过程中的心得写下来,留给自己以后看看,也希望可以给新手们一点帮助!
GDALAllRegister();
const char* str ;
m_pDataset = (GDALDataset*) GDALOpen( str, GA_ReadOnly );
这一部分应该很好理解,首先打开一个影像,我们必须注册其驱动,因为每种不同的栅格数据都有不同的驱动,也就是driver。之后我们就可以用GDALOpen()函数来打开一个数据集dataset,如果打开的格式并不是GDAL支持的,我们就需要通过new GDALDriver()创建一个新的driver并设置,这样才能打开。如果GDALOpen()函数返回NULL,表示打开文件失败。
打开了一个dataset之后,我们就可以对dataset的内部信息进行操作,dtaset的详细信息以及内部的关系在上图表述的非常详细。
m_pDataset->GetGeoTransform( m_AdfGeoTransform );
上面这行代码是用来获取仿射信息用的,m_AdfGeoTransform是一个含6个元素的数组,执行了这行代码后,我们就可以获取m_AdfGeoTransform数组的信息,m_AdfGeoTransform[0],m_AdfGeoTransform[3]是整个影像的坐下角坐标,m_AdfGeoTransform[1]是影像宽度上的分辨率,m_AdfGeoTransform[5]是影像高度上的分辨率,而对于m_AdfGeoTransform[2]和m_AdfGeoTransform[4]来说,如果影像是指北的,这两个参数的值为0。有了这几个参数,我们就能通过以下两行代码求出影像左下角和右上角的信息:
XMin = m_AdfGeoTransform[0];
YMin = m_AdfGeoTransform[3];
XMax = m_AdfGeoTransform[0] + nX * m_AdfGeoTransform[1] + m_AdfGeoTransform[2];
YMax = m_AdfGeoTransform[3] + m_AdfGeoTransform[4] + nY * m_AdfGeoTransform[5];
有了影像的信息之后,我们要做的就是将影像显示出来,这里就有一个分辨率的问题,一个是图像分辨率,一个是显示分辨率。图像分辨率就是单位长度内的像素数,而显示分辨率就是把数字图像在输出设备(比如显示屏或打印机等)上能够显示的像素数目和所显示像素之间的点距。这两个分辨率在显示影像的时候非常有作用。弄清楚原理的东西确实是成功的基石!
然后就到了GDAL的核心部分了:
pBuffer = (BYTE*) CPLMalloc(sizeof(BYTE)*(xBuf)*(yBuf)*nBand);
m_pDataset->RasterIO( GF_Read, xSrc, ySrc, xWidth, yHight, pBuffer, xBuf, yBuf,GDT_Byte, nBand, NULL, nBand, 0, 1 );
对于三个波段以上的影像,我们可以直接通过以上两行代码讲影像读入pBuffer这个内存,然后根据我们的需要,比如说OPENGL,我们就可以利用glDrawPixels( )这个函数直接显示出影像了。现在关键的地方就是RasterIO里面的几个参数了,对照GDAL官方的函数说明:
GDALDataset::RasterIO ( GDALRWFlag eRWFlag,
int nXOff,
int nYOff,
int nXSize,
int nYSize,
void * pData,
int nBufXSize,
int nBufYSize,
GDALDataType eBufType,
int nBandCount,
int * panBandMap,
int nPixelSpace,
int nLineSpace,
int nBandSpace
)
如果为GF_Read,则是将影像内容写入内存,如果为GF_Write,则是将内存中内容写入文件。
nXOff,nYOff,nXSize,nYSize这四个参数是用于影像的,nXOff,nYOff就是说我们要从影像的这个像素坐标开始取数据,nXSize,nYSize就是从影像上取数据的宽度和高度,也就是说要从影像上取出来的数据范围是(nXOff,nYOff)到(nXOff+nXSize,nYOff+nYSize)。如果我们要显示这个取出来的范围,我们就要把这个数据域写入缓存pData中,nBufXSize,nBufYSize即是这个缓存区的大小范围。
RasterIO这个函数只有这些说明,那我们在应用的时候就需要根据我们的实际需要计算,如果有一幅100M的影像,你想快速显示,那么这六个参数的设置就是关键,不过有一个前提条件就是这个影像是金字塔影像,这样你设置好了buffer的size,那么GDAL就会根据GDAL内部函数的实现过程,自动帮你完成缩放操作(把nXSize,nYSizen的数据缩放到BufXSize,nBufYSize的buffer里显示),而并不需要你去控制获取哪个overview,由于开始我并没有理解透这个函数的真正含义,在大影像的显示上走了很多弯路,自己去判断要读金字塔的第几层,以至于自己都把自己快搞崩溃了,这里要非常感谢李林大哥,呵呵,每个细节都给我讲的很详细,并且对于一些抽象的东西他也耐心的给我举些例子,加上自己的时间,最后终于明白了这个函数的原理所在。呵呵,在这里要真挚的感谢李大哥。
nBufXSize,nBufYSize这个缓存区的大小范围,决定了我们要在多大的屏幕范围显示你想显示的图像内容,因此我们要根据屏幕范围和缩放比例来计算这个buffer的size。
nPixelSpace表示一个像素所占byte大小,假如是24位的,那么一个像素就占3个字节,那么nPixelSpace = 3。nLineSpace表示一行所占大小,如果设为0的话,就默认为nBufXSize*nBufYSize。
nBandSpace为一个波段数据所占大小,如果设为0的话,就是以RRRGGGBBB这种形式存储,如果设为1的话,就是以RGBRGBRGB这种形式存储。
不过这个函数还是要自己试了才知道真正的意义,呵呵,希望新手少走我的弯路!!以后还会陆续添加自己的学习心得的,^_^Fighting!!!o(∩_∩)o...
分类: 编程相关