作者:朱金灿
来源:http://blog.csdn.net/clever101
最近使用gdal库比较多,就谈谈gdal库的一些使用心得。
第一个是GDALOpen的访问权限参数会影响图像的创建金字塔方式。比如你是这样打开图像和创建金字塔:
std::string strImgPath = _T(“C:\1.tif”); GDALDataset* mGdalDataset=(GDALDataset*)(GDALOpen(strImgPath.c_str(),GA_Update)); mGdalDataset ->BuildOverviews(_T("NEAREST"),nLevel,pBandList,0,NULL,GdalBuildPyramidProgress,NULL);
运行完这段代码之后你会奇怪地发现在图像文件所在的文件夹并没有ovr文件或rrd文件出现,那么究竟有没有金字塔生成呢?实际上是有的。那么图像金字塔数据究竟存储在哪里,我猜测是存储在图像文件本身去了。为何这么说呢?因为我试着把第一行代码的GA_Update改为GA_ReadOnly,结果出现了ovr文件,也就是说当设置为GA_Update,金字塔数据是有可能放在图像文件的,当然我没有确认。这里还有一些疑问:如果金字塔数据是存储在文件里,那么对于tif文件具体是存储在哪里?对于其它图像文件又是存储在哪里呢?
第二个在调用完RasterIO函数对图像进行写入操作之后只是保留在缓存,需要再调用FlushCache函数才能真正把数据写到磁盘去。
第三个是网上有一篇关于坐标转换的教程:GDAL库学习笔记(五):坐标系之间的转化。其中有一段代码是这样的:
OGRSpatialReference oUTM, *poLatLong; OGRCoordinateTransformation *poTransform; oUTM.SetProjCS("UTM 17 / WGS84"); oUTM.SetWellKnownGeogCS( "WGS84" ); oUTM.SetUTM( 17 ); poLatLong = oUTM.CloneGeogCS(); poTransform = OGRCreateCoordinateTransformation( &oUTM, poLatLong ); if( poTransform == NULL ) { ... } ... if( !poTransform->Transform( nPoints, x, y, z ) ) ...
我试过多次,OGRCreateCoordinateTransformation总是执行失败。后来看了gdal的源码,发现ogr集成prj4库进行投影坐标转换颇有些坑爹的地方。我们看一些OGRCreateCoordinateTransformation函数大致是怎么做的:
OGRCreateCoordinateTransformation函数大致是怎么做的: OGRCoordinateTransformation* OGRCreateCoordinateTransformation( OGRSpatialReference *poSource, OGRSpatialReference *poTarget ) { OGRProj4CT *poCT; if( !LoadProjLibrary() ) { CPLError( CE_Failure, CPLE_NotSupported, "Unable to load PROJ.4 library (%s), creation of " "OGRCoordinateTransformation failed.", GetProjLibraryName() ); return NULL; } poCT = new OGRProj4CT(); if( !poCT->Initialize( poSource, poTarget ) ) { delete poCT; return NULL; } else { return poCT; } }其中LoadProjLibrary的含义很明显,就是加载prj4库。我们再看看LoadProjLibrary函数:
static int LoadProjLibrary() { CPLMutexHolderD( &hPROJMutex ); static int bTriedToLoad = FALSE; const char *pszLibName; if( bTriedToLoad ) return( pfn_pj_transform != NULL ); bTriedToLoad = TRUE; pszLibName = GetProjLibraryName(); #ifdef PROJ_STATIC pfn_pj_init = pj_init; pfn_pj_init_plus = pj_init_plus; pfn_pj_fwd = pj_fwd; pfn_pj_inv = pj_inv; pfn_pj_free = pj_free; pfn_pj_transform = pj_transform; pfn_pj_get_errno_ref = (int *(*)(void)) pj_get_errno_ref; pfn_pj_strerrno = pj_strerrno; pfn_pj_dalloc = pj_dalloc; #if PJ_VERSION >= 446 pfn_pj_get_def = pj_get_def; #endif #else CPLPushErrorHandler( CPLQuietErrorHandler ); pfn_pj_init = (projPJ (*)(int, char**)) CPLGetSymbol( pszLibName, "pj_init" ); CPLPopErrorHandler(); if( pfn_pj_init == NULL ) return( FALSE ); pfn_pj_init_plus = (projPJ (*)(const char *)) CPLGetSymbol( pszLibName, "pj_init_plus" ); pfn_pj_fwd = (projUV (*)(projUV,projPJ)) CPLGetSymbol( pszLibName, "pj_fwd" ); pfn_pj_inv = (projUV (*)(projUV,projPJ)) CPLGetSymbol( pszLibName, "pj_inv" ); pfn_pj_free = (void (*)(projPJ)) CPLGetSymbol( pszLibName, "pj_free" ); pfn_pj_transform = (int (*)(projPJ,projPJ,long,int,double*, double*,double*)) CPLGetSymbol( pszLibName, "pj_transform" ); pfn_pj_get_errno_ref = (int *(*)(void)) CPLGetSymbol( pszLibName, "pj_get_errno_ref" ); pfn_pj_strerrno = (char *(*)(int)) CPLGetSymbol( pszLibName, "pj_strerrno" ); CPLPushErrorHandler( CPLQuietErrorHandler ); pfn_pj_get_def = (char *(*)(projPJ,int)) CPLGetSymbol( pszLibName, "pj_get_def" ); pfn_pj_dalloc = (void (*)(void*)) CPLGetSymbol( pszLibName, "pj_dalloc" ); CPLPopErrorHandler(); #endif if( pfn_pj_transform == NULL ) { CPLError( CE_Failure, CPLE_AppDefined, "Attempt to load %s, but couldn't find pj_transform. " "Please upgrade to PROJ 4.1.2 or later.", pszLibName ); return FALSE; } return( TRUE ); }
gdal库集成prj4库有两种方式:静态库集成和动态库集成,使用预处理器PROJ_STATIC。首先看看静态库集成:
pfn_pj_init = pj_init; pfn_pj_init_plus = pj_init_plus; pfn_pj_fwd = pj_fwd; pfn_pj_inv = pj_inv; pfn_pj_free = pj_free; pfn_pj_transform = pj_transform; pfn_pj_get_errno_ref = (int *(*)(void)) pj_get_errno_ref; pfn_pj_strerrno = pj_strerrno; pfn_pj_dalloc = pj_dalloc;
这里只是函数指针的赋值,那么函数调用的地方在哪里呢?我并没有找到。动态库集成就更扯淡了,首先通过GetProjLibraryName函数获取prj4库的动态库名字,这里名字规定为:
#if (defined(WIN32) || defined(WIN32CE)) && !defined(__MINGW32__) # define LIBNAME "proj.dll" #elif defined(__CYGWIN__) || defined(__MINGW32__) // XXX: If PROJ.4 library was properly built using libtool in Cygwin or MinGW // environments it has the interface version number embedded in the file name // (it is CURRENT-AGE number). If DLL came somewhere else (e.g. from MSVC // build) it can be named either way, so use PROJSO environment variable to // specify the right library name. By default assume that in Cygwin/MinGW all // components were buit in the same way. # define LIBNAME "libproj-0.dll" #elif defined(__APPLE__) # define LIBNAME "libproj.dylib" #else # define LIBNAME "libproj.so" #endif
也就是说假如在windows平台下不叫proj.dll,压根加载不了prj4库,还有致命一条:proj.dll究竟放在哪个路径下呢?据我经验,LoadLibrary没有指定路径的话,在Windows平台只能在当前目录和在系统环境变量路径中找到,具体见:关于DLL搜索路径的顺序问题。动态库集成和静态库集成存在一样的问题,只找到函数地址,并不见调用的地方。