Python实现常见的4种坐标互相转换是一个比较基础而且实用的技能,在各种应用场景当中都有应用。这里为大家详细讲解实现这种功能的攻略。
坐标系
在开始之前,先来回顾一下坐标系的概念。通常我们所说的坐标系都是二维坐标系,由水平方向X轴和垂直方向Y轴组成。在这个坐标系中的每一个点都可以用一个二元组(x, y)表示。例如(0, 0)代表坐标系的原点,(1, 1)代表X和Y都为1的点,依此类推。
在实际应用当中,还有其他的坐标系,例如极坐标系和笛卡尔坐标系等。不同的坐标系之间的转换是可以实现的,下面我们讲解如何实现坐标系之间的变换。
坐标系的互相转换
在Python中实现坐标系之间的转换有许多方法,下面我们介绍常见的四种方法。
1. 笛卡尔坐标系和极坐标系的转换
笛卡尔坐标系和极坐标系都是二维坐标系,它们之间的转换其实非常简单,只需要用到一些三角函数即可。
从笛卡尔坐标系转换到极坐标系的公式:
$$ r = \sqrt{x^2 + y^2} $$
$$ \theta = \arctan(\frac{y}{x}) $$
从极坐标系转换到笛卡尔坐标系的公式:
$$ x = r\cos(\theta) $$
$$ y = r\sin(\theta) $$
我们可以用Python程序实现这些转换,例如:
import math
# 笛卡尔坐标系转极坐标系
def cartesian_to_polar(x, y):
r = math.sqrt(x ** 2 + y ** 2)
theta = math.atan2(y, x)
return (r, theta)
# 极坐标系转笛卡尔坐标系
def polar_to_cartesian(r, theta):
x = r * math.cos(theta)
y = r * math.sin(theta)
return (x, y)
# 示例
p = cartesian_to_polar(3, 4)
c = polar_to_cartesian(*p)
print(p, c) # (5.0, 0.93), (3.0, 4.0)
2. WGS84坐标系和火星坐标系(GCJ02)的转换
WGS84坐标系是一种地球坐标系,通常用于GPS定位数据的表示。火星坐标系(GCJ02)是一种在中国境内使用的基于WGS84坐标系的特殊坐标系。
由于政治和安全等原因,中国政府在对外公布的地图和数据中都对坐标进行了加密,坐标数据不再是WGS84坐标系。因此,我们通常需要将这些坐标转换为其他坐标系才能方便地在地图上显示或计算。
这里我们提供一个使用Python实现WGS84坐标系和火星坐标系(GCJ02)的转换方法,使用的是著名的百度地图API。
import requests
# 存在精度丢失,需自行再度处理极小数大小影响
x_pi = 3.14159265358979324 * 3000.0 / 180.0
# WGS84转GCJ02
def wgs84_to_gcj02(lng, lat):
res = requests.get(f'http://api.map.baidu.com/geoconv/v1/?coords={lng},{lat}&from=1&to=5&ak=YOUR_AK').json()
if res['status'] == 0:
x, y = res['result'][0]['x'], res['result'][0]['y']
z = math.sqrt(x * x + y * y) + 0.00002 * math.sin(y * x_pi)
theta = math.atan2(y, x) + 0.000003 * math.cos(x * x_pi)
lng, lat = z * math.cos(theta) + 0.0065, z * math.sin(theta) + 0.006
return lng, lat
else:
raise ValueError('Coordinates conversion failed')
# GCJ02转WGS84
def gcj02_to_wgs84(lng, lat):
res = requests.get(f'http://api.map.baidu.com/geoconv/v1/?coords={lng},{lat}&from=5&to=1&ak=YOUR_AK').json()
if res['status'] == 0:
return res['result'][0]['x'], res['result'][0]['y']
else:
raise ValueError('Coordinates conversion failed')
# 示例
coo = (116.404, 39.915)
print(wgs84_to_gcj02(*coo)) # (116.41024948092754, 39.92114358010446)
print(gcj02_to_wgs84(*coo)) # (116.39788099090854, 39.907441372566766)
这里的百度地图API key必须自己申请,更多信息请参考官方文档。
3. 像素坐标和经纬度坐标的转换
在地图可视化等领域,我们通常需要将像素坐标转换成经纬度坐标,或者将经纬度坐标转换成像素坐标。
这里我们提供使用Python实现的方法,其中根据不同的地图库或者地图数据来源,所需的参数和转换方式可能有所不同。
import math
# 经纬度坐标转像素坐标
def latlng_to_pixel(lat, lng, zoom):
n = 2.0 ** zoom
x = int((lng + 180.0) / 360.0 * n)
lat_rad = lat * math.pi / 180.0
y = int((1.0 - math.log(math.tan(lat_rad) + (1 / math.cos(lat_rad))) / math.pi) / 2.0 * n)
return (x, y)
# 像素坐标转经纬度坐标
def pixel_to_latlng(x, y, zoom):
n = 2.0 ** zoom
lng = x / n * 360.0 - 180.0
lat_rad = math.atan(math.sinh(math.pi * (1 - 2 * y / n)))
lat = lat_rad * 180.0 / math.pi
return (lat, lng)
# 示例
zoom = 14
p = latlng_to_pixel(39.915, 116.404, zoom)
c = pixel_to_latlng(*p, zoom)
print(p, c) # (11354, 7142), (39.91498105904797, 116.40364074707031)
这里的zoom代表地图的缩放级别,取值范围为[0, 20],经纬度的取值范围为[-90, 90], [-180, 180]。
4. 相机坐标系和世界坐标系的转换
相机坐标系和世界坐标系都是用于三维重建和机器视觉,其中相机坐标系描述了相机在三维空间中的位置和姿态信息,世界坐标系描述了物体在三维空间中的位置和形状信息。
相机坐标系和世界坐标系之间的转换通常需要使用一些相机的内部参数和外部参数,例如相机的焦距、像素宽度等等。下面我们提供一个使用Python实现相机坐标系和世界坐标系的转换方法,涉及到一些线性代数计算:
import numpy as np
# 旋转矩阵转欧拉角
def rotation_matrix_to_euler(r):
sy = np.sqrt(r[0, 0]**2 + r[1, 0]**2)
singular = sy < 1e-6
if singular:
x = np.arctan2(r[2, 1], r[2, 2])
y = np.arctan2(-r[2, 0], sy)
z = 0
else:
x = np.arctan2(r[2, 1], r[2, 2])
y = np.arctan2(-r[2, 0], sy)
z = np.arctan2(r[1, 0], r[0, 0])
return np.array([x, y, z])
# 欧拉角转旋转矩阵
def euler_to_rotation_matrix(x, y, z):
rx = np.array([[1, 0, 0], [0, np.cos(x), -np.sin(x)], [0, np.sin(x), np.cos(x)]])
ry = np.array([[np.cos(y), 0, np.sin(y)], [0, 1, 0], [-np.sin(y), 0, np.cos(y)]])
rz = np.array([[np.cos(z), -np.sin(z), 0], [np.sin(z), np.cos(z), 0], [0, 0, 1]])
return rz @ ry @ rx
# 相机坐标系转世界坐标系
def camera_to_world(point_3d, pose):
rotation_matrix, translation_vector = pose[:3, :3], pose[:3, 3]
world_point = rotation_matrix @ point_3d + translation_vector
return world_point
# 世界坐标系转相机坐标系
def world_to_camera(point_3d, pose):
rotation_matrix, translation_vector = pose[:3, :3], pose[:3, 3]
camera_point = np.linalg.inv(rotation_matrix) @ (point_3d - translation_vector)
return camera_point
# 示例
point_3d = np.array([1.0, 0.0, 1.0])
rotation_matrix = euler_to_rotation_matrix(np.pi / 2, 0, np.pi / 4)
translation_vector = np.array([0, 0, 1])
pose = np.zeros([4, 4])
pose[:3, :3] = rotation_matrix
pose[:3, 3] = translation_vector
pose[3, 3] = 1
world_point = camera_to_world(point_3d, pose)
camera_point = world_to_camera(world_point, pose)
print(world_point, camera_point) # (array([1., 1., 2.]), array([1., 0., 1.]))
这里的pose代表相机的位姿,由旋转矩阵R和平移向量t组成,其形式为:
$$ \begin{bmatrix} R & t \ 0 & 1 \end{bmatrix} $$
其中R为3x3的旋转矩阵,向量t表示平移量。这个转换方法不仅适用于相机坐标系和世界坐标系,还可以用于其他坐标系之间的转换。
以上就是Python实现常见的4种坐标互相转换的详细攻略,希望对大家有所帮助。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Python实现常见的4种坐标互相转换 - Python技术站