欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

3d点投影到2d屏幕,矩阵计算

程序员文章站 2022-07-12 09:52:21
...

3d点投影到2d屏幕,矩阵计算

背景

最近在优化VIBE输出的3D关节点抖动问题。需要将3D点投影到2D屏幕上。3D点通过相机投影到2D屏幕上,通过一系列矩阵相乘可以求得。但是具体操作实现说明太少,本文用来记录投影流程的实现。附python实现代码

算法

3d 转 2d 的流水线如下:

世界坐标系->相机坐标系->投影矩阵->像素映射->生成图片

  1. 世界坐标系和相机坐标系转换可以通过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
    
  2. 投影矩阵,可以参考pyrender.camera.py中的透视投影和正交投影矩阵。也可以根据自己的需求定制
  3. 通过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

待更新

  1. 图例说明