【问题标题】:Python - Downsampling of a list of points, with given coordinates and distance between two adjacent points in the listPython - 点列表的下采样,具有列表中两个相邻点之间的给定坐标和距离
【发布时间】:2011-11-22 13:16:40
【问题描述】:

我真的希望有人可以帮助我!我试图让这个脚本按我的意愿运行,但我似乎无法掌握它。

要处理的数据文件是从 GPS 输入的,如下所示:

Line 20081002-1119.nmea
$GPGGA,094406.00,5849.40174,N,01738.15828,E,2,08,00.9,00003.26,M,0024.93,M,005,0734*62
$GPGGA,094407.00,5849.40177,N,01738.15827,E,2,08,00.9,00003.22,M,0024.93,M,005,0734*6B
$GPGGA,094408.00,5849.40174,N,01738.15826,E,2,08,00.9,00003.00,M,0024.93,M,006,0734*65
$GPGGA,094409.00,5849.40171,N,01738.15831,E,2,08,00.9,00003.24,M,0024.93,M,005,0734*62
$GPGGA,094410.00,5849.40176,N,01738.15833,E,2,08,00.9,00003.29,M,0024.93,M,006,0734*61
$GPGGA,094411.00,5849.40172,N,01738.15831,E,2,08,00.9,00003.31,M,0024.93,M,004,0734*6D
$GPGGA,094412.00,5849.40172,N,01738.15830,E,2,08,00.9,00003.15,M,0024.93,M,005,0734*68
$GPGGA,094413.00,5849.40175,N,01738.15834,E,2,08,00.9,00003.18,M,0024.93,M,005,0734*67
$GPGGA,094414.00,5849.40173,N,01738.15835,E,2,08,00.9,00003.16,M,0024.93,M,006,0734*6A
EOL

我的输出文件应该是这样的(现在加上距离只是为了显示我想要的):

Line 20081002-1119.nmea
58.853952   17.643113   102.15 
58.853946   17.643243   101.63 
58.853939   17.643372   105.93 
58.853933   17.643503   104.01 
58.853927   17.643633   104.25 
...
EOL

这些列是:经度、纬度、到上面点的距离。

如何将其下采样到两点之间的给定间隔(在我的情况下为 100 米)?

到目前为止我管理的脚本:`

indata=open('C:/nav.nmea', 'r')
outdata=open('C:/nav_out.txt', 'w')

from math import *

coords_list=[]
coords=[]

def distance(coords_list):
    for (longi2,lati2) in coords_list:
        for (longi1,lati1) in coords_list:
            a = sin(lati1) * sin(lati2)+cos(longi1-longi2)*cos(lati1) * cos(lati2)
            c= 2* asin(sqrt(a))

            s= (6367* c)/100000 # For results in meters

        if s<100:
            # Here I want to discard current line if not s<100 and jump to the next line
        else:
            "Return the valid lines"
    return s


for line in indata:

    if line.startswith('$GPGGA'):

        data=line.split(",")
        # Import only coordinates from input file

        LON=float(data[2])/100

        LAT=float(data[4])/100

        # Convert coordinates from DDMM.MMMM to DD.DDDDDD

        lon=((LON-int(LON))/60)*100+int(LON)

        lat=((LAT-int(LAT))/60)*100+int(LAT)

        coords_list.append((lon,lat))

        outdata.writelines("%0.6f\t" %lon)

        outdata.writelines("%0.6f\t" %lat)
        outdata.writelines("%s \n" %distance(coords_list))


    elif line.startswith('EOL'):

        outdata.writelines("EOL")

    elif line.startswith('Line'):

        LineID=line

        outdata.writelines('\n%s' %LineID)


indata.close()     

outdata.close() 

`

【问题讨论】:

  • 我的并不是真正的答案,更多的是贡献。如果您有兴趣,可以找到here 一个命令实用程序,我编写它来处理我的航行机器人的日志。它可以完成您所要求的更多[但您所要求的]...但也许您可能会发现一些对您有用的东西。请记住,唯一真正有效的部分是命令行实用程序logman.py 和连接的库。其余的是前一次迭代的残留代码,它可能已损坏。

标签: python io gps coordinates downsampling


【解决方案1】:

对于曲线中的点减少,您可能想要使用Ramer–Douglas–Peucker algorithm。这保持了曲线的整体形状,但去除了细节,去除的量可以通过一个参数来控制。

请注意,链接的维基百科页面上的代码是伪代码,而不是 python。


我找到了一个python implementation of the DP line-simplication algorthim,我没有测试过,不能保证它的正确性。

【讨论】:

  • 好的!似乎这就是我正在寻找的东西。但是如何在我的脚本中使用它?我对整个编程世界都很陌生,所以我可以说我完全迷失了。
  • 我找到了一个免费提供的实现,我会在我的答案中链接到它。
  • 我也发现了一个,但是没有更简单的方法可以解决这个问题吗?这个脚本是数据数字处理入门课程的一部分,我无法想象我们应该做的事情和你的链接一样先进。我最初的计划是在行上使用迭代,例如“如果距离
【解决方案2】:

这是一种相当简单的数据下采样方法:coord1 用于存储先前的坐标。每次通过循环,都会计算coord1 和新坐标coord2 之间的距离。当距离

import math
import itertools

def distance(coord1,coord2):
    longi1,lati1=coord1
    longi2,lati2=coord2
    a = (math.sin(lati1)*math.sin(lati2)
         +math.cos(longi1-longi2)*math.cos(lati1)*math.cos(lati2))
    c = 2*math.asin(math.sqrt(a))
    s = (6367*c)/100000 # For results in meters
    return s

with open('nav.nmea', 'r') as indata:
    with open('nav_out.txt', 'w') as outdata:
        coords=[]
        coord1=None
        for line in indata:
            if line.startswith('$GPGGA'):
                data=line.split(",")
                # Import only coordinates from input file
                LON=float(data[2])/100
                LAT=float(data[4])/100
                # Convert coordinates from DDMM.MMMM to DD.DDDDDD
                lon=((LON-int(LON))/60)*100+int(LON)
                lat=((LAT-int(LAT))/60)*100+int(LAT)
                coords.append((lon,lat))
                if coord1 is None:
                    # The first time through the loop `coord1` is None
                    outdata.write('%0.6f\t%0.6f\t%s \n'%(lon,lat,0))
                    coord1=(lon,lat)
                else:
                    coord2=(lon,lat)
                    dist=distance(coord1,coord2)
                    if dist<100:
                        # go back to the beginning of the loop
                        continue
                    outdata.write('%0.6f\t%0.6f\t%s \n'%(lon,lat,dist))
                    coord1=coord2
            elif line.startswith('EOL'):
                outdata.writelines("EOL")
            elif line.startswith('Line'):
                LineID=line
                outdata.writelines('\n%s' %LineID)

【讨论】:

  • 这绝对是我要找的!!是否还需要添加一些内容来保留每个不同 nmea 行中的最后一行?另外,我没有让它正常工作......这是我在 outdata 中得到的结果:` Line 20081002-1119.nmea 58.853952 17.643113 0 EOL Line 20081002-1119.nmea EOL Line 20081002-1119.nmea EOL Line 20081003-0710.nmea EOL Line 20081003-0834.nmea EOL`
  • 检查距离公式。当我在您发布的数据上运行我的脚本时,距离都在 0.2 左右。然而你说你想过滤掉所有小于 100 的距离。问题很可能出在 distance 函数中。你的公式正确吗?如果您需要帮助,请发布输入数据的示例所需的输出。
  • 现在更仔细地查看distance,我发现math.asin 的范围为[-pi/2, +pi/2]。所以c 的范围是[-pi,+pi]。所以s 的范围(大致)超过[-0.1,0.1]。因此distance 的返回值将始终远小于 100。公式似乎有问题。
  • 这就是我的作业所说的:你从主管那里得到的导航点将非常靠近,因此必须将它们过滤到大约 100 m 的步长(所谓的下采样)。所有其他点都应该被丢弃。但是,应该保留每条线的第一个和最后一个点。这意味着需要丢弃 1000 行中的大约 999 行。 indata 文件中的总行数约为 19k。而且距离公式应该是正确的,我手动试了一下,效果很好。
猜你喜欢
  • 1970-01-01
  • 2019-07-29
  • 2020-02-12
  • 2014-02-19
  • 1970-01-01
  • 1970-01-01
  • 2021-07-09
  • 1970-01-01
  • 2023-01-26
相关资源
最近更新 更多