【问题标题】:Is there any algorithm suitable for compression of GPS waypoints?是否有适合压缩 GPS 航点的算法?
【发布时间】:2020-11-25 01:25:29
【问题描述】:

我正在寻找任何用于有损压缩 GPS 轨道航点的算法,其坐标为 EPSG:4326 CRS(通常的度数,如 (75.223423,-10.123123))

简而言之,在消除元信息并使用 Ramer-Douglas-Peucker 算法进行简化后,我有一个有序的航点坐标序列,每个航点占用 16 个字节(2 x 8 字节 @987654322 @)。

利用航点是有序的,航点之间的距离在大多数情况下小于 0.01°(~1 公里在赤道),我做了一个假设,可能有某种此类序列的有损压缩算法。

你能帮我找出来吗?

UPD:根据真实轨迹(约 800 条分析),点之间的距离(度数)如下所示。 P95 是所有距离的第 95 个百分位。

LON    
    avg: 0,000334560520818109
    p95: 0,001239999999999240 # ~138 meters
    max: 0,307273900000000000
LAT    
    avg: 0,000221987685948093
    p95: 0,000839999999996621
    max: 0,309625799999999000

【问题讨论】:

  • 在您的数据集上尝试第一个常见的通用无损压缩工具,以评估可能的潜在压缩系数。
  • @chux-ReinstateMonica 我认为通常的压缩方法针对重复序列和词汇使用进行了优化。在我的例子中,不存在二进制形式的词汇或重复序列,因此它提供的压缩率太小而资源使用率太高(cpu 和 ram)。
  • “在我的情况下,不存在二进制形式的词汇或重复序列”与“在大多数情况下航路点之间的距离小于 0.01°”相矛盾——>您的数据存在模式。 “资源使用率过高”不是帖子的一部分。如果您有限制,最好在帖子中说明。 "给出的压缩率太小" --> 那个压缩率是多少?
  • 仅在Optimal GZip 和 Deflate 时只有 35%。比Optimal Brotli 更好(平均 21.5%)。测量 5000 个真实 GPX 文件。我认为它仍然很大并且没有损失。我将尝试尝试将浮点放大到整数(有损)并使用默认算法对其进行压缩。 *** Optimal 是.net 的条款。
  • 我认为 10m 的精度非常适合我的需求。

标签: floating-point gps compression coordinates gpx


【解决方案1】:

对于您期望的有效数字数量以及可能值的有限范围,您不需要八字节浮点格式。我首先将数据转换为可以表示值的准确性和范围的适当长度的整数序列。看起来两个四字节整数就足够了。那里有二分之一的压缩。

然后将每个点替换为该点与前一个点的差异,第一个点除外。现在整数应该更小,允许任何通用无损压缩器进一步减少它。如果差异仅在 0.1° 左右,则可以得到另一个因子 2。

这是一个简单的例子,这个点的预测是最后一个点。如果您的点序列代表一条路径,您可以在模拟速度的地方做一些更复杂的事情。在这种情况下,您使用最后一个建模速度传播最后一个点,然后从当前点中减去它。

修改

我发现 WGS84 参考框架本身精确到只有 2-5 米。使用三字节整数,您可以在赤道处获得 2.4 米的分辨率。在差分和压缩之前,这提供了 62.5% 的减少。它还为您提供了一个免费的纬度位,因为它具有经度范围的一半。该位可用于标记这是绝对坐标还是从最后一个坐标预测的。

【讨论】:

  • 嗯,这个想法很有用,但我害怕重新发明轮子。我希望这种压缩已经被发明和测试了。比如,基于两个delta,或者基于两个点之间的角度和距离,以及keyframes对于非标准情况,采用实际的点之间的delta等。
  • 我不知道现有的实现。 lat-lat 和 long-long 的转换和减法非常简单,压缩部分可以依赖现成的软件。
  • 小心穿越180E->180W。路点可能相距几米,但经度约为 360 度!
  • @dmuir 除非路径正好挂在那条线上,来回穿过它,否则交叉对压缩的影响很小。
【解决方案2】:

如果您需要自己编写代码,这里有一个简单的“delta”编码方案的技巧,可以避免不必要地丢失准确性。

这个想法是压缩器不应该在当前数据点和最后一个数据点之间计算增量,而是在当前数据点和解压缩器为最后一个计算的数据点之间计算增量。这意味着量化误差不会累加。

作为一个简单的示例,您可能想仔细阅读/试验这里的 c 代码,该代码将双精度数压缩为(开始双精度数)和一系列浮点数:

typedef struct
{   double  start;
    int n;
    float*  delta;
} compT;

compT   compress( int n, const double* data)
{
compT   c = (compT){ data[0], n-1, malloc( (n-1)*sizeof *c.delta)};
double  r = c.start;
    for( int i=1; i<n; ++i)
    {
    float   d = (float)(data[i]-r);
        c.delta[i-1] = d;
        r += d;
    }
    return c;
}

static  double* uncompress( compT c)
{
double* d = malloc( (c.n+1)*sizeof *d);
double  r = c.start;
    d[0] = r;
    for( int i=1; i<=c.n; ++i)
    {   r += c.delta[i-1];
        d[i] = r;
    }
    return d;
}
compT   bad_compress( int n, const double* data)
{
compT   c = (compT){ data[0], n-1, malloc( (n-1)*sizeof *c.delta)};
    for( int i=1; i<n; ++i)
    {
    float   d = (float)(data[i]-data[i-1]);
        c.delta[i-1] = d;
    }
    return c;
}

当使用浮点数时,量化误差的累积实际上只在长(数百万)数据序列上才明显。

但是,当希望压缩更多时,效果会更明显。下面的代码对增量使用 int_16t。我在数据值保证在 1Km 左右的情况下使用了这个,所以我使用了 16 的比例(在下面的代码中),所以可以处理 2km 的差异。

typedef struct
{   float   scale;
    double  start;
    int n;
    int16_t*    delta;
} compiT;

compiT  compressi( int n, const double* data, float scale)
{
compiT  c = (compiT){ scale, data[0], n-1, malloc( (n-1)*sizeof *c.delta)};
double  r = c.start;
    for( int i=1; i<n; ++i)
    {
    int16_t d = (int16_t)round(c.scale*(data[i]-r));
        c.delta[i-1] = d;
        r += ((double)d)/c.scale;
    }
    return c;
}

compiT  bad_compressi( int n, const double* data, float scale)
{
compiT  c = (compiT){ scale, data[0], n-1, malloc( (n-1)*sizeof *c.delta)};
    for( int i=1; i<n; ++i)
    {
    int16_t d = (int16_t)round(c.scale*(data[i]-data[i-1]));
        c.delta[i-1] = d;
    }
    return c;
}

static  double* uncompressi( compiT c)
{
double* d = malloc( (c.n+1)*sizeof *d);
double  r = c.start;
    d[0] = r;
    for( int i=1; i<=c.n; ++i)
    {
    double  delta = ((double)c.delta[i-1])/c.scale;
        r += delta;
        d[i] = r;
    }
    return d;
}

在任意长度的运行中,最大误差(即原始数据和解压缩的压缩数据之间的差异)应该是大约 3cm,而使用 bad_compressor 在运行 1000 次时误差约为 0.5m , 2.5m 运行 10000 次

当然,如果您无法保证差异的有限性,则需要合并某种重新启动。

【讨论】:

  • "这意味着量化误差不会累加。" --> 好主意。
  • 在我的具体情况下,我通过按顺序添加两种类型的帧 - 关键帧增量帧找到了它。如果计算点和实际点之间的距离离原始点太远,则写入关键帧,否则写入有损增量帧。所以总量化误差不能超过我设置为参数的最大误差。
【解决方案3】:

我找到了一个现有的解决方案:TinyWKB or TWKB or Tiny Well-known Binary 数据格式适合我的需求。

  • 它存储几何图元(它有LineString 支持我当前的需求)。
  • 它使用增量存储数据。
  • 它支持浮点精度(+2 到 -2)。
  • 它支持几何的 ID 数据。
  • 可以使用NetTopologySuite的.Net模块编写。

TinyWKB 是从WKT -&gt; WKB -&gt; TWKB 开发的,用于存储几何图元(Points、LineStrings、Polygons、MultiPoints、MultiLineStrings、MultiPolygons、GeometryCollections)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-02-08
    • 1970-01-01
    • 1970-01-01
    • 2018-10-17
    • 1970-01-01
    • 2011-04-25
    • 1970-01-01
    • 2022-12-06
    相关资源
    最近更新 更多