3d点投影到2d屏幕,矩阵计算
程序员文章站
2022-07-12 09:52:21
...
背景
最近在优化VIBE输出的3D关节点抖动问题。需要将3D点投影到2D屏幕上。3D点通过相机投影到2D屏幕上,通过一系列矩阵相乘可以求得。但是具体操作实现说明太少,本文用来记录投影流程的实现。附python实现代码
算法
3d 转 2d 的流水线如下:
世界坐标系->相机坐标系->投影矩阵->像素映射->生成图片
- 世界坐标系和相机坐标系转换可以通过dcm矩阵计算求出
def dcm(origin: np.ndarray, target: np.ndarray): """ 3 * 3 矩阵 ,{x,y,z}T 将origin坐标系转换到target坐标系的dcm旋转矩阵 Args: origin: target: Returns: """ matrix = np.zeros((3, 3)) for i in range(3): for j in range(3): matrix[i, j] = np.dot(target[i], origin[j]) return matrix.T
- 投影矩阵,可以参考pyrender.camera.py中的透视投影和正交投影矩阵。也可以根据自己的需求定制
- 通过
1,2
两步计算出的2d投影点,会落在(-1,1)范围内。通过像素映射完成3d点到2d点的投影
完整代码
class Camera:
def __init__(self, scale, translation, resolution, znear=0.05, zfar=1000):
self.scale = np.array(scale) # 相机缩放
self.translation = np.array(translation) # 相机位移
self.resolution = np.array(resolution) # 2d 分辨率
self.znear = znear # *面
self.h_s = self.resolution / 2 # h/2 w/2
self.center = self.h_s # 2d投影面中心点
def camera_matrix(self):
"""
相机外参矩阵,世界坐标系转相机坐标系
Returns:
"""
world = np.eye(3)
camera = np.eye(3)
camera[-1, -1] = -1
matrix = np.eye(4)
matrix[:3, :3] = dcm(world, camera)
return matrix
def get_projection_matrix(self) -> np.ndarray:
"""
投影矩阵 业务定制
Returns:
"""
P = np.eye(4)
P[0, 0] = self.scale[0]
P[1, 1] = self.scale[1]
P[0, 3] = self.translation[0] * self.scale[0]
P[1, 3] = -self.translation[1] * self.scale[1]
P[2, 2] = -1
return P
class Render:
def __init__(self, camera: Camera):
self.camera = camera
def p_point(self, point: np.ndarray):
"""
投影点坐标
Args:
point: 点 4D 例如[0.5,0.5,0.5,1] 3d点需要填充1
Returns:
"""
p = self.camera.get_projection_matrix().dot(self.camera.camera_matrix().dot(point))
p = p[:2] / p[-1] * self.camera.h_s * np.array([1, -1]) + self.camera.center
return p
待更新
- 图例说明
上一篇: CSS3~2D到3D的转变