博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
数据图像GDAL对于raw数据支持的一个bug
阅读量:7207 次
发布时间:2019-06-29

本文共 4351 字,大约阅读时间需要 14 分钟。

首先声明,我是一个菜鸟。一下文章中出现技术误导情况盖不负责

    下面的GDAL版本针对最新的1.10.0而言,对于GDAL1.9.2问题照旧。

    最近在处理卫星的长条带数据,图像的行数差不多200w行阁下,格式的raw格式。可以应用VRT文件来很方便的对raw数据进行管理。比如要提取raw数据中的某一部份等等。由于处理的数据是1536列的16bit数据,并对raw数据进行提取。比如指定从多少行开始,到多少行结束。关于VRT数据进行管理raw数据可以参考《》和《应用GDAL下载并转换SRTM的DEM数据(二)》这两篇文章。

    原来功能已实现,明天测试说起始位置超越70w行(最后定位到如果大于即是699051行就会出错)提取出来的数据就不准确了,开始觉得多是我的程序写的有问题,因为我的程序图像的宽高偏移量都是用int,最大值应当是2147483647,对于图像的宽高来说,这个数完全够用,可是对于图像的偏移量就不必定了。

    图像的偏移量就是指图像的第一个像元值先对于raw文件的起始位置的字节数,比如下面的问题,就是出在这个图像偏移量,由于之前用的是int来进行存储,对于最大值来说就是2147483647。

    由于每行图像是1536列的16bit数据,所以每行就是3072字节,699051行就是2147484672,这个值已显著大于int所能表现的最大值2147483647了,看来问题就是出在这里了,按照这个思路将程序中的图像偏移量全体用__int64进行表现,按理说不会出现问题,可是问题照旧。

    初步查看了一下GDAL的源代码,发现图像的偏移量是用的一个名为vsi_l_offset的类型进行表现,查看定义会发现下面这样的重定义:

/* ==================================================================== *//*      64bit stdio file access functions.  If we have a big size       *//*      defined, then provide protypes for the large file API,          *//*      otherwise redefine to use the regular api.                      *//* ==================================================================== */typedef GUIntBig vsi_l_offset;

     以及

/* -------------------------------------------------------------------- *//*      64bit support                                                   *//* -------------------------------------------------------------------- */#if defined(WIN32) && defined(_MSC_VER)#define VSI_LARGE_API_SUPPORTEDtypedef __int64          GIntBig;typedef unsigned __int64 GUIntBig;#elif HAVE_LONG_LONGtypedef long long        GIntBig;typedef unsigned long long GUIntBig;#elsetypedef long             GIntBig;typedef unsigned long    GUIntBig;#endif

     从下面的定义来看,vsi_l_offset实质上就是一个64为的无符号整型,按理说不会出错啊,可是为什么还是会出错呢?继续调试GDAL的代码,在文件f:\Work\3rdPart\gdal-1.10.0\frmts\vrt\vrtdataset.cpp的926行阁下,会发现下面的代码:

    每日一道理
聪明人学习,像搏击长空的雄鹰,仰视一望无际的大地;愚笨的人学习,漫无目的,犹如乱飞乱撞的无头飞蛾;刻苦的人学习,像弯弯的河流,虽有曲折,但终会流入大海;懒惰的人学习,像水中的木头,阻力越大倒退得越快。
/* -------------------------------------------------------------------- *//*      Collect required information.                                   *//* -------------------------------------------------------------------- */        if( CSLFetchNameValue(papszOptions, "ImageOffset") != NULL )            nImageOffset = atoi(CSLFetchNameValue(papszOptions, "ImageOffset"));

     最后发现是函数atoi出问题了,查看MSDN的说明,会发现atoi函数,对于超出int存储范围时会返回int存储的最大值或者最小值。按照下面的偏移量是2147484672,通过下面这句代码转换的结果就成2147483647,从而致使后续定位错误,致使提取的图像失败。晓得原因,我们就可以应用一个函数来替换atoi这个函数。下面是我写的一个函数用来替换atoi来支撑int64,具体如下:

// define atoi64 transform string to 64bit intGIntBig atoi64(const char * str);GUIntBig atoi64u(const char * str);// function implementations/* -------------------------------------------------------------------- *//*      string to 64bit int support(liml 2013-5-17)                     *//* -------------------------------------------------------------------- */#if defined(WIN32) && defined(_MSC_VER)GIntBig atoi64(const char * str) { return _atoi64(str); }GUIntBig atoi64u(const char * str) { return _strtoui64(str, NULL, 10); }#elif HAVE_LONG_LONGGIntBig atoi64(const char * str) { return strtoll(str, NULL, 10); }GUIntBig atoi64u(const char * str) { return strtoull(str, NULL, 10); }#elseGIntBig atoi64(const char * str) { return _atoi64(str); }GUIntBig atoi64u(const char * str) { return _strtoui64(str, NULL, 10); }#endif

     下面的代码在Windows平台下测试通过,Linux下没有进行测试,准确性未知。有了下面的函数,就可以用函数atoi64来代替下面的atoi函数即可,然后重新编译生成GDAL,替换原来的dll即可。

    修改下面的代码后,这个提取的问题解决,可是应用GDAL打开之后关闭发现又出问题了,显示的图像不准确。继续调试代码,还发现两处代码,分别是:文件f:\Work\3rdPart\gdal-1.10.0\frmts\vrt\vrtrawrasterband.cpp的334行和403行阁下:

nImageOffset = atoi(CPLGetXMLValue( psTree, "ImageOffset", "0") );
/* -------------------------------------------------------------------- *//*      Set other layout information.                                   *//* -------------------------------------------------------------------- */    CPLCreateXMLElementAndValue(         psTree, "ImageOffset",         CPLSPrintf("%d",(int) poRawRaster->GetImgOffset()) );

     对于下面第一处,将atoi函数替换为atoi64即可,对于第二处将%d替换为%llu并将前面的强制类型转换(int)去掉即可。

    通过下面的修改,对于raw格式的大图像偏移量应当不会出现什么别的问题了。一个无符号的int64最大值应当是18446744073709551615,换成字节的话,差不多是2048的PB,这下应当足够大了。应当不会有一个文件大小能够变态到这类田地。

    PS:已将这个bug提交到GDAL开辟组,不出所料的话应当下个版本会修复,GDAL开辟组修复问题还是非常及时的。

文章结束给大家分享下程序员的一些笑话语录: 爱情观

  爱情就是死循环,一旦执行就陷进去了。
  爱上一个人,就是内存泄露--你永远释放不了。
  真正爱上一个人的时候,那就是常量限定,永远不会改变。
  女朋友就是私有变量,只有我这个类才能调用。
  情人就是指针用的时候一定要注意,要不然就带来巨大的灾难。

转载地址:http://sroum.baihongyu.com/

你可能感兴趣的文章
Cnetos 6 / Centos 7 修改主机名
查看>>
UIWebView
查看>>
UIViewController函数调用顺序
查看>>
第三方框架的使用
查看>>
配置Eclipse支持MacBook Pro Retina屏幕的办法(解决Retina屏幕下eclipse字体变虚的问题)...
查看>>
python导包路径的修改
查看>>
C语言第十一次作业--函数嵌套调用
查看>>
hdu 1728 逃离迷宫 *
查看>>
将Word文档转化为HTML格式的文档
查看>>
WCF
查看>>
IDE安装Lombok插件提高开发效率
查看>>
转://使用showplan.sql分析sql Performance
查看>>
第七课:增量分析
查看>>
【总结整理】JQuery基础学习---动画
查看>>
A. Round House_数学问题
查看>>
LeetCode OJ:Remove Nth Node From End of List(倒序移除List中的元素)
查看>>
0920编译原理词法分析
查看>>
浅谈数位DP的dfs写法
查看>>
Linux下的bash对拍
查看>>
C++ STL标准入门
查看>>