fepk文件格式说明

打印 上一主题 下一主题

主题 651|帖子 651|积分 1953

 

1  卫星影像金字塔分块原理说明

 
通常我们在工作中使用的卫星影像数据,轻则几百M,重则几百个G甚至上TB级。影像数据太大,是大家经常会遇到的一个问题,尤其是想下载一个省以上数据的时候该问题尤为突出。那么该问题是否有一个比较好的解决方案呢?
以全球为例,我们以19级为例,共有2^18 * 2^17 张瓦片,如此多的瓦片会让磁盘愈来愈慢,同时也无法维护。
当影像范围比较大时,我们可以采用金字塔分块的方式进行管理,系统会自动将大范围分成若干个块,且块与块之间是可以无缝拼接的。
一般情况我们选择全球前10级别作为基础级别,因数据量不大(1G)左右,后续以10级作为基础级别,全球19级别数据被划分为 2^8 * 2^7(512 * 256)个块。每个块中包含了256 * 256 张小瓦片。
1.1  Fepk文件命名规则

 
文件说明(包含索引与数据两个文件,文件必须都配套才可以正常使用):
*.fepk          :文件中存储具体的瓦片数据。
*.fepk.idx    :文件中存储的瓦片的索引信息,当给定一个瓦片编号后,可以根据编号计算出来瓦片存在索引中的信息(大小,以及数据在8-174-138.fepk中的位置)。
名称命名规
以8-174-138.fepk为例:其中8是级别,174是列号,138是行号,文件中存储了8-174-138瓦片裂分出来的所有瓦片数据。
2  .fepk文件格式说明

我们一般不会直接采用瓦片作为管理单元,会把一个块作为管理单元,把数据划分为索引文件与数据文件,如下所示:
数据文件:world.fepk
索引文件:world.fepk.idx
 
2.1  索引文件

1文件说明

文件头

  
字段

  

  
文件头

  
char    szMagic[20]

  
fe.tile.store.data20字节

  
uint    version

  
版本号4字节

  
uint    typeId

  
数据类型

enum PKType

{

 PK_IMAGE ,

 PK_DEM,

 PK_VEC,

PK_QXSY,

PK_USER,

};4字节

  
uint    wgs84

  
是否是wgs84经纬投影4字节

  
uint    flag

  
4字节

  
uint64  timestamp

  
时间戳8字节

  
real2   vStart

  
经纬度最小范围8*2字节

  
real2   vEnd

  
经纬度最大范围 8*2字节

  
LevSnap levOff[24]

  
级别索引,8 * 24 字节

  
char    _reserve[240]

  
保留

  
级别1

  
int2    _start

  
2 * 4字节,瓦片最小行列号

  
int2    _end

  
2 * 4字节,瓦片最大行列号

  
uint64  _offset

  
8字节

  
uint64  _dataSize

  
8字节

  
uint    _lev

  
4字节

  
char    _reserve[216]

  
216字节

  
瓦片数据索引矩阵数据PKTLHeader  

  
N * PKTLHeader

N = (_end.x  - _start.x + 1) * (_end.y - _start.y + 1)

  
 

  
PKTLHeader

  
 

  
级别2

  
 

  
 

  
级别3

  
 

  
 

  
级别…

  
 

  
 

  
 
PKTLHeader定义:
  1. PKTLHeader定义:
  2. struct  PKTLHeader
  3.     {
  4.         /// 有无数据标记,即服务器上是否有该数据 0,无,1,有
  5.         uint64  _data:2;
  6.         /// 在本文件中是否已经存储 0,无,1,有
  7.         uint64  _stored:2;
  8.         /// 状态,
  9.         uint64  _state :6;
  10.         /// 数据地址,使用50个bit最大 2^54
  11.         /// 单个文件最大16 K T
  12.         uint64  _offset : 54;
  13.         /// 如果该值!= 0xFFFF,则有效,否则无效,
  14.         /// 使用该字段的意义在于解决网络读取问题,比如在云盘上
  15.         /// 先读取索引,如果没有数据大小,或者数据大小存储在数据文件中,则需要
  16.         /// 再次访问数据文件,才可以得大小,增加额外的IO,同时兼顾大小,该变量最大可以存储64K
  17.         /// 如果超过了64K,那么一样的需要访问数据文件获取大小
  18.    ushort  _dataSize;
  19. };
复制代码
 
共计10自字节
LevSnap定义:
  1. struct  LevSnap
  2. {
  3.         uint64  _lev:8;
  4.         uint64  _offset:56;
  5. };
复制代码
 
共计8字节
2.2  数据文件文件

文件头

  
字段

  

  
文件头

  
char    szMagic[20]

  
fe.tile.store.data20字节

  
uint    version

  
版本号4字节

  
uint    typeId

  
数据类型

enum PKType

{

 PK_IMAGE ,

 PK_DEM,

 PK_VEC,

PK_QXSY,

PK_USER,

};4字节

  
uint    wgs84

  
是否是wgs84经纬投影4字节

  
uint    flag

  
4字节

  
uint64  timestamp

  
时间戳8字节

  
real2   vStart

  
经纬度最小范围8*2字节

  
real2   vEnd

  
经纬度最大范围 8*2字节

  
LevSnap levOff[24]

  
级别索引,8 * 24 字节

  
char    _reserve[240]

  
保留

  
数据0

  
Int4

  
4*4字节,行号,列号,级别,大小

  
数据

  
 

  
数据1

  
Int4

  
4*4字节,行号,列号,级别,大小

  
数据

  
 

  
数据…

  
Int4

  
4*4字节,行号,列号,级别,大小

  
数据

  
 

  
 
3  如何使用数据

3.1  解压成标注金字塔瓦片

用户可以通过FEPKUNPack.exe解压程序,将数据加压标准的金字塔瓦片,然后即可使用,导出后如下所示。
导出后可以方便的被osgEarth,cesium,argis,fastearth等软件直接加载。
缺点: 导出后,占用磁盘大小比未解压前大50%。
             导出后,维护困难,因为文件很多,拷贝能都受到影响。
 
数据截图

 

3.2  API读取瓦片

使用SDK/API访问数据,为了方便大家使用,避免数据解压,可以使用FEPKReadApi
SDK读取数据,SDK使用C语言编写,接口如下所示
  1. extern  "C"
  2. {
  3.     /// <summary>
  4.     /// 打开文件函数,可以打开索引也可以打开数据文件
  5.     /// </summary>
  6.     /// <param name = "fileName">文件名称</param>
  7.     /// <return>0:失败,否则成功</return>
  8. FEPKFile    fepkOpenFile(const char* fileName);
  9.     /// <summary>
  10.     /// 读取索引数据函数
  11.     /// </summary>
  12.     /// <param name = "file">索引文件指针</param>
  13.     /// <param name = "x">列号</param>
  14.     /// <param name = "y">行号</param>
  15.     /// <param name = "z">级别</param>
  16.     /// <param name = "header">返回文件头信息</param>
  17.     /// <return>true:false</return>
  18. bool        fepkReadHeader(FEPKFile file,int x,int y,int z,FEPHHeader* header);
  19.     /// <summary>
  20.     /// 根据文件头信息读取文件大小(瓦片数据大小)
  21.     /// </summary>
  22.     /// <param name = "file">索引文件指针</param>
  23.     /// <param name = "header">文件头信息</param>
  24.     /// <param name = "pSize">输出文件大小</param>
  25.     /// <return>true:false</return>
  26. bool        fepkReadDataSize(FEPKFile file,const FEPHHeader* header,uint* pSize);
  27.     /// <summary>
  28.     /// 读取瓦片数据函数
  29.     /// </summary>
  30.     /// <param name = "file">索引文件指针</param>
  31.     /// <param name = "header">文件头信息</param>
  32.     /// <param name = "pBuf">输入缓冲区大小</param>
  33.     /// <param name = "nBufLen">缓冲区长度</param>
  34.     /// <return> -1:失败,0:无数据,>0 数据的真实大小</return>
  35. int         fepkReadData(FEPKFile file,const FEPHHeader* header,void* pBuf,uint nBufLen);
  36.     /// <summary>
  37.     /// 关闭文件
  38.     /// </summary>
  39. void        fepkCloseFile(FEPKFile file);
  40. /// <summary>
  41.     /// 从一个文件夹中读取瓦片的数据头,以及瓦片的大小
  42.     /// </summary>
  43.     /// <param name = "path">目录组,以null结束</param>
  44.     /// <param name = "x">瓦片的编号</param>
  45.     /// <param name = "y">瓦片的编号</param>
  46.     /// <param name = "z">瓦片的编号</param>
  47.     /// <param name = "header">文件头信息</param>
  48.     /// <param name = "pSize">瓦片大小</param>
  49.     /// <return>返回打开的文件</return>
  50. FEPKFile    fepkReadTileHeader(const char** path,int x,int y,int z,FEPHHeader* header,uint* pSize);
  51.     /// <summary>
  52.     /// 从一个文件夹中读取
  53.     /// </summary>
  54.     /// <param name = "file">文件句柄</param>
  55.     /// <param name = "header">文件头信息</param>
  56.     /// <param name = "pBuf">输入/输出,从fepkReadTileHeader读取</param>
  57.     /// <param name = "nBufLen">输入,从fepkReadTileHeader读取</param>
  58.     /// <return>返回读取的长度-1,失败,0,文件内部错误,其他读取的长度</return>
  59. int         fepkReadTileData(FEPKFile file,const FEPHHeader* header,void* pBuf,uint nBufLen);
  60. }
复制代码
 
使用说明:
 
  1. #include "FEPKReaderApi.h"
  2. #include <stdio.h>
  3. /// 如果是SDK,非源码方式,则需要因入库
  4. /// #pragma comment(lib,"FEPKReader.lib")
  5. int main(int, char**)
  6. {
  7.     /// 1. 开发文件
  8.     FEPKFile    file = fepkOpenFile("D:\\FE\\data\\fepk\\world.fepk");
  9.     if (file == nullptr)
  10.     {
  11.         return  0;
  12.     }
  13.     FEPHHeader  header;
  14.     uint        nSize = 0;
  15.     /// 2. 读取给定瓦片编号的文件头信息
  16.     /// 如果返回false,说明当前文件中没有给定的瓦片数据
  17.     if (!fepkReadHeader(file, 0, 0, 0, &header))
  18.     {
  19.         return  0;
  20.     }
  21.     /// 3. 读取数据大小
  22.     if (!fepkReadDataSize(file, &header, &nSize))
  23.     {
  24.         return  0;
  25.     }
  26.     /// 申请空间
  27.     char*   pBuf = new char[nSize];
  28.     /// 4. 读取数据
  29.     if (!fepkReadData(file, &header, pBuf, nSize))
  30.     {
  31.         printf("read ok!\n");
  32.     }
  33.     /// 5. 释放内存
  34.     delete[]pBuf;
  35.     /// 6. 关闭文件
  36.     fepkCloseFile(file);
  37.     return  0;
  38. }
复制代码
 
 


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

正序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

石小疯

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表