倾斜摄影测量:实现图像坐标到真实世界坐标的转换

在现代摄影测量技术中,将图像坐标转换为真实世界坐标是一项重要任务。这涉及到相机内参矩阵、外参矩阵的计算,以及各种坐标系之间的转换。本文将详细介绍如何使用Python进行这些转换,并逐步讲解相关的知识点和代码实现。

一、相机内参矩阵的计算

1.1 什么是相机内参矩阵?

相机内参矩阵(Intrinsic Matrix)用于描述相机的内部特性,包括焦距、主点位置(光学中心)以及像素尺寸等。这些参数帮助我们将图像坐标与相机坐标系联系起来。

1.2 所需参数

我们需要以下参数来计算相机内参矩阵:

focal_length = 35  # 焦距为35mm
sensor_width = 35.9  # 传感器宽度为35.9mm
sensor_height = 24  # 传感器高度为24mm
resolution_x = 8192  # 图像水平分辨率
resolution_y = 5460  # 图像垂直分辨率
principal_point_x = 4077.9153
principal_point_y = 2759.38247

1.3 计算每个像素的宽度和高度

首先,计算每个像素的宽度和高度:

pixel_width = sensor_width / resolution_x
pixel_height = sensor_height / resolution_y

接下来,定义相机内参矩阵K:

a = np.array([focal_length / pixel_width, 0, principal_point_x, 0])  # 第一行
b = np.array([0, focal_length / pixel_height, principal_point_y, 0])  # 第二行
c = np.array([0, 0, 1, 0])  # 第三行
K = np.array([a, b, c])

print("相机内参矩阵 K:")
print(K)

此矩阵用于将图像平面的坐标转换为相机坐标系下的坐标。

二、相机外参矩阵的计算

2.1 什么是相机外参矩阵?

相机外参矩阵(Extrinsic Matrix)用于描述相机在世界坐标系中的位置和姿态。它包括旋转矩阵和平移向量,帮助我们将相机坐标系下的坐标转换为世界坐标系下的坐标。

2.2 指定相机姿态和地理位置

我们需要指定相机的偏航角、俯仰角和横滚角,以及相机的位置(LBH坐标:经度、纬度、高度):

yaw = -75.8
pitch = -89.9
roll = 0

longitude = 112.772631094
latitude = 37.768497756
height = 96.8736

2.3 地理坐标转换

首先,将地理坐标转换为弧度:

longitude1 = 117  # 中央子午线
a = 6378137.0
f = 1 / 298.257222101
iPI = 0.0174532925199433  # 3.1415926535898/180.0

longitude0 = longitude1 * iPI
longitude1 = longitude * iPI
latitude1 = latitude * iPI

2.4 计算投影坐标

进行地理坐标到投影坐标的转换,并计算xval和yval:

e2 = 2 * f - f**2
ee = e2 * (1.0 - e2)
NN = a / np.sqrt(1.0 - e2 * np.sin(latitude1)**2)
T = np.tan(latitude1)**2
C = ee * np.cos(latitude1)**2
A = (longitude1 - longitude0) * np.cos(latitude1)

M = a * ((1 - e2 / 4 - 3 * e2**2 / 64 - 5 * e2**3 / 256) * latitude1 -
         (3 * e2 / 8 + 3 * e2**2 / 32 + 45 * e2**3 / 1024) * np.sin(2 * latitude1) +
         (15 * e2**2 / 256 + 45 * e2**3 / 1024) * np.sin(4 * latitude1) -
         (35 * e2**3 / 3072) * np.sin(6 * latitude1))

xval = NN * (A + (1 - T + C) * A**3 / 6 + (5 - 18 * T + T**2 + 72 * C - 58 * ee) * A**5 / 120)
yval = M + NN * np.tan(latitude1) * (A**2 / 2 + (5 - T + 9 * C + 4 * C**2) * A**4 / 24 +
                                     (61 - 58 * T + T**2 + 600 * C - 330 * ee) * A**6 / 720)

X0 = 500000
Y0 = 0
xval = xval + X0
yval = yval + Y0

radius = a / np.sqrt(1 - e2 * np.sin(latitude1)**2)
height = height + radius

X = xval
Y = yval
Z = height

print("转换后的坐标:")
print(f"X: {X}, Y: {Y}, Z: {Z}")

2.5 计算旋转矩阵

定义函数以计算旋转矩阵:

def calculate_rotation_matrix(yaw, pitch, roll):
    yaw = yaw * np.pi / 180
    pitch = pitch * np.pi / 180
    roll = roll * np.pi / 180

    Rz = np.array([[np.cos(yaw), -np.sin(yaw), 0],
                   [np.sin(yaw), np.cos(yaw), 0],
                   [0, 0, 1]])

    Ry = np.array([[np.cos(pitch), 0, np.sin(pitch)],
                   [0, 1, 0],
                   [-np.sin(pitch), 0, np.cos(pitch)]])

    Rx = np.array([[1, 0, 0],
                   [0, np.cos(roll), -np.sin(roll)],
                   [0, np.sin(roll), np.cos(roll)]])

    R = np.dot(np.dot(Rz, Ry), Rx)

    return R

R = calculate_rotation_matrix(yaw, pitch, roll)
T = np.array([[X, Y, Z]])
T = np.transpose(T)

camera_extrinsics = np.hstack((R, T))

三、坐标转换

3.1 定义坐标转换函数

定义函数将图像坐标转换为世界坐标:

def inverse_project(u, v, z_c, K, R, T):
    camera_matrix = K
    extrinsics_matrix = np.hstack((R, T))
    extrinsics_matrix = np.vstack((extrinsics_matrix, [0, 0, 0, 1]))

    uv_homogeneous = np.array([u, v, 1])
    M = np.dot(K, extrinsics_matrix)

    coefficient_matrix = M[:, :3]
    column_vector = M[:, 3]

    Right = (uv_homogeneous * z_c) - column_vector
    world_coords = np.linalg.solve(coefficient_matrix, Right)

    return world_coords

u = resolution_x / 2
v = resolution_y / 2
z_c = 96.8736100

world_coords = inverse_project(u, v, z_c, K, R, T)

print("世界坐标:")
print(world_coords)

3.2 解释坐标转换过程

这个函数inverse_project将图像坐标(u, v)转换为世界坐标。首先,它构建了一个扩展的相机矩阵,然后使用线性代数方法解方程以获得世界坐标。

四、CGS2000坐标转换为WGS84坐标

4.1 定义转换函数

定义将CGS2000坐标转换为WGS84坐标的函数:

def CGS2000ToWGS84(x, y):
    output = np.zeros(2)
    longitude1 = 117  # 中央子午线 根据实际进行配置
    a = 6378137.0
    f = 1 / 298.257222101
    iPI = 0.0174532925199433  # 3.1415926535898/180.0

    X0 = 500000
    Y0 = 0
    xval = x - X0
    yval = y - Y0

    longitude0 = longitude1 * iPI
    e2 = 2 * f - f**2

    M = yval
    u = M / (a * (1 - e2 / 4 - 3 * e2**2 / 64 - 5 * e2**3 / 256))

    e1 = (1 - np.sqrt(1 - e2)) / (1 + np.sqrt(1 - e2))
    e1_2 = e1**2 / (1 - e1**2)

    fai_u = u + (3 * e1 / 2 - 27 * e1**3 / 32) * np.sin(2 * u) + (21 * e1**2 / 16 - 55 * e1**4 / 32) * np.sin(4 * u) + \
            (151 * e1**3 / 96) * np.sin(6 * u) + (1097 * e1**4 / 512) * np.sin(8 * u)

    C1 = np.sqrt(1 + e1_2 * np.cos(fai_u)**2)
    T1 = np.tan(fai_u)**2
    R1 = a * (1 - e2) / (C1**3)
    N1 = a / C1

    D = xval / N1
    latitude1 = fai_u - (N1 * np.tan(fai_u) / R1) * \
        (D**2 / 2 - (5 + 3 * T1 + 10 * C1 - 4 * C1**2 - 9 * e1_2) * D**4 / 24 +
         (61 + 90 * T1 + 298 * C1 + 45 * T1**2 - 252 * e1_2 - 3 * C1**2) * D**6 / 720)

    longitude1 = longitude0 + (D - (1 + 2 * T1 + C1) * D**3 / 6 +
                              (5 - 2 * C1 + 28 * T1 - 3 * C1**2 + 8 * e1_2 + 24 * T1**2) * D**5 / 120) / np.cos(fai_u)

    # 转换为度
    output[0] = longitude1 / iPI
    output[1] = latitude1 / iPI

    return output

本文详细介绍了如何计算相机的内参矩阵和外参矩阵,并进行了图像坐标到世界坐标的转换。最后,展示了如何将CGS2000坐标转换为WGS84坐标。这些过程对于从图像获取地理信息、进行三维重建等应用至关重要。通过Python编程实现这些转换,能够使我们更好地理解和应用摄影测量技术。

如果您对YOLOv8模型的改进和深度学习技术感兴趣,欢迎关注我的微信公众号 "AI代码 Insights"。在这里,我会定期分享最新的人工智能技术、深度学习算法和实践经验,与大家共同探讨AI领域的前沿动态。同时需要实现代码的可以通过公众号来找我要。

4o

猜你喜欢

转载自blog.csdn.net/weixin_62921094/article/details/139389658