QGIS|QGIS中的金字塔机制优化


QGIS 中可以通过图层的属性窗口来给栅格数据创建金字塔,如下图:


右侧的 Pyramid resolutions 表示可以建立的金字塔的级别,数字前面的符号有个小叉就表示该级别的金字塔还没有被建立。可以通过点击右下方的 Build pyramid 按钮来为影像建立金字塔。
QGIS 内部也是调用了 GDAL 的 GDALBuildOverviews 方法来为影像建立金字塔。 但在使用 Build pyramid 建立金字塔的过程中发现速度非常慢,与使用 gdaladdo.exe 命令来建立金字塔相比,要耗费它几倍的时间,对此感到非常疑惑,于是看了一下内部的实现机制。
建立金字塔的实现函数位于 QgsRasterLayer 中,函数名为buildPyramids ,定义如下:
/** /brief Create GDAL pyramid overviews */
QString buildPyramids ( const RasterPyramidList &,
const QString &theResamplingMethod = "NEAREST" ,
bool theTryInternalFlag = false );
RasterPyramidList 参数表示要建立金字塔的级别。
theResamplingMethod 参数表示重采样方法。
theTryInternalFlag 参数表示是否将金字塔嵌入影像内部,该操作好像只支持TIFF 格式。
找到了函数,查看其内部实现,很快就找到了原因所在。
以下代码是 QGIS 建立金字塔的核心代码
RasterPyramidList ::const_iterator myRasterPyramidIterator ;
for ( myRasterPyramidIterator = theRasterPyramidList .begin ();
myRasterPyramidIterator != theRasterPyramidList .end ();
++myRasterPyramidIterator )
{
if (( *myRasterPyramidIterator ).build )
{
QgsDebugMsg ( "Building....." );
emit drawingProgress ( myCount , myTotal );
int myOverviewLevelsArray [1] = {( *myRasterPyramidIterator ).level };
/* From : http://remotesensing.org/gdal/classGDALDataset.html#a23
* pszResampling : one of "NEAREST", "AVERAGE" or "MODE" controlling the downsampling method applied.
* nOverviews : number of overviews to build.
* panOverviewList : the list of overview decimation factors to build.
* nBand : number of bands to build overviews for in panBandList. Build for all bands if this is 0.
* panBandList : list of band numbers.
* pfnProgress : a function to call to report progress, or NULL.
* pProgressData : application data to pass to the progress function.
*/
//build the pyramid and show progress to console
try
{

//build the pyramid and show progress to console
//NOTE this (magphase) is disabled in teh gui since it tends
//to create corrupted images. The images can be repaired
//by running one of the other resampling strategies below.
//see ticket #284
if ( theResamplingMethod == tr ( "Average Magphase" ) )
{
myError = GDALBuildOverviews ( mGdalBaseDataset , "MODE" , 1, myOverviewLevelsArray , 0, NULL ,
progressCallback , this ); //this is the arg for the gdal progress callback
}
else if ( theResamplingMethod == tr ( "Average" ) )

{
myError = GDALBuildOverviews ( mGdalBaseDataset , "AVERAGE" , 1, myOverviewLevelsArray , 0, NULL ,
progressCallback , this ); //this is the arg for the gdal progress callback
}
else // fall back to nearest neighbor
{
myError = GDALBuildOverviews ( mGdalBaseDataset , "NEAREST" , 1, myOverviewLevelsArray , 0, NULL ,
progressCallback , this ); //this is the arg for the gdal progress callback
}

if ( myError == CE_Failure || CPLGetLastErrorNo () == CPLE_NotSupported )
{
//something bad happenend
//QString myString = QString (CPLGetLastError());
GDALClose ( mGdalBaseDataset );
mGdalBaseDataset = GDALOpen ( QFile ::encodeName ( mDataSource ).constData (), GA_ReadOnly );
//Since we are not a virtual warped dataset, mGdalDataSet and mGdalBaseDataset are supposed to be the same
mGdalDataset = mGdalBaseDataset ;

emit drawingProgress ( 0, 0 );
return "FAILED_NOT_SUPPORTED" ;
}
else
{
【QGIS|QGIS中的金字塔机制优化】//make sure the raster knows it has pyramids
mHasPyramids = true ;
}
myCount ++;

}
catch ( CPLErr )
{
QgsLogger ::warning ( "Pyramid overview building failed!" );
}
}
可以看到,QGIS 将建立金字塔的关键函数GDALBuildOverviews放到了一个for 循环中。也就是说每建立一级金字塔,都会调用一次GDALBuildOverviews函数。
对此我使用gdaladdo 命令做了一个验证,使用GDALBuildOverviews函数一次建立4 级金字塔和分四次建立一个金字塔耗费的时间差不多是1:4 。这就是速度慢的问题所在,不清楚QGIS 的开发团队为什么要用这种方法来实现。
我对代码进行了一些修改,将GDALBuildOverviews函数移到了for 循环之外。然后重新在属性面板中建立金字塔,速度提高很多。
修改的时侯要注意的核心代码如下:
原代码:
intmyOverviewLevelsArray [1] = {( *myRasterPyramidIterator ).level };
myError= GDALBuildOverviews ( mGdalBaseDataset , "NEAREST" , 1, myOverviewLevelsArray , 0, NULL , progressCallback , this );
修改后:假如5 级金字塔
IntiLevels = 5;
intmyOverviewLevelsArray [5];
在循环中对myOverviewLevelsArray 分别赋值: ( *myRasterPyramidIterator ).level
myError= GDALBuildOverviews ( mGdalBaseDataset , "NEAREST" , iLevels , myOverviewLevelsArray , 0, NULL,progressCallback , this );
重点就是红色部分的两个变量修改,希望能对大家有所帮助。

    推荐阅读