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


緣起

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

ArcGIS提示建立金字塔

我們碰到這么一種情況,就是原始影像是不帶金字塔的,並且所在的目錄不允許修改,也就是不能將金字塔創建在其中,原始影像文件更是不允許修改,所以也不能更新內建金字塔。

解決

對於這個問題,為了加速影像的瀏覽,只能將金字塔建立在外部的目錄,而讀取的時候根據讀取輸出的分辨率,來確認是使用源影像讀取還是使用金字塔文件讀取,這都需要自己控制。
因為自己控制會將一些控制流程變復雜,所以我想讓GDAL直接支持索引到這個外部的金字塔文件。

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

我看了GDAL的RasterIO流程相關的代碼,簡單的制作了如下的流程圖:

GDALDataset::RasterIO簡單流程圖

GDALDefaultOverviews::OverviewScan()函數

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

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

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

  • 1、.ovr后綴金字塔文件
  • 2、.aux后綴金字塔文件
  • 3、.rrd后綴金字塔文件(如果配置有USE_RRD=YES
  • 4、影像元數據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,如果需要創建內建的金字塔,則做另外的實現。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2026 CODEPRJ.COM