GDAL C++ API 学习之路 (1)Dataset篇 代码示例 翻译 自学

GDALDataset Class        “gdal_priv.h”

一组关联的栅格波段,通常来自一个文件。

封装一个或多个栅格波段的数据集

在GDAL中,GDALDataset类并没有直接封装打开文件的方法。相反,您需要使用GDALOpen或其他相关函数来打开数据源,并将其返回为一个新的GDALDataset对象。

使用 GDALOpen() 或 GDALOpenShared() 为命名文件创建 GDALDataset,或使用 GDALDriver::Create() 或 GDALDriver::CreateCopy() 创建新数据集。

GDALOpen()

GDALOpen()是默认函数,它将数据集加载到应用程序的内存中,并阻止其他应用程序打开同一数据集。这通常称为独占访问(exclusive access)

poDataset = (GDALDataset *) GDALOpen( "filenema.tif", GA_ReadOnly );

加载数据时有GA_UpdateGA_ReadOnly两种模式

(GDALDataset *)GDALOpen()的详细解释:http://t.csdn.cn/PFmc6

GDALOpenShared()

GDALOpenShared()允许多个应用程序共享数据集,因此它允许在同一时间内打开多个实例。这通常称为共享访问(shared access)

如果您的应用程序需要同时打开并读取或写入多个数据集,则每个数据集都应该使用GDALOpenShared()打开,以避免竞争条件或进程崩溃,但如果您可以确保每个数据集只被一个应用程序或线程访问,那么GDALOpen()是一个合适的选择

GDALDataset* dataset1 = (GDALDataset*) GDALOpenShared("filename1", GA_ReadOnly);
GDALDataset* dataset2 = (GDALDataset*) GDALOpenShared("filename2", GA_ReadOnly);

如果之前已经有线程打开了这个数据集,则它会返回一个指向相同数据集的指针,避免重复打开数据集而浪费资源。这也使得多个线程可以同时访问同一个数据集,提高了程序的效率

注:

GDALOpenShared()函数可以利用已经建立的缓存,是因为在打开数据集时,它会检查内存中是否已经有缓存了该数据集的信息。如果有,则使用已有的缓存而不是重新从硬盘读取数据集。这种缓存机制可以减少程序读取硬盘数据的次数,提高读取效率

通过对数据集进行缓存,GDALOpenShared()函数减少了读取硬盘数据集的次数,节省了系统资源,提高了程序效率,对于处理多个数据集的任务尤为重要

如果使用GDALOpen()函数分别打开多个不同的数据集,会占用较多的缓存和内存,导致程序效率低下,甚至引起内存不足的问题

GDALClose()

参数:要删除的数据集的名称

返回值: 成功 CE_None     失败 CE_Failure

关闭 GDAL 数据集并解除分配与其关联的所有资源的公认方法

关闭GDAL数据集,并且释放与数据集相关的所有资源,以便于操作系统回收该数据集所占用的空间

// 打开数据集
dataset = (GDALDataset*)GDALOpen("filename.tif", GA_ReadOnly);

// 关闭数据集
GDALClose(dataset);

~GDALDataset()

GDALDataset的析构方法

两种释放数据集方式的比较

    GDALAllRegister();
    GDALDataset* dataset = (GDALDataset*) GDALOpen("my_data.tif", GA_ReadOnly);

    GDALClose(dataset);    //关闭数据集

    dataset = (GDALDataset*) GDALOpen("my_data2.tif", GA_ReadOnly);

    delete dataset;      //销毁对象


    

GDALClose(dataset),它关闭了数据集并释放占用的资源,但是对象dataset并没有被摧毁,可以继续使用打开新的数据集

delete dataset,直接销毁对象,并在此过程中调用析构函数,释放该对象所占用的所有资源

对于 Windows 用户,不建议对数据集对象使用 delete 运算符,因为在跨模块边界分配和释放内存时存在已知问题。调用GDALClose()是一个更好的选择

GetRasterXSize()

获取栅格宽度(以像素为单位)  相当于 C 函数 GDALGetRasterXSize()

参数:无参

返回值:int

GetRasterYSize()

获取栅格高度(以像素为单位)  相当于 C 函数 GDALGetRasterYSize()

参数:无参

返回值:int

关于GetRasterXSize和GetXSize的理解:

https://blog.csdn.net/qq_69574549/article/details/129896322

GetRasterCount()

获取此数据集上的栅格波段数       与 C 函数 GDALGetRasterCount() 相同

参数:无参

返回值:int

GDALDataset * dataset = (GDALDataset *)GDALOpen("1.jpeg" , GA_ReadOnly);
	
cout<GetRasterXSize()<GetRasterYSize()<GetRasterCount()<

700
700
3

GetRasterBand()

GDALRasterBand *GetRasterBand (int)  获取数据集的波段对象

相当于 C 函数 GDALGetRasterBand()。

参数:  nBandId – 要获取的波段的索引号,从 1 到 GetRasterCount()。

返回:  nBandId 第 n 波段对象

后面有GDALRasterBand的API,但是我们也提前了解下:http://t.csdn.cn/0nS96

FlushCache()

将所有写入缓存数据刷新到磁盘        此方法与 C 函数 GDALFlushCache() 相同

参数: bAtClosing – 这是否从 GDALDataset 析构函数调用

返回:  成功情况下CE_None

    GDALDataset *ds = (GDALDataset *) GDALOpen("example.tif", GA_Update);

    // 读取栅格数据
    GDALRasterBand *band = ds->GetRasterBand(1);
    int xsize = band->GetXSize();
    int ysize = band->GetYSize();
    float *data = new float[xsize * ysize];
    band->RasterIO(GF_Read, 0, 0, xsize, ysize, data, xsize, ysize, GDT_Float32, 0, 0);

    // 修改栅格数据
    for (int i = 0; i < xsize * ysize; i++) {
        data[i] += 1.0;
    }

    // 写入修改后的栅格数据
    band->RasterIO(GF_Write, 0, 0, xsize, ysize, data, xsize, ysize, GDT_Float32, 0, 0);

    // 刷新缓存,将修改写入文件
    band->FlushCache();

    delete [] data;

    // 关闭栅格文件
    GDALClose(ds);

中间暂时看不懂没关系,只需要知道中间部分是修改了example.tif的band1的数据,每个数据都+1了

bool bAtClosesing

bool bAtClosesing参数表示是否在文件关闭时自动刷新缓存。如果设置为true,则在调用GDALClose()函数关闭文件时会自动调用FlushCache()函数,将缓存中的修改写入文件中。如果设置为false,则在文件关闭时不会自动刷新缓存,需要在程序中手动调用FlushCache()函数来刷新缓存

需要注意的是,当bAtClosing为true时,FlushCache()函数的调用并不会直接关闭文件,而是将缓存中的修改写入文件后保持文件处于打开状态。在程序结束时,应该手动调用GDALClose()函数来关闭文件。如果程序异常退出或崩溃,未刷新的数据将会丢失。

一般来说,如果不需要频繁地修改文件,建议将bAtClosesing参数设置为true,确保数据在文件关闭前都被写入文件中。如果需要频繁地修改文件,可以将bAtClosing设置为false,并在必要的时候手动调用FlushCache()函数来刷新缓存

GetEstimatedRAMUsage()

返回此数据集的固有 RAM 使用情况

返回: RAM 使用率(以字节为单位),如果未知,则为 -1(默认实现返回 -1)

意义

用于估算当前数据集占用内存的函数。它的作用是计算打开当前数据集所需的内存大小,包括数据集的元数据、波段数据、缓存等。

在数据处理中,我们通常需要在内存中进行数据的计算和处理,因此需要知道当前数据集占用的内存大小,以便预估程序运行的内存需求,避免程序因内存不足而崩溃或运行缓慢。GetEstimatedRAMUsage()函数可以帮助我们计算当前数据集所需的内存大小,从而更好地管理程序的内存使用

GetSpatialRef()

virtual const OGRSpatialReference *GetSpatialRef() const 

与 C 函数 GDALGetSpatialRef() 相同

获取此数据集的空间参考             

返回:  poSRS –空间参考系统对象     当投影定义不可用时,将返回 null

poSRS是一个OGRSpatialReference对象的指针

OGRSpatialReference

OGRSpatialReference是GDAL/OGR库中用于处理空间参考系统的类。它可以表示和操作不同的空间参考系统,如经纬度、投影坐标系等。通过OGRSpatialReference类,可以获取和设置空间参考系统的各种属性,如坐标系名称、投影方法、椭球体参数等。同时,OGRSpatialReference类也提供了与EPSG和PROJ.4等标准的互操作性,使得用户可以方便地使用已有的空间参考系统定义

Const

函数返回的是一个指向内部静态缓冲区的指针,因此该指针指向的字符串应该被视为只读字符串,不应该被修改。如果尝试修改该指针指向的字符串,可能会导致不可预测的行为

后面有很多类似的获取(Get)类型的方法,一般都是const类型的,需要注意

SetSpatialRef()

virtual CPLErr SetSpatialRefconst OGRSpatialReference *poSRS)    

此方法与 C GDALSetSpatialRef() 函数相同。

设置此数据集的空间参考系统

参数:poSRS – 空间参考系统对象

返回:如果发生错误,CE_Failure,否则CE_None。

取消空间参考系统

当需要取消数据集的空间参考信息时,可以将nullptr(空指针)作为参数传递给SetSpatialRef()函数,以表示当前数据集不再具有空间参考信息。

需要注意的是,并非所有的GDAL驱动程序都支持取消数据集的空间参考信息。因此,在使用SetSpatialRef()函数取消数据集的空间参考信息之前,需要确认当前驱动程序是否支持该操作。可以通过调用GDALDriver类的GetMetadataItem()方法,并传递参数“DCAP_UNSETTABLESRS”,来查询当前驱动程序是否支持取消数据集的空间参考信息。如果返回值为“YES”,则表示当前驱动程序支持取消数据集的空间参考信息

举例

GDALAllRegister();

GDALDriverManager* poDriverManager = GetGDALDriverManager();

const char* pszDriverName = "GTiff"; // 替换成所需的驱动名称

GDALDriver* poDriver = poDriverManager->GetDriverByName(pszDriverName);

if (poDriver->GetMetadataItem("DCAP_UNSETTABLESRS") != NULL) {
        cout << "支持取消数据集的空间参考信息." << endl;
    } else {
        cout << "不支持取消数据集的空间参考信息" << endl;
    }

由此可见,GTiff并不支持取消数据集的空间参考信息

但是,不同版本的GDAL驱动程序可能会有不同的功能和支持,因此某些驱动程序可能会支持取消数据集的空间参考信息,而另一些则不支持。因此,在使用某个GDAL驱动程序之前,最好查看该驱动程序的文档以及GDAL版本的兼容性信息,以确定它支持哪些功能和选项

GetProjectionRef

const char *GetProjectionRef(void) const  与 C 函数 GDALGetProjectionRef() 相同

提取此数据集的投影定义字符串       

参数:无参

返回:当投影定义不可用时,将返回空(但不是 NULL)字符串

GDALDataset *dataset = (GDALDataset *) GDALOpen("filename.tif", GA_ReadOnly);
const char *projection = dataset->GetProjectionRef();
GEOGCS["NAD83",DATUM["North_American_Datum_1983",SPHEROID["GRS 1980",6378137,298.257222101004,AUTHORITY["EPSG","7019"]],AUTHORITY["EPSG","6269"]],PRIMEM["Greenwich",0],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AXIS["Latitude",NORTH],AXIS["Longitude",EAST],AUTHORITY["EPSG","4269"]]

SetProjection

CPLErr SetProjectionconst char *pszProjection)      此方法与 C GDALSetProjection() 函数相同

设置此数据集的投影参考字符串

参数:psz投影 – 投影引用字符串      字符串应采用 OGC WKT 或 PROJ.4 格式

返回:如果发生错误,CE_Failure,否则CE_None

OGC WKT 示例:

// 设置 WGS84 地理坐标系
SetProjection("GEOGCS[\"WGS 84\",DATUM[\"WGS_1984\",SPHEROID[\"WGS 84\",6378137,298.257223563]],PRIMEM[\"Greenwich\",0],UNIT[\"degree\",0.0174532925199433]]");

// 设置 UTM 投影坐标系
SetProjection("PROJCS[\"WGS 84 / UTM zone 18N\",GEOGCS[\"WGS 84\",DATUM[\"WGS_1984\",SPHEROID[\"WGS 84\",6378137,298.257223563]],PRIMEM[\"Greenwich\",0],UNIT[\"degree\",0.0174532925199433]],PROJECTION[\"Transverse_Mercator\"],PARAMETER[\"latitude_of_origin\",0],PARAMETER[\"central_meridian\",-75],PARAMETER[\"scale_factor\",0.9996],PARAMETER[\"false_easting\",500000],PARAMETER[\"false_northing\",0],UNIT[\"metre\",1]]");

PROJ.4 示例:

// 设置 WGS84 地理坐标系
SetProjection("+proj=longlat +datum=WGS84 +no_defs");

// 设置 UTM 投影坐标系
SetProjection("+proj=utm +zone=18 +datum=WGS84 +units=m +no_defs");

OGC WKT 太麻烦了,我选择PROJ [doge]

不过,OGC WKT 格式作为一种标准格式,在某些应用场景中也有其优势,例如与其他标准格式的互操作性更好,可读性更强等。具体使用哪种格式还需要根据具体应用场景和需求来进行选择

可以通过将projection参数设置为NULL或空字符串来取消空间参考

代码:

GDALAllRegister();

GDALDataset *dataset = (GDALDataset *) GDALOpen("USGS_1_n33w096_20211124.tif", GA_Update);

const char * projection = dataset->GetProjectionRef();   //打印原来的投影定义字符串
cout<SetProjection(NULL);    //取消空间参考系统
//dataset->SetProjection("");
	
projection = dataset->GetProjectionRef();    //再次打印投影定义字符串
cout<

 结果:无论是使用NULL还是"",都会显示格局被破坏了,取消空间参考可能导致元数据信息与实际数据不一致,所有一般还是不要取消空间参考,没了参考,数据其实就没有是使用价值了

在使用取消空间参考系统前,一定要提前备份好数据

Warning 1: USGS_1_n33w096_20211124.tif: The IFD has been rewritten at the end of the file, which breaks COG layout.

GDALDataset 的东西一篇写完太多了,今天就到这了

持续补充、修改、更新。。。。。

你可能感兴趣的:(GDAL,学习,c++,开源)