在Python中将经纬度坐标转换为本地ENU坐标

时间:2018-11-21 09:21:33

标签: python-2.7 coordinate-systems coordinate-transformation pyproj

(如何)可以将lat长坐标转换为使用Python的本地ENU(东,北,上)坐标? 我似乎在pyproj软件包中找不到正确的功能...

3 个答案:

答案 0 :(得分:2)

您可以使用pymap3d软件包:

安装

pip install pymap3d

简单示例

让我们以this page上显示的示例值为例。

import pymap3d as pm

# The local coordinate origin (Zermatt, Switzerland)
lat0 = 46.017 # deg
lon0 = 7.750  # deg
h0 = 1673     # meters

# The point of interest
lat = 45.976  # deg
lon = 7.658   # deg
h = 4531      # meters

pm.geodetic2enu(lat, lon, h, lat0, lon0, h0)

产生

(-7134.757195979863, -4556.321513844541, 2852.3904239436915)

分别是东,北和上部分。

默认使用的椭圆体是WGS84。可以看到here,所有可用的椭球模型(可以作为geodetic2enu的参数来输入)。这是使用WGS72参考椭球来计算相同ENU坐标的方法:

pm.geodetic2enu(lat, lon, h, lat0, lon0, h0, ell=pm.utils.Ellipsoid('wgs72'))
# (-7134.754845247729, -4556.320150825548, 2852.3904257449926)

答案 1 :(得分:0)

Pymap3d 模块,https://scivision.github.io/pymap3d/提供了坐标转换和大地测量功能,包括ENU <->(long,lat,h)。

这里有一些例子。

import pymap3d
# create an ellipsoid object
ell_clrk66 = pymap3d.Ellipsoid('clrk66')
# print ellipsoid's properties
ell_clrk66.a, ell_clrk66.b, ell_clrk66.f

# output
(6378206.4, 6356583.8, 0.0033900753039287634)

假设我们定义了一个ENU坐标系,其原点位于(lat0,lon0,h0 = 5.0,48.0,10.0)。并将坐标为ENU:(0,0,0)的点(point_1)作为测试点,此point_1将用于进行正向和反向转换。

lat0, lon0, h0 = 5.0, 48.0, 10.0   # origin of ENU, (h is height above ellipsoid)
e1, n1, u1     =  0.0,  0.0,  0.0  # ENU coordinates of test point, `point_1`
# From ENU to geodetic computation
lat1, lon1, h1 = pymap3d.enu2geodetic(e1, n1, u1, \
                                      lat0, lon0, h0, \
                                      ell=ell_clrk66, deg=True)  # use clark66 ellisoid
print(lat1, lon1, h1)
# display: (5.000000000000001, 48.0, 10.000000000097717)

现在,使用获得的(lat1,lon1,h1),我们计算大地到ENU的转换。

e2, n2, u2 = pymap3d.geodetic2enu(lat1, lon1, h1, \
                           lat0, lon0, h0, \
                           ell=ell_clrk66, deg=True)
print(e2, n2, u2)

输出应与(e1,n1,u1)一致。对于这种计算,小的差异是正常的。

在上述计算中,选项ellWGS84椭球作为默认值。

答案 2 :(得分:0)

使用不带pymap3d的pyproj

import numpy as np
import pyproj
import scipy.spatial.transform     

def geodetic2enu(lat, lon, alt, lat_org, lon_org, alt_org):
    transformer = pyproj.Transformer.from_crs(
        {"proj":'latlong', "ellps":'WGS84', "datum":'WGS84'},
        {"proj":'geocent', "ellps":'WGS84', "datum":'WGS84'},
        )
    x, y, z = transformer.transform( lon,lat,  alt,radians=False)
    x_org, y_org, z_org = transformer.transform( lon_org,lat_org,  alt_org,radians=False)
    vec=np.array([[ x-x_org, y-y_org, z-z_org]]).T

    rot1 =  scipy.spatial.transform.Rotation.from_euler('x', -(90-lat_org), degrees=True).as_matrix()#angle*-1 : left handed *-1
    rot3 =  scipy.spatial.transform.Rotation.from_euler('z', -(90+lon_org), degrees=True).as_matrix()#angle*-1 : left handed *-1

    rotMatrix = rot1.dot(rot3)    
   
    enu = rotMatrix.dot(vec).T.ravel()
    return enu.T

def enu2geodetic(x,y,z, lat_org, lon_org, alt_org):
    transformer1 = pyproj.Transformer.from_crs(
        {"proj":'latlong', "ellps":'WGS84', "datum":'WGS84'},
        {"proj":'geocent', "ellps":'WGS84', "datum":'WGS84'},
        )
    transformer2 = pyproj.Transformer.from_crs(
        {"proj":'geocent', "ellps":'WGS84', "datum":'WGS84'},
        {"proj":'latlong', "ellps":'WGS84', "datum":'WGS84'},
        )
    
    x_org, y_org, z_org = transformer1.transform( lon_org,lat_org,  alt_org,radians=False)
    ecef_org=np.array([[x_org,y_org,z_org]]).T
    
    rot1 =  scipy.spatial.transform.Rotation.from_euler('x', -(90-lat_org), degrees=True).as_matrix()#angle*-1 : left handed *-1
    rot3 =  scipy.spatial.transform.Rotation.from_euler('z', -(90+lon_org), degrees=True).as_matrix()#angle*-1 : left handed *-1

    rotMatrix = rot1.dot(rot3)

    ecefDelta = rotMatrix.T.dot( np.array([[x,y,z]]).T )
    ecef = ecefDelta+ecef_org
    lon, lat, alt = transformer2.transform( ecef[0,0],ecef[1,0],ecef[2,0],radians=False)

    return [lat,lon,alt]



if __name__ == '__main__':
    # The local coordinate origin (Zermatt, Switzerland)
    lat_org = 46.017 # deg
    lon_org = 7.750  # deg
    alt_org   = 1673     # meters

    # The point of interest
    lat = 45.976  # deg
    lon = 7.658   # deg
    alt = 4531      # meters

    res1 = geodetic2enu(lat, lon, alt, lat_org, lon_org, alt_org)
    print (res1)
    #[-7134.75719598 -4556.32151385  2852.39042395]
    
    x=res1[0]
    y=res1[1]
    z=res1[2]
    res2 = enu2geodetic(x,y,z, lat_org, lon_org, alt_org)
    print (res2)
    #[45.97600000000164, 7.658000000000001, 4531.0000001890585]

参考1 https://gssc.esa.int/navipedia/index.php/Transformations_between_ECEF_and_ENU_coordinates

参考2 https://www.nsstc.uah.edu/users/phillip.bitzer/python_doc/pyltg/_modules/pyltg/utilities/latlon.html

Ref 3 https://gist.github.com/sbarratt/a72bede917b482826192bf34f9ff5d0b