You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

已知相机内外参,3D点投影2D图像出错及坐标系疑问

问题

已知一张图像的相机内参(K)和外参(旋转矩阵R、平移向量t),需要将3D点(X,Y,Z)投影到图像上得到像素坐标(u,v),已知该点的正确像素坐标为(5126, 1482)。

按照常规投影步骤(先转换到相机坐标系,计算x'、y'再推导图像坐标)得到的结果偏差极大:u: [9050.37868283],v: [1490.14136818]。

相关代码如下:

import numpy as np

np.set_printoptions(suppress=True)

class NadirImage():

    def __init__(self):
        self.name = 'Leica CityMapper-2_96616_S150051-146040_MFC150_Backward'
        self.width = 14192
        self.height = 10640

        # ----------------------- Camera matrix --------------------------------------
        self.pixel_size_mm = 0.00376
        self.focal_length_mm = 112

        self.focal_length = self.focal_length_mm / self.pixel_size_mm
        self.xo = 7095.5
        self.yo = 5319.5
        self.Camera_matrix = np.array([[self.focal_length,                0., self.xo ],
                                       [               0., self.focal_length, self.yo ],
                                       [               0.,                0.,      1. ]],
                                      dtype=np.float64)
        # ---------------------------------------------------------------------------
        # ----------------------- Rotation Matrix -----------------------------------
        self.omega_deg = 0.09444
        self.phi_deg = -0.02652
        self.kappa_deg = -92.21505
        self.Rotation_matrix = self.rotation_matrix()
        # ---------------------------------------------------------------------------
        # ----------------------- Translation Vector --------------------------------
        self.X =  409971.705
        self.Y = 4201193.819
        self.Z =    1480.099
        self.Translation_vector = np.array([[self.X],
                                            [self.Y],
                                            [self.Z]])
        # ---------------------------------------------------------------------------

    def rotation_matrix(self):
        # Convert degrees to radians
        omega = np.radians(self.omega_deg)
        phi = np.radians(self.phi_deg)
        kappa = np.radians(self.kappa_deg)

        # Rotation matrix around X-axis
        R_x = np.array([[1,               0,               0],
                        [0,   np.cos(omega),   np.sin(omega)],
                        [0,  -np.sin(omega),   np.cos(omega)]])
        
        # Rotation matrix around Y-axis
        R_y = np.array([[  np.cos(phi), 0, -np.sin(phi)],
                        [            0, 1,           0],
                        [  np.sin(phi), 0,  np.cos(phi)]])
        
        # Rotation matrix around Z-axis
        R_z = np.array([[  np.cos(kappa),  np.sin(kappa), 0],
                        [  -np.sin(kappa),   np.cos(kappa), 0],
                        [              0,               0, 1]])
        
        # Combined rotation matrix
        Rotation_matrix = R_z @ R_y @ R_x
        return Rotation_matrix

# Create the NadirImage instance
image = NadirImage()

test_point = np.array([[410163.605],  #uv: 5126.559809474944, 1482.3423009603664
                       [4201284.701], 
                       [20.58]])

R = image.Rotation_matrix
t  = image.Translation_vector

point_on_camera = R @ (test_point - t)
x, y, z, = point_on_camera[0], point_on_camera[1], point_on_camera[2]

#print the point on the camera coordinate system
print(f'Point on the camera coordinate system: {x[0], y[0], z[0]}')

# Calculate x_prime and y_prime
x_prime = x/z
y_prime = y/z   

print('x_prime:', x_prime)
print('y_prime:', y_prime, '\n')

# Calculate image coordinates
u = image.focal_length * x_prime + image.xo
v = image.focal_length * y_prime + image.yo
print('image.focal_length:', image.focal_length)
print('image.xo:', image.xo)
print('image.yo:', image.yo)
print('u:', u)
print('v:', v)

编辑补充:修改以下计算方式后结果正确,但不明白对应的坐标系含义:

x_prime = x/-z
y_prime = y/z   

问题分析与解答

核心问题是这台相机的坐标系轴向约定和常规计算机视觉标准不一致,具体体现在Z轴方向:

  1. 常规计算机视觉的相机坐标系约定

    • 相机光轴指向场景方向,Z轴向外(远离相机、朝向场景),只有Z为正的点才在相机视野内,投影公式为 x' = x/z、y' = y/z,对应像素坐标系u轴向右、v轴向下的存储逻辑。
  2. 你的相机的特殊约定

    • 从修改x' = x/-z能得到正确结果可以推断:这台Leica CityMapper-2的相机坐标系Z轴是向内的(朝向相机自身),场景中的3D点转换到相机坐标系后,Z值为负数。
    • 常规公式用x/z会因为Z为负导致x'符号反转,最终u坐标偏离正确值;x/-z相当于修正符号,让投影后的x'符合像素坐标系的轴向要求。
    • y方向无需修改符号,说明相机坐标系Y轴的约定和常规一致,和像素v轴的映射方向匹配。

这个修改本质是修正了相机Z轴方向与常规投影公式的不匹配,确保投影坐标的符号符合像素坐标系的定义。

内容的提问来源于stack exchange,提问作者mkr

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 10:42:03