GDAL指定自定義的金字塔目錄

緣起

對於通常的遙感影像文件,金字塔文件默認都是與影像文件放在同一個目錄下,金字塔文件名通常與源影像文件名相同,但後綴名不一樣。或者金字塔內建於影像內部,但這不是這裏所涉及的。
在使用ArcGIS桌面版或者Erdas遙感影像處理軟件打開遙感影像文件的時候,若是影像不含(帶有)金字塔,則會提示是否建立金字塔。git

ArcGIS提示創建金字塔

咱們碰到這麼一種狀況,就是原始影像是不帶金字塔的,而且所在的目錄不容許修改,也就是不能將金字塔建立在其中,原始影像文件更是不容許修改,因此也不能更新內建金字塔。github

解決

對於這個問題,爲了加速影像的瀏覽,只能將金字塔創建在外部的目錄,而讀取的時候根據讀取輸出的分辨率,來確認是使用源影像讀取仍是使用金字塔文件讀取,這都須要本身控制。
由於本身控制會將一些控制流程變複雜,因此我想讓GDAL直接支持索引到這個外部的金字塔文件。函數

在GDAL中,金字塔稱之爲Overviews(概覽視圖),因此與之相關的接口都帶有Overview單詞。ui

我看了GDAL的RasterIO流程相關的代碼,簡單的製做了以下的流程圖:指針

GDALDataset::RasterIO簡單流程圖

GDALDefaultOverviews::OverviewScan()函數

與金字塔路徑查找的關鍵代碼在函數GDALDefaultOverviews::OverviewScan()中。code

經過查看其實現代碼,和被調用時候的參數(參數在GDALDefaultOverviews::Initialize函數被調用的時候肯定,能夠搜索poDS->oOvManager.Initialize查看,都是在對應格式的XXXDataset::Open()函數中被調用,不一樣格式影像調用時候傳的參數可能不一樣),能夠知道GDAL搜尋金字塔的方式與順序。orm

這裏不詳細說這裏面的流程結構了,一些判斷條件也略過,只大概說一下搜索順序(若是有內建金字塔則不會讀取外部金字塔):blog

  • 一、.ovr後綴金字塔文件
  • 二、.aux後綴金字塔文件
  • 三、.rrd後綴金字塔文件(若是配置有USE_RRD=YES
  • 四、影像元數據Metadata中的OVERVIEW_FILE指定的金字塔路徑

若是須要使用到自定義的金字塔文件,能夠在此處修改,添加一段搜索代碼,示例以下:索引

if( poODS == nullptr )
    {
        osOvrFilename = MyOverviewFileSearch(pszInitName);
        poODS = GDALDataset::Open(osOvrFilename,
            GDAL_OF_RASTER | (poDS->GetAccess() == GA_Update ? GDAL_OF_UPDATE: 0));
    }

MyOverviewFileSearch是用於搜索自定義路徑下金字塔的函數。接口

關於 GDALRasterBand::GetOverview

上面說若是有內建金字塔則不會讀取外部金字塔,這個其實是各個影像文件格式的相關代碼裏面本身定義的。
由於virtual GDALRasterBand* GDALRasterBand::GetOverview(int);原本就是一個虛函數,而GDAL中又基本都是依賴指針進行操做,因此實際上會調用各自的實現。

GeoTiff格式爲例,在它的Overview相關函數中就是先搜索Tiff目錄內的金字塔,若是找不到才調用GDALRasterBand中對應的接口,進而訪問外部金字塔文件。

例如如下代碼:

/************************************************************************/
/*                          GetOverviewCount()                          */
/************************************************************************/
int GTiffRasterBand::GetOverviewCount()
{
    poGDS->ScanDirectories();
    if( poGDS->nOverviewCount > 0 )
    {
        return poGDS->nOverviewCount;
    }

    const int nOverviewCount = GDALRasterBand::GetOverviewCount();
    if( nOverviewCount > 0 )
        return nOverviewCount;

    // Implicit JPEG overviews are normally hidden, except when doing
    // IRasterIO() operations.
    if( poGDS->nJPEGOverviewVisibilityCounter )
        return poGDS->GetJPEGOverviewCount();

    return 0;
}

/************************************************************************/
/*                            GetOverview()                             */
/************************************************************************/
GDALRasterBand *GTiffRasterBand::GetOverview( int i )
{
    poGDS->ScanDirectories();
    if( poGDS->nOverviewCount > 0 )
    {
        // Do we have internal overviews?
        if( i < 0 || i >= poGDS->nOverviewCount )
            return nullptr;
        return poGDS->papoOverviewDS[i]->GetRasterBand(nBand);
    }

    GDALRasterBand* const poOvrBand = GDALRasterBand::GetOverview( i );
    if( poOvrBand != nullptr )
        return poOvrBand;

    // For consistency with GetOverviewCount(), we should also test
    // nJPEGOverviewVisibilityCounter, but it is also convenient to be able
    // to query them for testing purposes.
    if( i >= 0 && i < poGDS->GetJPEGOverviewCount() )
        return poGDS->papoJPEGOverviewDS[i]->GetRasterBand(nBand);

    return nullptr;
}

上面代碼中的poGDS->ScanDirectories();語句,內部調用去遍歷Tiff目錄,找到TIFFTAG_SUBFILETYPE(子文件類型)字段爲FILETYPE_REDUCEDIMAGE(縮小圖像)的目錄,而後解析出須要的金字塔信息(僅第一次調用時作,後面調用會判斷bScanDeferred直接跳過)。

若是沒有找到才調用基類GDALRasterBand對應的函數去訪問外部金字塔。

關於構建外部金字塔等

構建也是差很少的過程,這裏就簡單的寫一下調用過程:GDALDataset::BuildOverviews ---> GDALDataset::IBuildOverviews ---> GDALDefaultOverviews::BuildOverviews

因此設置構建外部金字塔的路徑,也能夠修改GDALDefaultOverviews::BuildOverviews
一樣,對於不一樣的影像格式,能夠有本身的GDALDataset::IBuildOverviews實現,例如GeoTiff的就是GTiffDataset::IBuildOverviews,若是須要建立內建的金字塔,則作另外的實現。

相關文章
相關標籤/搜索