在遥感领域,许多图片的大小动辄上G。读取、显示这样的图片极为耗时,影响用户体验。金字塔技术在几乎不降低显示效果的前提下,大大降低了图片处理的耗时,改善了用户体验
目录
原理
操作方法
示例
解释
生成金字塔
读取金字塔
效果
考虑一幅1024乘以1024的图片。假如每个像素占据1字节,则整个文件占据1MB(不算文件辅助信息之类的话)。假如显示这幅图片的窗口尺寸只有256*256,则我们完全可以抽样,每4行抽一行,每4列抽一列。抽取出来的字节数仅为原有字节数的1/16.假如读取的字节数变少了,耗时自然会降低。但是这要求我们在读取之前,就要把抽样完成,并且将抽样结果存放到一段连续的磁盘或内存里供使用(有人可能提出来,RasterIO函数具备抽样功能,可否每次读取时都利用RasterIO来抽样一次?不行,假如对若干段不连续的地址进行读取,RasterIO的耗时也会增加,不会比读取全部数据快多少。所以抽样结果一定要存入一段连续的内存或者磁盘里)。
gdal提供了函数BuildOverviews()完成抽样并保存。
CPLErr BuildOverviews(const char *pszResampling, int nOverviews,
int *panOverviewList, int nListBands, int *panBandList,
GDALProgressFunc pfnProgress, void *pProgressData)
1)pszResampling可以是如下字符串的一个:
"NEAREST" 选取最近邻的原始像素值
"AVERAGE"取平均
"BILINEAR"双线性插值
"CUBIC"立方插值
"GAUSS"高斯插值
"LANZCOS"兰佐斯插值(高斯与兰佐斯都是数学-物理学家)
"AVERAGE_MAGPHASE"
"CUBICSPLINE"
"MODE"
"NONE"
2) 考虑到许多显示界面都具备缩放功能,一旦图像发生缩放,抽样的比率将发生变化,所以BuildOverviews()函数提供了nOverviews和panOverviewList。前者表示你可以做几次抽样;后者是一个数组,表示每次抽样的采样率是多少。
3) nListBands表示被采样的波段号。
4) 最后两个变量一般不用,写NULL即可
以下面的代码为例,nOverviews=3,panOverviewList={2,4,8},说明采样三次。第一次采样率为2,也就是每两行取一行,每2列取一列;第二次采样率为4,也就是每4行取一行,每4列取1列;...三次采样的结果都要保存下来。对于tif文件,抽样结果存入源文件;对于bmp文件,所有抽样结果存入一个统一的新文件,文件名是源文件名加后缀.ovr
采样率越高,抽样的结果占用字节数就越少。以原文件占1024kB为例,采样率为2,抽样结果占256kB;采样率4,则占据64kB;采样率为8,则占据16kB.采样率从高到低,占用空间越来越大,形成金字塔型,这也正是“影像金字塔”命名的由来。
下面的代码利用buildOverviews函数建立金字塔,然后按照不同分辨率来读取图片,并记录不同分辨率下读取的花费时间。关于如何记录读取时间,可以参看我的另外一篇博客《Visual Studio C++精确计时》
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "gdal_priv.h"
#include
#pragma comment(lib, "winmm.lib")//不可少
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
ui->lineEdit->setText("C:\\code\\QT\\pyramid\\2-1.tif");
ui->lineEdit_2->setText("C:\\code\\QT\\pyramid\\");
QueryPerformanceFrequency(&m_nFreq);//获取频率
QueryPerformanceCounter(&m_nBegin);//获取起始时间
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_clicked()
{
QString qstrName = ui->lineEdit->text();
GDALDataset * pSet = (GDALDataset *)GDALOpen(qstrName.toLatin1().data(), GA_Update);
int anOverviewList[3] = { 2, 4, 8};
if(CE_None == pSet->BuildOverviews( "NEAREST", 3, anOverviewList, 0, NULL,
NULL, NULL ))
{
ui->label->setText("OK");
}
else
{
ui->label->setText("fail");
}
GDALClose(pSet);
}
void MainWindow::on_pushButton_2_clicked()
{
int iRatio = ui->spinBox->value();
QString qstrName = ui->lineEdit->text();
GDALDataset * pSet = (GDALDataset *)GDALOpen(qstrName.toLatin1().data(), GA_ReadOnly);
GDALRasterBand *pBand =pSet->GetRasterBand(1);
int iX = pSet->GetRasterXSize();
int iY = pSet->GetRasterYSize();
unsigned char * pData = new unsigned char[iX * iY];
LARGE_INTEGER nTime1, nTime2;
QueryPerformanceCounter(&nTime1);//获取时间
pBand->RasterIO(GF_Read,0, 0, iX, iY, pData, iX/iRatio, iY/iRatio, GDT_Byte, 0, 0);
QueryPerformanceCounter(&nTime2);
int iInterval = (nTime2.QuadPart - nTime1.QuadPart) / (double)m_nFreq.QuadPart * 1000;
ui->label_2->setText(QString("%1ms").arg(iInterval));
GDALClose(pSet);
//save
static int iIndex = 0;
QString qstrSavePath = ui->lineEdit_2->text();
QString qstrSaveFile = QString("%1new%2.tif").arg(qstrSavePath).arg(iIndex++);
GDALDriver * pDriver = GetGDALDriverManager()->GetDriverByName("GTiff");
GDALDataset * pSetWrite = pDriver->Create(qstrSaveFile.toLatin1().data(),
iX/iRatio, iY/iRatio,1,GDT_Byte,NULL);
pBand =pSetWrite->GetRasterBand(1);
pBand->RasterIO(GF_Write,0, 0, iX/iRatio, iY/iRatio, pData, iX/iRatio, iY/iRatio, GDT_Byte, 0, 0);
GDALClose(pSetWrite);
delete [] pData;
}
函数 on_pushButton_clicked()用于产生金字塔
语句
int anOverviewList[3] = { 2, 4, 8};
意味着抽样三次,抽样率分别为2,4,8
函数 on_pushButton_2_clicked()用于读取金字塔,然后把读取的结果保存成单独的文件
语句
pBand->RasterIO(GF_Read,0, 0, iX, iY, pData, iX/iRatio, iY/iRatio, GDT_Byte, 0, 0);
中各个参数意义如下:(按从左到右的次序)
GF_Read 表示读取
第一对 0,0表示读取的开始位置是原始图片(也就是抽样之前的图片)的左上角
iX,iY表示读取的范围:原始图片横向iX个像素,纵向iY个像素
pData表示读取后,像素存储的首地址
iRatio代表抽样率,iX/iRatio代表抽样后,抽样结果在X方向占多少像素,iY/iRatio代表抽样结果在Y方向占多少像素
GDT_Byte代表原始文件的像素占一个字节
RasterIO前后的两个QueryPerformanceCounter函数记下了读取前后的时间,两者相减便是RasterIO的耗时。这个耗时将显示在界面上。
读取不抽样的图(微缩比例1)耗时48ms。结果文件new0.tif占据2967KB
读取抽样率为2(微缩比例2)的图耗时12ms。结果文件new1.tif占据742KB
读取抽样率为4的图耗时16ms。当图变小以后,读取耗时就存在随机性了,但是总的趋势不变。16ms也正常。结果文件new2.tif占据186KB
读取抽样率为8的图耗时0.结果文件new3.tif占据47KB
我们从图片的字节数也可以看出抽样确实减少了文件大小。从new0.tif到new3.tif