GDAL API Tutorial中文翻譯(只介紹C++部分)
來源 https://www.gdal.org/gdal_tutorial.html (2018-10-28版)
1 Opening The File(開啟檔案)
原文:
Before opening a GDAL supported raster datastore it is necessary to register drivers. There is a driver for each supported format. Normally this is accomplished with the GDALAllRegister() function which attempts to register all known drivers, including those auto-loaded from .so files using GDALDriverManager::AutoLoadDrivers(). If for some applications it is necessary to limit the set of drivers it may be helpful to review the code from gdalallregister.cpp. Python automatically calls GDALAllRegister() when the gdal module is imported.
Once the drivers are registered, the application should call the free standing GDALOpen() function to open a dataset, passing the name of the dataset and the access desired (GA_ReadOnly or GA_Update).
翻譯:
開啟GDAL的光柵資料之前,必須註冊驅動.每一個被GDAL支援的格式都對應一個驅動.通常只要一次性呼叫函式GDALAllRegister(),就可以把所有驅動都註冊完畢.(下略)
驅動註冊完成後,你的程式就要利用GDALOpen()函式開啟一個數據集.這個函式的兩個輸入引數分別是資料集的名字,以及開啟方式(GA_ReadOnly只讀,GA_Update更新)。
C++程式碼
#include "gdal_priv.h" #include "cpl_conv.h" // for CPLMalloc() int main() { GDALDataset *poDataset; GDALAllRegister(); //驅動註冊完成後,你的程式就要利用GDALOpen()函式開啟一個數據集.這個函式的兩個輸入引數分別是資料集的名字,以及開啟方式 poDataset = (GDALDataset *) GDALOpen( pszFilename, GA_ReadOnly ); if( poDataset == NULL ) { ...;
原文:
Note that if GDALOpen() returns NULL it means the open failed, and that an error messages will already have been emitted via CPLError(). If you want to control how errors are reported to the user review the CPLError() documentation. Generally speaking all of GDAL uses CPLError() for error reporting. Also, note that pszFilename need not actually be the name of a physical file (though it usually is). It's interpretation is driver dependent, and it might be an URL, a filename with additional parameters added at the end controlling the open or almost anything. Please try not to limit GDAL file selection dialogs to only selecting physical files.
翻譯:
假如GDALOpen()的返回值是NULL,說明資料集開啟失敗。此時錯誤資訊會通過CPLError()傳送出來,其使用方法參見對應的文件。總的來說,所有的錯誤都是通過CPLError()報告的。pszFilename也不一定是一個實體檔案的名稱(不一定是,但往往是實體檔案的名稱)。具體如何理解pszFilename的含義取決於具體的驅動:含義可以是URL,或者檔名+額外引數,或者其它什麼東西。所以啟動GDAL的檔案選擇對話方塊時,請不要將選擇範圍僅限於實體檔案。
2 Getting Dataset Infomation(獲取資料集資訊)
原文:
As described in the GDAL Data Model, a GDALDataset contains a list of raster bands, all pertaining to the same area, and having the same resolution. It also has metadata, a coordinate system, a georeferencing transform, size of raster and various other information.
In the particular, but common, case of a "north up" image without any rotation or shearing, the georeferencing transform takes the following form :
adfGeoTransform[0] /* 左上角X座標 */
adfGeoTransform[1] /* 西-東 方向畫素解析度 */
adfGeoTransform[2] /* 0 */
adfGeoTransform[3] /* 左上角Y座標 */
adfGeoTransform[4] /* 0 */
adfGeoTransform[5] /* 北-南 方向畫素解析度(前面加負號) */
In the general case, this is an affine transform.
翻譯:
正如在GDAL 資料模型裡所說,資料集包括一系列的波段(可見光、紅外等--譯者注),這些波段對應同一個區域,且解析度相同。資料集還包括元資料、座標系、地理參考變換,光柵尺寸等資訊。
著重講一下,一副正北指向正上,並且沒有任何旋轉和拉伸的圖片,其地理參考變換都保持如下形式:(略)
這通常是仿射變換。
C++程式碼:
double adfGeoTransform[6];
printf( "Driver: %s/%s\n",
poDataset->GetDriver()->GetDescription(),
poDataset->GetDriver()->GetMetadataItem( GDAL_DMD_LONGNAME ) );
printf( "Size is %dx%dx%d\n",
poDataset->GetRasterXSize(), poDataset->GetRasterYSize(),
poDataset->GetRasterCount() );
if( poDataset->GetProjectionRef() != NULL )
printf( "Projection is `%s'\n", poDataset->GetProjectionRef() );
if( poDataset->GetGeoTransform( adfGeoTransform ) == CE_None )
{
printf( "Origin = (%.6f,%.6f)\n",
adfGeoTransform[0], adfGeoTransform[3] );
printf( "Pixel Size = (%.6f,%.6f)\n",
adfGeoTransform[1], adfGeoTransform[5] );
}
3 Fetching a Raster Band(獲取光柵波段)
原文:
At this time access to raster data via GDAL is done one band at a time. Also, there is metadata, block sizes, color tables, and various other information available on a band by band basis. The following codes fetches a GDALRasterBand object from the dataset (numbered 1 through GetRasterCount()) and displays a little information about it.
翻譯:
開啟資料集後,程式設計師可以每次讀取一個光柵波段的資料。此外,每個波段還有各自的元資料、影象尺寸、色表等資訊。下面的程式碼從資料集裡取出一個GDALRasterBand物件(物件編號從1開始,最後一個編號用函式GetRasterCount()返回)並顯示一些它的資訊。
C++程式碼:
GDALRasterBand *poBand;
int nBlockXSize, nBlockYSize;
int bGotMin, bGotMax;
double adfMinMax[2];
poBand = poDataset->GetRasterBand( 1 );
poBand->GetBlockSize( &nBlockXSize, &nBlockYSize );
printf( "Block=%dx%d Type=%s, ColorInterp=%s\n",
nBlockXSize, nBlockYSize,
GDALGetDataTypeName(poBand->GetRasterDataType()),
GDALGetColorInterpretationName(
poBand->GetColorInterpretation()) );
adfMinMax[0] = poBand->GetMinimum( &bGotMin );
adfMinMax[1] = poBand->GetMaximum( &bGotMax );
if( ! (bGotMin && bGotMax) )
GDALComputeRasterMinMax((GDALRasterBandH)poBand, TRUE, adfMinMax);
printf( "Min=%.3fd, Max=%.3f\n", adfMinMax[0], adfMinMax[1] );
if( poBand->GetOverviewCount() > 0 )
printf( "Band has %d overviews.\n", poBand->GetOverviewCount() );
if( poBand->GetColorTable() != NULL )
printf( "Band has a color table with %d entries.\n",
poBand->GetColorTable()->GetColorEntryCount() );
4 Reading Raster Data(讀取光柵資料)
原文:
There are a few ways to read raster data, but the most common is via the GDALRasterBand::RasterIO() method. This method will automatically take care of data type conversion, up/down sampling and windowing. The following code will read the first scanline of data into a similarly sized buffer, converting it to floating point as part of the operation.
float *pafScanline;
int nXSize = poBand->GetXSize();
pafScanline = (float *) CPLMalloc(sizeof(float)*nXSize);
poBand->RasterIO( GF_Read, 0, 0, nXSize, 1,
pafScanline, nXSize, 1, GDT_Float32,
0, 0 );
The pafScanline buffer should be freed with CPLFree() when it is no longer used.
The RasterIO call takes the following arguments.
CPLErr GDALRasterBand::RasterIO( GDALRWFlag eRWFlag,
int nXOff, int nYOff, int nXSize, int nYSize,
void * pData, int nBufXSize, int nBufYSize,
GDALDataType eBufType,
int nPixelSpace,
int nLineSpace )
Note that the same RasterIO() call is used to read, or write based on the setting of eRWFlag (either GF_Read or GF_Write). The nXOff, nYOff, nXSize, nYSize argument describe the window of raster data on disk to read (or write). It doesn't have to fall on tile boundaries though access may be more efficient if it does.
The pData is the memory buffer the data is read into, or written from. It's real type must be whatever is passed as eBufType, such as GDT_Float32, or GDT_Byte. The RasterIO() call will take care of converting between the buffer's data type and the data type of the band. Note that when converting floating point data to integer RasterIO() rounds down, and when converting source values outside the legal range of the output the nearest legal value is used. This implies, for instance, that 16bit data read into a GDT_Byte buffer will map all values greater than 255 to 255, the data is not scaled!
The nBufXSize and nBufYSize values describe the size of the buffer. When loading data at full resolution this would be the same as the window size. However, to load a reduced resolution overview this could be set to smaller than the window on disk. In this case the RasterIO() will utilize overviews to do the IO more efficiently if the overviews are suitable.
The nPixelSpace, and nLineSpace are normally zero indicating that default values should be used. However, they can be used to control access to the memory data buffer, allowing reading into a buffer containing other pixel interleaved data for instance.
翻譯:
讀取光柵資料的辦法不止一個,但是通常使用的函式式GDALRasterBand::RasterIO()這個辦法可以自動執行資料型別轉換、取樣、開窗等操作。下面的程式碼自動把光柵資料的首行資料拷貝到大小相似的另一塊記憶體裡,同時把資料轉化為浮點型。
pafScanline通過CPLMalloc申請,通過CPLFree()釋放。eRWFlag決定RasterIO函式是向光柵資料讀取還是寫入(GF_Read是讀取,GF_WRITE是寫入)。nXOff, nYOff,定位了被操作的光柵資料的首地址在第幾列,第幾行。nXSize和nYSize代表被操作資料的寬度和高度。被操作的資料塊的邊界不需要與光柵資料的邊界相同,但是假如重合,會提高讀寫效率。
與光柵資料的讀寫相對應的另一塊資料地址是pData。從(向)光柵讀取(寫入)的資料將寫入(讀取自)pData。pData的型別必須與eBufType一致,如GDT_Float32或GDT_Byte。(假如光柵資料的型別與pData型別不同)RasterIO()將自動完成型別轉換。注意,從浮點向整形轉化時,小數點後面的被捨棄。當被讀取一方的資料超過了被寫入方資料型別的表數範圍時,被寫入方的資料將飽和。比方說,16位元的資料(表數範圍0-65535)寫入位元組型資料(0-255,譯者注)時,所有超過255的資料都作為255寫入!
nBufXSzie與nBufYSize描述pData的尺寸。假如pData和光柵保持同等解析度,那麼pdata和光柵的尺寸將相等。假如(從光柵向轉化pData後),解析度降低,則pData佔據的記憶體將少於原始資料。這時,RasterIO將採用縮圖來實現更高效的轉化。
nPixelSpace和nLineSpace通常為0。假如不為0,RasterIO可以實現隔行/隔列的資料轉移。
5 Closing the Dataset(關閉資料集)
原文:
Please keep in mind that GDALRasterBand objects are owned by their dataset, and they should never be destroyed with the C++ delete operator. GDALDataset's can be closed by calling GDALClose() (it is NOT recommended to use the delete operator on a GDALDataset for Windows users because of known issues when allocating and freeing memory across module boundaries. See the relevant topic on the FAQ). Calling GDALClose will result in proper cleanup, and flushing of any pending writes. Forgetting to call GDALClose on a dataset opened in update mode in a popular format like GTiff will likely result in being unable to open it afterwards.
翻譯:
請牢記,波段資料的擁有者是資料集,因此不能用c++的 delete操作釋放。資料集可以用GDALClose()關閉(在windows平臺上,不建議用delete操作直接刪除,這可能導致邊界記憶體無法釋放,見FAQ)。只有呼叫GDALClose()此能妥善釋放記憶體,並且完成等待中的寫操作(假如有的話)。假如有一個更新模式下的資料集,正在寫入GTiff資料,但程式退出時沒有用GDALClose()關閉,則這個Tiff檔案很可能無法再正常開啟。
6 Techniques for Creating Files(開啟檔案的手段)
原文:
New files in GDAL supported formats may be created if the format driver supports creation. There are two general techniques for creating files, using CreateCopy() and Create(). The CreateCopy method involves calling the CreateCopy() method on the format driver, and passing in a source dataset that should be copied. The Create method involves calling the Create() method on the driver, and then explicitly writing all the metadata, and raster data with separate calls. All drivers that support creating new files support the CreateCopy() method, but only a few support the Create() method.
To determine if a particular format supports Create or CreateCopy it is possible to check the DCAP_CREATE and DCAP_CREATECOPY metadata on the format driver object. Ensure that GDALAllRegister() has been called before calling GetDriverByName(). In this example we fetch a driver, and determine whether it supports Create() and/or CreateCopy().
Note that a number of drivers are read-only and won't support Create() or CreateCopy().
C++程式碼:
#include "cpl_string.h"
...
const char *pszFormat = "GTiff";
GDALDriver *poDriver;
char **papszMetadata;
poDriver = GetGDALDriverManager()->GetDriverByName(pszFormat);
if( poDriver == NULL )
exit( 1 );
papszMetadata = poDriver->GetMetadata();
if( CSLFetchBoolean( papszMetadata, GDAL_DCAP_CREATE, FALSE ) )
printf( "Driver %s supports Create() method.\n", pszFormat );
if( CSLFetchBoolean( papszMetadata, GDAL_DCAP_CREATECOPY, FALSE ) )
printf( "Driver %s supports CreateCopy() method.\n", pszFormat );
翻譯:
建立檔案的辦法有兩個:Create()和CreateCopy().CreateCopy()通過對應格式的驅動來呼叫CreateCopy函式,並且在函式輸入引數裡註明資料來源.Create()也通過對應格式的驅動呼叫Create函式,呼叫Create函式之後,再呼叫其它函式,寫入元資料,光柵資料等.所有驅動,只要支援建立新檔案,都支援CreateCopy方法,只有少數支援Create方法.
通過查詢元資料DCAP_CREATE/DCAP_CREATECOPY,檢查一個驅動是否支援Create/CreateCopy.確保呼叫GetDriverByName之前先呼叫GDALAllRegister().下面的例子,我們檢查驅動是否支援Create/CreateCopy.
注意,有一些只讀驅動,不支援Create/CreateCopy
7 Using CreateCopy()(使用CreateCopy)
原文:
The GDALDriver::CreateCopy() method can be used fairly simply as most information is collected from the source dataset. However, it includes options for passing format specific creation options, and for reporting progress to the user as a long dataset copy takes place. A simple copy from the a file named pszSrcFilename, to a new file named pszDstFilename using default options on a format whose driver was previously fetched might look like this:
GDALDataset *poSrcDS =
(GDALDataset *) GDALOpen( pszSrcFilename, GA_ReadOnly );
GDALDataset *poDstDS;
poDstDS = poDriver->CreateCopy( pszDstFilename, poSrcDS, FALSE,
NULL, NULL, NULL );
/* Once we're done, close properly the dataset */
if( poDstDS != NULL )
GDALClose( (GDALDatasetH) poDstDS );
GDALClose( (GDALDatasetH) poSrcDS );
Note that the CreateCopy() method returns a writable dataset, and that it must be closed properly to complete writing and flushing the dataset to disk. In the Python case this occurs automatically when "dst_ds" goes out of scope. The FALSE (or 0) value used for the bStrict option just after the destination filename in the CreateCopy() call indicates that the CreateCopy() call should proceed without a fatal error even if the destination dataset cannot be created to exactly match the input dataset. This might be because the output format does not support the pixel datatype of the input dataset, or because the destination cannot support writing georeferencing for instance.
A more complex case might involve passing creation options, and using a predefined progress monitor like this:
#include "cpl_string.h"
...
char **papszOptions = NULL;
papszOptions = CSLSetNameValue( papszOptions, "TILED", "YES" );
papszOptions = CSLSetNameValue( papszOptions, "COMPRESS", "PACKBITS" );
poDstDS = poDriver->CreateCopy( pszDstFilename, poSrcDS, FALSE,
papszOptions, GDALTermProgress, NULL );
/* Once we're done, close properly the dataset */
if( poDstDS != NULL )
GDALClose( (GDALDatasetH) poDstDS );
CSLDestroy( papszOptions );
翻譯:
CreateCopy函式使用較簡單,因為多數資訊可以從源資料集獲得.但是,函式輸入引數裡包括與格式相關的建立選項,以及向用戶回報拷貝進度的選項.下面的例子展示的是從pszSrcFilename向pszDstFilename拷貝的過程,檔案格式由驅動決定.
注意,CreateCopy返回一個可寫的資料集,它必須採用合適的方法關閉,以保證待寫資料寫入磁碟.在例子裡,緊跟在目標檔名pszDstFilename後的選項為FASLE,含義是,即使目標檔案建立後,與原資料集不能完全一致,CreateCopy函式也不要報"致命錯誤",而是要繼續執行下去.這可能是因為輸出的檔案格式不支援源資料集的格式,或者因為輸出檔案不支援寫入地理參考.
更復雜的例子,輸入變數裡包括建立選項,並且結合了一個已經定義的進度監視物件.
8 Using Create()(使用Create())
原文:
For situations in which you are not just exporting an existing file to a new file, it is generally necessary to use the GDALDriver::Create() method (though some interesting options are possible through use of virtual files or in-memory files). The Create() method takes an options list much like CreateCopy(), but the image size, number of bands and band type must be provided explicitly.
GDALDataset *poDstDS;
char **papszOptions = NULL;
poDstDS = poDriver->Create( pszDstFilename, 512, 512, 1, GDT_Byte,
papszOptions );
Once the dataset is successfully created, all appropriate metadata and raster data must be written to the file. What this is will vary according to usage, but a simple case with a projection, geotransform and raster data is covered here.
double adfGeoTransform[6] = { 444720, 30, 0, 3751320, 0, -30 };
OGRSpatialReference oSRS;
char *pszSRS_WKT = NULL;
GDALRasterBand *poBand;
GByte abyRaster[512*512];
poDstDS->SetGeoTransform( adfGeoTransform );
oSRS.SetUTM( 11, TRUE );
oSRS.SetWellKnownGeogCS( "NAD27" );
oSRS.exportToWkt( &pszSRS_WKT );
poDstDS->SetProjection( pszSRS_WKT );
CPLFree( pszSRS_WKT );
poBand = poDstDS->GetRasterBand(1);
poBand->RasterIO( GF_Write, 0, 0, 512, 512,
abyRaster, 512, 512, GDT_Byte, 0, 0 );
/* Once we're done, close properly the dataset */
GDALClose( (GDALDatasetH) poDstDS );
翻譯:
假如你不是要從已有檔案拷貝到新檔案,那麼你可以採用Create函式(還有其它辦法,如虛擬檔案,記憶體檔案等).Create函式的輸入格式與CreateCopy類似,但是必須明確其圖片尺寸,波段數目,波段型別.
建立完成後,元資料和光柵資料都要寫入新檔案.其內容與具體使用有關,下面介紹一個含有投影資料,地理變換和光柵資料的例子.