当前位置: 首页 > article >正文

P_all: 投影矩阵(Projection Matrix)

P_all 是所有摄像头的投影矩阵(Projection Matrix)的集合。每个摄像头的投影矩阵 Pi 是一个 3×4 的矩阵,用于将世界坐标系中的 3D 点 X=[X,Y,Z,1]T 投影到该摄像头的 2D 图像平面上的点 u=[u,v,1]T。投影关系可以表示为:

u=PiX

其中:

  • u=[u,v,1]T 是 2D 图像平面上的齐次坐标。

  • X=[X,Y,Z,1]T 是世界坐标系中的齐次 3D 坐标。

  • Pi是第 i 个摄像头的投影矩阵。


投影矩阵 Pi​ 的组成

投影矩阵 Pi 由摄像头的内参矩阵 Ki外参矩阵 [Ri∣ti] 组成:

Pi=Ki[Ri∣ti]

其中:


Pall 的含义

P_all 是所有摄像头的投影矩阵的集合。假设有 23 个摄像头,那么 P_all 是一个长度为 23 的列表,每个元素是一个 3×4 的投影矩阵 Pi​,即:

Pall=[P1,P2,…,P23]

其中,每个 Pi​ 对应一个摄像头的投影矩阵。


Pall的作用

在多视角三角化中,P_all 用于将多个摄像头的 2D 观测数据(即关键点的 2D 坐标)与 3D 世界坐标联系起来。具体来说:

  1. 线性三角化
    通过构造超定方程组 AX=0,利用所有摄像头的投影矩阵 PiPi​ 和对应的 2D 点 (ui​,vi​),求解 3D 点 X。

  2. 非线性优化
    在 Bundle Adjustment 中,P_all 用于计算重投影误差,即 3D 点 X 投影到每个摄像头的 2D 平面后,与观测到的 2D 点之间的误差。


示例代码:构造 Pall

假设你已经有了每个摄像头的内参矩阵 Ki​ 和外参矩阵 [Ri∣ti],可以通过以下代码构造 P_all

以Easymocap 需中的Dataset为例从数据集的内参文件和外参文件构建Pall矩阵:multiview dataset (链接可以下载具体的数据集):

import cv2
import numpy as npdef read_opencv_matrix(file_storage, key):"""从 OpenCV 的 YAML 文件中读取矩阵"""node = file_storage.getNode(key)if node.empty():raise ValueError(f"Node '{key}' is empty or does not exist.")mat = node.mat()return matdef read_opencv_string_list(file_storage, key):"""从 OpenCV 的 YAML 文件中读取字符串列表"""node = file_storage.getNode(key)if node.empty():raise ValueError(f"Node '{key}' is empty or does not exist.")# 读取字符串列表string_list = []for i in range(node.size()):string_list.append(node.at(i).string())return string_listdef compute_projection_matrix(K, R, t):"""计算投影矩阵 P = K * [R | t]"""# 将 t 转换为列向量t = t.reshape(-1, 1)# 构造外参矩阵 [R | t]extrinsic = np.hstack((R, t))# 计算投影矩阵 PP = np.dot(K, extrinsic)return Pdef main():# 读取 extri.yml 文件extri_path = 'extri.yml'extri_fs = cv2.FileStorage(extri_path, cv2.FILE_STORAGE_READ)# 读取 intri.yml 文件intri_path = 'intri.yml'intri_fs = cv2.FileStorage(intri_path, cv2.FILE_STORAGE_READ)# 获取相机名称列表names = read_opencv_string_list(extri_fs, "names")# 将字符串数组转换为整数数组names_int = [int(name) for name in names]names = sorted(names_int)print("names: ", names)# 初始化 P_all 列表P_all = []for name in names:try:# 读取内参矩阵 KK_key = f'K_{name}'K = read_opencv_matrix(intri_fs, K_key)# 读取畸变系数 distdist_key = f'dist_{name}'dist = read_opencv_matrix(intri_fs, dist_key)# 读取外参矩阵 R 和 tRot_key = f'Rot_{name}'Rot = read_opencv_matrix(extri_fs, Rot_key)T_key = f'T_{name}'T = read_opencv_matrix(extri_fs, T_key)# 计算投影矩阵 PP = compute_projection_matrix(K, Rot, T)# 将 P 添加到 P_all 列表P_all.append(P)except ValueError as e:print(f"Error processing camera {name}: {e}")continue# 将 P_all 转换为 NumPy 数组P_all = np.array(P_all)print("P_all:",len(P_all))# 保存为 .npy 文件np.save('Pall.npy', P_all)print("投影矩阵 P_all 已保存到 P_all.npy 文件中。")if __name__ == "__main__":main()

利用数据集中的3D keypoints 关键点可以通过Pall矩阵计算得到23个视角下对应的2D关键点坐标:

可以参考如下代码:

import numpy as np
import json
import osdef project_3d_to_2d(P, points_3d):"""将 3D 点投影到 2D 图像平面:param P: 投影矩阵 (3x4):param points_3d: 3D 点坐标 (Nx3):return: 2D 点坐标 (Nx2)"""# 将 3D 点转换为齐次坐标points_3d_homo = np.hstack((points_3d, np.ones((points_3d.shape[0], 1))))# 投影到 2D 平面points_2d_homo = np.dot(P, points_3d_homo.T).T# 将齐次坐标转换为非齐次坐标points_2d = points_2d_homo[:, :2] / points_2d_homo[:, 2:3]return points_2ddef process_keypoints3d_file(file_path, P_all):"""处理单个 JSON 文件,计算 2D 关键点并保存到摄像头目录:param file_path: JSON 文件路径:param P_all: 所有摄像头的投影矩阵 (23x3x4)"""# 读取 JSON 文件with open(file_path, 'r') as f:data = json.load(f)# 提取 3D 关键点坐标keypoints_3d = np.array(data[0]['keypoints3d'])[:, :3]  # 只取前 3 列 (x, y, z)# 获取文件名(如 000000.json -> 000000)file_name = os.path.splitext(os.path.basename(file_path))[0]# 遍历每个摄像头的投影矩阵for i, P in enumerate(P_all):# 将 3D 关键点投影到当前摄像头的 2D 平面keypoints_2d = project_3d_to_2d(P, keypoints_3d)# 创建摄像头编号对应的目录camera_dir = f"keypoints2d/{i + 1}"os.makedirs(camera_dir, exist_ok=True)# 保存当前摄像头的 2D 关键点到对应的 JSON 文件output_path = os.path.join(camera_dir, f"{file_name}.json")with open(output_path, 'w') as f:json.dump({"keypoints2d": keypoints_2d.tolist()}, f, indent=4)print(f"Camera {i + 1} 2D keypoints saved to {output_path}")def main():# 加载 P_all.npy 文件P_all = np.load('Pall.npy')  # 假设 P_all.npy 是投影矩阵的数组# 定义 keypoints3d 目录路径keypoints3d_dir = 'test-dwpose-f-track/keypoints3d'# 遍历 keypoints3d 目录下的所有 JSON 文件for file_name in os.listdir(keypoints3d_dir):if file_name.endswith('.json'):file_path = os.path.join(keypoints3d_dir, file_name)print(f"Processing file: {file_path}")process_keypoints3d_file(file_path, P_all)print("所有文件的 2D 关键点已保存到对应的摄像头目录中。")if __name__ == "__main__":main()

python3 apps/demo/mvmp.py feng/ --out feng/test-dwpose-f --annot filtered/annots-dwpose --cfg config/exp/mvmp1f.yml --undis
python3 apps/demo/auto_track.py feng/test-dwpose-f feng/test-dwpose-f-track --track3

相关文章:

P_all: 投影矩阵(Projection Matrix)

P_all 是所有摄像头的投影矩阵(Projection Matrix)的集合。每个摄像头的投影矩阵 Pi 是一个 34 的矩阵,用于将世界坐标系中的 3D 点 X[X,Y,Z,1]T 投影到该摄像头的 2D 图像平面上的点 u[u,v,1]T。投影关系可以表示为: uPiX 其中…...

机器学习--概览

一、机器学习基础概念 1. 定义 机器学习(Machine Learning, ML):通过算法让计算机从数据中自动学习规律,并利用学习到的模型进行预测或决策,而无需显式编程。 2. 与编程的区别 传统编程机器学习输入:规…...

Python算法详解:贪心算法

贪心算法(Greedy Algorithm)是一种通过选择当前最优解以期望达到全局最优解的算法思想。它在每一步选择时只考虑当前状态下的局部最优,而不关心全局问题的复杂性。这种算法简单高效,适用于某些特定问题,尤其是存在贪心…...

gesp(C++六级)(10)洛谷:P10722:[GESP202406 六级] 二叉树

gesp(C六级)(10)洛谷:P10722:[GESP202406 六级] 二叉树 题目描述 小杨有⼀棵包含 n n n 个节点的二叉树,且根节点的编号为 1 1 1。这棵二叉树任意⼀个节点要么是白色,要么是黑色。之后小杨会对这棵二叉树…...

7.DP算法

DP 在C中,动态规划(Dynamic Programming,DP)是一种通过将复杂问题分解为重叠子问题来高效求解的算法设计范式。以下是DP算法的核心要点和实现方法: 一、动态规划的核心思想 重叠子问题:问题可分解为多个重…...

2025年2月2日(tcp3次握手4次挥手)

TCP(三次握手和四次挥手)是建立和关闭网络连接的标准过程,确保数据在传输过程中可靠无误。下面是详细解释: 1. 三次握手(TCP连接建立过程) 三次握手是为了在客户端和服务器之间建立一个可靠的连接&#x…...

w186格障碍诊断系统spring boot设计与实现

🙊作者简介:多年一线开发工作经验,原创团队,分享技术代码帮助学生学习,独立完成自己的网站项目。 代码可以查看文章末尾⬇️联系方式获取,记得注明来意哦~🌹赠送计算机毕业设计600个选题excel文…...

Android Studio 正式版 10 周年回顾,承载 Androider 的峥嵘十年

Android Studio 1.0 宣发于 2014 年 12 月,而现在时间来到 2025 ,不知不觉间 Android Studio 已经陪伴 Androider 走过十年历程。 Android Studio 10 周年,也代表着了我的职业生涯也超十年,现在回想起来依然觉得「唏嘘」&#xff…...

【PyQt】lambda函数,实现动态传递参数

为什么需要 lambda? 在 PyQt5 中,clicked 信号默认会传递一个布尔值(表示按钮是否被选中)。如果我们希望将按钮的文本内容传递给槽函数,需要通过 lambda 函数显式传递参数。 这样可以实现将按钮内容传递给槽函数&…...

4 Hadoop 面试真题

4 Hadoop 面试真题 1. Apache Hadoop 3.0.02. HDFS 3.x 数据存储新特性-纠删码Hadoop面试真题 1. Apache Hadoop 3.0.0 Apache Hadoop 3.0.0在以前的主要发行版本(hadoop-2.x)上进行了许多重大改进。 最低要求的Java版本从Java 7增加到Java 8 现在&…...

25寒假算法刷题 | Day1 | LeetCode 240. 搜索二维矩阵 II,148. 排序链表

目录 240. 搜索二维矩阵 II题目描述题解 148. 排序链表题目描述题解 240. 搜索二维矩阵 II 点此跳转题目链接 题目描述 编写一个高效的算法来搜索 m x n 矩阵 matrix 中的一个目标值 target 。该矩阵具有以下特性: 每行的元素从左到右升序排列。每列的元素从上到…...

[paddle] 矩阵相关的指标

行列式 det 行列式定义参考 d e t ( A ) ∑ i 1 , i 2 , ⋯ , i n ( − 1 ) σ ( i 1 , ⋯ , i n ) a 1 , i 1 a 2 , i 2 , ⋯ , a n , i n det(A) \sum_{i_1,i_2,\cdots,i_n } (-1)^{\sigma(i_1,\cdots,i_n)} a_{1,i_1}a_{2,i_2},\cdots, a_{n,i_n} det(A)i1​,i2​,⋯,in​…...

何谓共赢?

A和B是人或组织,他们怎样的合作才是共赢呢? 形态1:A提供自己的身份证等个人信息,B用来作贷款等一些事务,A每月得到一笔钱。 A的风险远大于收益,或者B从事的是非法行为; 形态2:A单方面提前终止了与B的合作…...

Kanass基础教程-创建项目

Kanass是一款国产开源免费的项目管理工具,工具简洁易用,开源免费,之前介绍过kanass的一些产品简介及安装配置方法,本文就从如何创建第一个项目来开始kanass上手之旅吧。 1. 创建项目 点击项目->项目添加 按钮进入项目添加页面…...

实验9 JSP访问数据库(二)

实验9 JSP访问数据库(二) 目的: 1、熟悉JDBC的数据库访问模式。 2、掌握预处理语句的使用 实验要求: 1、使用Tomcat作为Web服务器 2、通过JDBC访问数据库,实现增删改查功能的实现 3、要求提交实验报告,将代…...

DeepSeek 核心技术全景解析

DeepSeek 核心技术全景解析:突破性创新背后的设计哲学 DeepSeek的创新不仅仅是对AI基础架构的改进,更是一场范式革命。本文将深入剖析其核心技术,探讨 如何突破 Transformer 计算瓶颈、如何在 MoE(Mixture of Experts&#xff09…...

单片机基础模块学习——DS1302时钟芯片

一、DS1302时钟简介 1.与定时器对比 DS1302时钟也称为RTC时钟(Real Time Clock,实时时钟),说到时钟,可能会想到定时器,下表来简单说明一下两者的区别。 定时器(Timer)实时时钟(RTC)精度高,可达微秒级精度较低,多为秒级计时范围短计时范围长2.开发板所在位置 下面方框里…...

Vue+Echarts 实现青岛自定义样式地图

一、效果 二、代码 <template><div class"chart-box"><chart ref"chartQingdao" style"width: 100%; height: 100%;" :options"options" autoresize></chart></div> </template> <script> …...

FIR滤波器:窗函数法

一、FIR滤波器基础 FIR&#xff08;有限脉冲响应&#xff09;滤波器的三大特点&#xff1a; 绝对稳定&#xff1a;没有反馈回路&#xff0c;不会出现失控振荡 线性相位&#xff1a;信号通过后波形不失真 直观设计&#xff1a;通过窗函数法、频率采样法等方法实现 二、窗函…...

【AI】探索自然语言处理(NLP):从基础到前沿技术及代码实践

Hi &#xff01; 云边有个稻草人-CSDN博客 必须有为成功付出代价的决心&#xff0c;然后想办法付出这个代价。 目录 引言 1. 什么是自然语言处理&#xff08;NLP&#xff09;&#xff1f; 2. NLP的基础技术 2.1 词袋模型&#xff08;Bag-of-Words&#xff0c;BoW&#xff…...

M|哪吒之魔童闹海

rating: 8.5 豆瓣: 8.5 上映时间: “2025” 类型: M动画 导演: 饺子 主演: 国家/地区: 中国大陆 片长/分钟: 144分钟 M&#xff5c;哪吒之魔童闹海 制作精良&#xff0c;除了剧情逻辑有一点瑕疵&#xff0c;各方面都很到位。总体瑕不掩瑜。 上映时间&#xff1a; &…...

DeepSeek 介绍及对外国的影响

DeepSeek 简介 DeepSeek&#xff08;深度求索&#xff09;是一家专注实现 AGI&#xff08;人工通用智能&#xff09;的中国科技公司&#xff0c;2023 年成立&#xff0c;总部位于杭州&#xff0c;在北京设有研发中心。与多数聚焦具体应用&#xff08;如人脸识别、语音助手&…...

力扣动态规划-18【算法学习day.112】

前言 ###我做这类文章一个重要的目的还是记录自己的学习过程&#xff0c;我的解析也不会做的非常详细&#xff0c;只会提供思路和一些关键点&#xff0c;力扣上的大佬们的题解质量是非常非常高滴&#xff01;&#xff01;&#xff01; 习题 1.下降路径最小和 题目链接:931. …...

DBASE DBF数据库文件解析

基于Java实现DBase DBF文件的解析和显示 JDK19编译运行&#xff0c;实现了数据库字段和数据解析显示。 首先解析数据库文件头代码 byte bytes[] Files.readAllBytes(Paths.get(file));BinaryBufferArray bis new BinaryBufferArray(bytes);DBF dbf new DBF();dbf.VersionN…...

【ESP32】ESP-IDF开发 | WiFi开发 | UDP用户数据报协议 + UDP客户端和服务器例程

1. 简介 UDP协议&#xff08;User Datagram Protocol&#xff09;&#xff0c;全称用户数据报协议&#xff0c;它是一种面向非连接的协议&#xff0c;面向非连接指的是在正式通信前不必与对方先建立连接&#xff0c; 不管对方状态就直接发送。至于对方是否可以接收到这些数据内…...

【Qt】常用的容器

Qt提供了多个基于模板的容器类&#xff0c;这些容器类可用于存储指定类型的数据项。例如常用的字符串列表类 QStringList 可用来操作一个 QList<QString>列表。 Qt的容器类比标准模板库(standard template library&#xff0c;STL)中的容器类更轻巧、使用更安全且更易于使…...

tiktok 国际版抖抖♬♬ X-Bogus参数算法逆向分析

加密请求参数得到乱码&#xff0c;最终得到X-Bogus...

【AI】人工智能没那么神秘!

AI是什么&#xff1f; 人工智能&#xff08;Artificial Intelligence&#xff09;&#xff0c;英文缩写为AI。 AI人工智能不是简单的应用程序&#xff0c;而是一类技术&#xff0c;包含机器学习、自然语言处理、计算机视觉等多个领域。AI系统通常由算法、数据、模型和代码组成…...

C#面试常考随笔9:什么是闭包?

最简单的例子&#xff1a; Lambda可以访问Lambda表达式块外部的变量&#xff0c;叫闭包。 定义 闭包是指有权访问另一个函数作用域中的变量的函数。即使该函数已经执行完毕&#xff0c;其作用域内的变量也不会被销毁&#xff0c;而是会被闭包所捕获并保留&#xff0c;供闭包…...

记录 | 基于MaxKB的仿小红书旅游文章AI制作(含图文、视频)

目录 前言一、创建应用Step1 表单Step2 AI对话生成旅游攻略提炼场景Step3 图片生成Step4 视频生成Step5 指定回复二、检验效果三、整体结构视图更新时间前言 参考文章: 自己的感想 想复现文章的内容你需要先学习下我之前的三篇文章中的记录。 1、记录 | Docker的windows版安装…...