• fepk文件格式说明


     

    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定义:

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

     

    共计10自字节

    LevSnap定义:

    struct  LevSnap
    {
            uint64  _lev:8;
            uint64  _offset:56;
    };

     

    共计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语言编写,接口如下所示

    复制代码
    extern  "C"
    {
        /// 
        /// 打开文件函数,可以打开索引也可以打开数据文件
        /// 
        /// 文件名称
        /// 0:失败,否则成功
    FEPKFile    fepkOpenFile(const char* fileName);
        /// 
        /// 读取索引数据函数
        /// 
        /// 索引文件指针
        /// 列号
        /// 行号
        /// 级别
        /// 返回文件头信息
        /// true:false
    bool        fepkReadHeader(FEPKFile file,int x,int y,int z,FEPHHeader* header);
        /// 
        /// 根据文件头信息读取文件大小(瓦片数据大小)
        /// 
        /// 索引文件指针
        /// 文件头信息
        /// 输出文件大小
        /// true:false
    bool        fepkReadDataSize(FEPKFile file,const FEPHHeader* header,uint* pSize);
        /// 
        /// 读取瓦片数据函数
        /// 
        /// 索引文件指针
        /// 文件头信息
        /// 输入缓冲区大小
        /// 缓冲区长度
        ///  -1:失败,0:无数据,>0 数据的真实大小
    int         fepkReadData(FEPKFile file,const FEPHHeader* header,void* pBuf,uint nBufLen);
        /// 
        /// 关闭文件
        /// 
    void        fepkCloseFile(FEPKFile file);
    /// 
        /// 从一个文件夹中读取瓦片的数据头,以及瓦片的大小
        /// 
        /// 目录组,以null结束
        /// 瓦片的编号
        /// 瓦片的编号
        /// 瓦片的编号
        /// 文件头信息
        /// 瓦片大小
        /// 返回打开的文件
    FEPKFile    fepkReadTileHeader(const char** path,int x,int y,int z,FEPHHeader* header,uint* pSize);
        /// 
        /// 从一个文件夹中读取
        /// 
        /// 文件句柄
        /// 文件头信息
        /// 输入/输出,从fepkReadTileHeader读取
        /// 输入,从fepkReadTileHeader读取
        /// 返回读取的长度-1,失败,0,文件内部错误,其他读取的长度
    int         fepkReadTileData(FEPKFile file,const FEPHHeader* header,void* pBuf,uint nBufLen);
    
    }
    复制代码

     

    使用说明:

     

    复制代码
    #include "FEPKReaderApi.h"
    
    #include 
    /// 如果是SDK,非源码方式,则需要因入库
    /// #pragma comment(lib,"FEPKReader.lib")
    int main(int, char**)
    {
        /// 1. 开发文件
        FEPKFile    file = fepkOpenFile("D:\\FE\\data\\fepk\\world.fepk");
        if (file == nullptr)
        {
            return  0;
        }
        FEPHHeader  header;
        uint        nSize = 0;
        /// 2. 读取给定瓦片编号的文件头信息
        /// 如果返回false,说明当前文件中没有给定的瓦片数据
        if (!fepkReadHeader(file, 0, 0, 0, &header))
        {
            return  0;
        }
        /// 3. 读取数据大小
        if (!fepkReadDataSize(file, &header, &nSize))
        {
            return  0;
        }
        /// 申请空间
        char*   pBuf = new char[nSize];
        /// 4. 读取数据
        if (!fepkReadData(file, &header, pBuf, nSize))
        {
            printf("read ok!\n");
        }
        /// 5. 释放内存
        delete[]pBuf;
        /// 6. 关闭文件
        fepkCloseFile(file);
        return  0;
    }
    复制代码

     

     

  • 相关阅读:
    Java网络编程
    基于人工智能与边缘计算Aidlux的工业表面缺陷检测
    Leetcode581. 最短无序连续子数组
    基于微信小程序的美食推荐系统的设计与实现
    Redis 命令汇总
    Java中Arrays类中的数组操作方法详解
    【JavaWeb】Servlet身份验证过滤器
    MATLAB中upsample函数用法
    欧姆龙plc梯形图T_T
    一文详解 requests 库中 json 参数和 data 参数的用法
  • 原文地址:https://www.cnblogs.com/FastEarth/p/17735287.html