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

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. 图例说明
  • 0
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
课程解决的问题: 作为游戏行业或者图形学从业者,你是否面临以下问题: 到底openGL底层如何实现的? 到底矩阵操作变换是怎么做到的? 到底光栅化的算法以及原理是什么? 到底如何才能从3D世界投射到2D屏幕呢? 图形学有这么多的矩阵操作,到底如何推导如何应用呢? 学完这门课程,你应该就可以从底层了解一个初级的openGL图形接口如何实现,图形学最底层的封装到底面临哪些挑战;跟随我们一行一行写完代码,你就会得到一个迷你版本的openGL图形库,你可以深度体会图形从模型变换,观察矩阵变换,投影矩阵变换一直到光栅化纹理操作的全套模拟流程。 课程介绍: 本课程将带领学员不使用任何图形库,实现从0到1的图形学接口封装以及算法讲解,并且带领大家手敲代码,一行一行进行实现。 涵盖了(环境搭建,绘制,Bresenham算法绘制完美直线,三角形拆分绘制算法,颜色插值算法,图片操作,图片二次插值放缩算法,纹理系统接口搭建及封装,矩阵操作理论以及实践,openGL类似接口封装,3D世界的图形学理论及接口封装等) 最终将带领大家通过C++实现一个3D世界的图形接口,方便所有人入门图形学,进行接下来的openGL接口以及GPU编程的学习   本课程为系列课程的第一步入门,且带领所有人进行实现,更加实用,可以让大家打牢图形学的基础知识及编程技能

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值