首页/新闻资讯/正文详情

相机投影核心约定深度解析:Kornia `kornia.geometry.camera` 的坐标系、整数像素中心、depth 双重含义与 `z = 0` 策略

发布时间:2026/9/23 11:30:50 来源:云帆数科 栏目:资讯中心
相机投影核心约定深度解析:Kornia `kornia.geometry.camera` 的坐标系、整数像素中心、depth 双重含义与 `z = 0` 策略
相机投影核心约定深度解析Korniakornia.geometry.camera的坐标系、整数像素中心、depth 双重含义与z 0策略【免费下载链接】kornia 空间人工智能的几何计算机视觉库项目地址: https://gitcode.com/kornia/kornia导读Kornia 在kornia.geometry.camera子包中为相机投影核心PinholeCamera类与project_points/unproject_points等函数式 API沉淀了一整套可执行约定世界到相机的外参方向、整数像素中心、depth 的两种语义以及z 0的投影行为。本文以迁移日志条目 changelog.d/migration-008.added.md 为主线结合源码实现、文档页与测试用例executable pins完整解析这些约定及其边界行为帮助你在相机标定、双目几何、深度反投影等场景中避免半像素偏移这类静默错误。一、背景为什么投影核心需要一份书面约定kornia.geometry.camera是 Kornia 几何子库中负责相机建模与投影的模块公开的 API 包括见 kornia/geometry/camera/init.py类式 APIPinholeCamera、StereoCamera、PinholeCamerasList函数式 APIproject_points/unproject_points透视投影、project_points_z1/unproject_points_z1规范化 z1 平面、project_points_orthographic/unproject_points_orthographic正交投影、cam2pixel/pixel2cam以及仿射与 Kannala-Brandt 两类畸变模型投影是几何视觉的公共地基标定、PnP、三角化、深度反投影、位姿估计全都依赖它。而相机约定在不同生态OpenCV、COLMAP、OpenGL、ARKit、PyTorch3D之间存在静默差异——形状依然匹配、图像看起来依然合理但重建结果会差半像素、甚至镜像。这正是迁移条目migration-008.added.md记录的工作PR #4294把投影核心的约定文档化并用可执行的测试把它钉住pins同时把已知的 scale 规则、别名、guard 与遗留 API 限制登记在专门的 issue 中跟踪。注意本文所称的约定与限制均以当前仓库源码中的Convention:/.. warning::注释块为准它们是这些文档化约定的第一手出处。二、PinholeCamera的帧约定世界到相机还是相机到世界PinholeCamera是投影核心的类式入口其约定块写在 kornia/geometry/camera/pinhole.py 的类 docstring 中intrinsics是(B, 4, 4)标定矩阵左上角3×3块为[[fx, 0, cx], [0, fy, cy], [0, 0, 1]]extrinsics是(B, 4, 4)的 world-to-camera 变换[R | t]即 OpenCV / COLMAP 语义project接收世界点计算K (R X t)得到像素unproject是其逆——接收像素与相机系深度返回世界点函数式 API 则工作在相机系project_points/unproject_points只接收K、不接收外参因此不会在帧之间移动。类式与函数式两条路径的投影实现可以在源码中对照# PinholeCamera.project完整 4x4 乘积 P self.intrinsics self.extrinsics return convert_points_from_homogeneous(transform_points(P, point_3d)) # project_points仅相机系 K无外参 xy_coords convert_points_from_homogeneous(point_3d) return denormalize_points_with_intrinsics(xy_coords, camera_matrix)对应关系见 perspective.py 与 pinhole.py。一个易错点是unproject_points的返回位于相机系无法返回世界坐标只有PinholeCamera.unproject才是世界系的反投影二者按需取用。PinholeCamera的构造会对形状做严格校验intrinsics/extrinsics必须是B×4×4或B×N×4×4height/width必须是(B,)一维张量且四者 batch 维与设备必须一致_check_valid、_check_valid_params、_check_consistent_device。注意project要求文档化的(B, 4, 4)布局(B, N, 4, 4)的直接投影限制被记录在 issue #4266 中见下文。PinholeCamera还提供了fx/fy/cx/cy/tx/ty/tz、camera_matrix、rotation_matrix、translation_vector等属性以及scale/scale_/clone/from_parameters等操作StereoCamerastereo.py同样遵循整数像素中心与整数像素中心深度约定供双目几何使用。三、整数像素中心cx (W - 1) / 2而不是W / 2PinholeCamera的第二个核心约定是整数像素中心integer pixel centres像素坐标是(u, v) (x, y) (列, 行)像素(0, 0)的中心位于(0, 0)——这正是kornia.geometry.create_meshgrid枚举的网格因此居中图像的像主点位于cx (W - 1) / 2、cy (H - 1) / 2半像素约定如 COLMAP把像素角点放在原点同一像主点会在每个轴上大半个像素。这一约定与 OpenCV / Kalibr 一致而 COLMAP 的 FAQ 明确指出 OpenCV and Kalibr place integer coordinates at pixelcenters。其完整对照表含grid_sample的align_corners语义记录在文档页 docs/source/get-started/camera-conventions.rst并从该表导出三条换算规则约定像素 (0,0) 中心居中 W×H 图像的像主点OpenCV / 整数Kornia(0.0, 0.0)((W-1)/2, (H-1)/2)COLMAP / 半像素(0.5, 0.5)(W/2, H/2)cx_colmap cx_opencv 0.5cy同理焦距与畸变系数不变图像按尺度s缩放时两种约定的主点缩放公式不同OpenCV 为cx s * cx (s - 1) / 2COLMAP 为cx s * cx仅在s 1时一致归一化到单位方格的 intrinsics首像素中心在(0.5/W, 0.5/H)属于半像素约定按图像尺寸缩放后的形式换算为整数中心像素需要fx_px W * fx_n、cx_px W * cx_n - 0.5。对应测试钉位于 tests/geometry/camera/test_perspective.pytest_convention_integer_pixel_centres_put_the_principal_point_at_w_minus_one_half用H2, W3的网格刻意让行列数不等避免转置读取碰巧通过验证——在cx1, cy0.5下首末像素反投影互为精确相反数光轴(0, 0, 1)恰好落在像主点(1, 0.5)上若误用半像素的cx1.5, cy1.0则两者都不成立。grid kornia.geometry.create_meshgrid(2, 3, normalized_coordinatesFalse) # - [[0, 0], [1, 0], [2, 0], [0, 1], [1, 1], [2, 1]] # cx (3 - 1) / 2 1, cy (2 - 1) / 2 0.5, fx fy 1 unproject_points([[0., 0.]], depth1, K) # - [[-1, -0.5, 1]] unproject_points([[2., 1.]], depth1, K) # - [[ 1, 0.5, 1]]四、depth 的两种含义相机系z还是欧氏射线长度迁移条目记录的第三类约定是depth 的两种含义默认语义depth是反投影结果的相机系z坐标第二种语义当unproject_points以normalizeTrue调用时depth_to_3d/depth_to_3d_v2的normalize_points标志同理depth被读作欧氏射线长度反投影点具有该范数、而z分量更小。源码实现非常直观perspective.pyxy normalize_points_with_intrinsics(point_2d, camera_matrix) xyz convert_points_to_homogeneous(xy) if normalize: xyz F.normalize(xyz, dim-1, p2.0) # 归一化到单位范数 return xyz * depthnormalizeFalse时xyz的z分量恒为 1乘上 depth 后z depthnormalizeTrue时先做 L2 归一化再乘 depth结果的范数等于 depth、z严格小于 depth。单目深度网络对预测的是z还是射线长度并无统一约定选择错误会移动所有不在主射线上的反投影点。测试钉test_convention_normalize_makes_depth_the_ray_lengthtests/geometry/camera/test_perspective.py用偏离主点的像素(29, 53)cx4 ≠ cy3使两种读法可区分验证K [[100, 0, 4], [0, 100, 3], [0, 0, 1]] unproject_points([[29., 53.]], depth2, K) # - [[0.5, 1.0, 2.0]] z depth unproject_points([[29., 53.]], depth2, K, normalizeTrue) # - [[0.436, 0.873, 1.746]] norm depth五、z 0策略投影核心的边界行为第四个被钉住的约定是z 0时的投影行为。透视投影的标准公式是u fx * X/Z cx但z 0意味着除零。不同入口对同一输入给出了不同的答案均不抛异常这是文档明确记录、并由测试 pin 住的行为入口z 0时的行为project_points/PinholeCamera.project跳过透视除法对未除的点应用K得到fx*x cx有限值project_points_z1/Z1Projection.project直接除零各分量按分子符号得到inf/-inf/nan分子为零时nancam2pixel有限但巨大的~1e14量级数值project_points的源码路径解释了前者convert_points_from_homogeneous会把|z| 1e-8的点屏蔽为除数 1因此z 0的点实际走不除法分支输出K·[x, y, z]^T的归一化结果perspective.py。测试钉test_wart_project_points_skips_the_divide_at_zero_4267tests/geometry/camera/test_perspective.py把它钉在精确值上K [[100, 0, 4], [0, 100, 3], [0, 0, 1]] project_points([[1., 2., 0.]], K) # - [[104., 203.]] 即 fx*14, fy*23无除法 project_points([[1., 2., -4.]], K) # - [[-21., -47.]] 相机背后的点被同样静默投影与之形成对照project_points_z1明确声明其前置条件是z 0点在相机前方但该前置条件不被校验在z 0处每个输出分量都是inf/-inf/nanprojection_z1.py。测试注释指出project_points_z1、PinholeCamera.project、project_points与cam2pixel四个入口在z 0处给出四种不同答案这一不一致被登记为 issue #4267测试 pin 的是当前行为而非契约待问题修复后应删除。这些测试的命名以wart_/convention_区分两类角色convention_*钉住的是被认定为正确并延续的约定如整数像素中心、depth 语义wart_*钉住的是已知缺陷的当前行为如z0除零策略注释明确标注 Pins the CURRENT value; NOT a contract; delete when #4267 is repaired。这套命名规范本身就是 migration-008 引入的可执行钉工程实践。六、已知限制与遗留 API五个被跟踪的问题迁移条目特意强调投影核心的已知限制没有悄悄修掉而是以当前行为为准文档化、并登记在独立 issue 中跟踪修复。源码中的.. warning::块一一对应Issue限制内容出处#4263PinholeCamera.scale/scale_以cx s * cx半像素规则缩放主点与库内其余部分的整数像素中心不一致pinhole.py、pinhole.py#4265scale_在整数height/width上使用浮点尺度因子会抛RuntimeError且抛出时相机已处于部分缩放状态scale则会把整数尺寸提升为浮点pinhole.py#4266(B, N, 4, 4)形状的相机存储无法直接用于project需要(B, 4, 4)仅PinholeCamerasList的共享校验器接受前者pinhole.py#4267z 0处多个投影入口行为不一致见第五节perspective.py、projection_z1.py#4268遗留 12 向量 APIpinhole_matrix的输出以eye(4) eps构建float32/float64下结构性零与一都携带eps且该遗留 API 未在任何 API 参考页导出pinhole.py其中pinhole_matrix接收遗留的 12 向量布局(fx, fy, cx, cy, height, width, rx, ry, rz, tx, ty, tz)(rx, ry, rz)为角轴旋转docstring 明确标注其已被PinholeCamera及camera_matrix属性取代Superseded。使用遗留接口时需自行处理eps问题eps0.0返回精确矩阵。七、跨库边界实践把约定落在代码里这些约定不只是文档它们直接决定你在标定数据接入、深度网络输出转点云、位姿换算时写下的公式像素坐标Kornia 的网格是整数中心的create_meshgrid(normalized_coordinatesFalse)枚举0..W-1接入 COLMAP 标定结果时主点要加0.5接入归一化 intrinsics 时用fx_px W * fx_n、cx_px W * cx_n - 0.5。外参方向Kornia 的extrinsics与 OpenCV、COLMAP 同为 world-to-cameraCOLMAPimages.txt的四元数平移无需取逆只需四元数转矩阵需要 camera-to-world 位姿时用 conversions.py 中的worldtocam_to_camtoworld_Rt/camtoworld_to_worldtocam_Rt按转置计算刚性逆(R^T, -R^T t)。depth 语义把单目深度网络的输出喂给unproject_points前先确认它预测的是相机系z还是射线长度后者必须传normalizeTruedepth_to_3d系函数对应normalize_points标志。边界输入z 0的点不会被拒绝。若你的管线不允许相机背后的点出现应在调用前自行校验而不是依赖投影函数抛错。完整的跨库对照OpenCV / COLMAP / OpenGL / ARKit / ARCore / PyTorch3D / Direct3D 的轴方向、手性、像素中心与对应转换器见文档页 docs/source/get-started/camera-conventions.rst其每个非 Kornia 单元格均标注了上游文档依据可作为跨生态换算的权威速查表。小结migration-008.added.md对应的是一次约定工程kornia.geometry.camera的投影核心从此有了书面的坐标系约定world-to-camera 外参、整数像素中心、depth 双重语义、z 0策略配套的可执行测试把每条约定钉在当前行为上convention_*为契约、wart_*为已知缺陷五个已知限制#4263、#4265、#4266、#4267、#4268被显式登记、按当前行为文档化。对使用者而言这意味着接入标定与深度数据前先对齐像素中心与 depth 语义规避scale的主点规则差异并对z 0输入保持警惕——这些约定本身就是避免半像素偏移这类静默错误的第一道防线。【免费下载链接】kornia 空间人工智能的几何计算机视觉库项目地址: https://gitcode.com/kornia/kornia创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关推荐

机房微孔天花选型与施工的5大误区解析
机房微孔天花选型与施工的5大误区解析

1. 机房微孔天花的重要性与常见误区概述在机房建设这个系统工程中,微孔天花看似只是吊顶系统的一个小部件,实则承担着多重关键功能。作为在机房建设领域摸爬滚打多年的从业者,我见过太多因为轻视这个"小部件"而付出惨痛代价的案例。… · 2026/9/23 11:30:50

重组家庭情感重构的心理学方法与实用技巧
重组家庭情感重构的心理学方法与实用技巧

1. 重组家庭的情感重构挑战当两个原本独立的家庭走到一起,就像把两幅不同的拼图重新组合。我见过不少重组家庭在最初几年都会面临相似的困境:孩子们用"你妈妈""我爸爸"这样的称呼划清界限,节假日因为探视安排闹得不欢而散… · 2026/9/23 11:30:50

麦吉机器人面试必问:3招拆解底层逻辑,拒绝背八股文
麦吉机器人面试必问:3招拆解底层逻辑,拒绝背八股文

麦吉机器人面试必问:3招拆解底层逻辑,拒绝背八股文 官方文档像天书一样厚,翻到第三页就头疼,抓不住重点怎么办? 麦吉机器人(MagicBot)的机制,往往是后端开发和架构师 面试必问 的高频考点。 很多同学背了一堆 API… · 2026/9/23 11:30:50

Java Web教学项目Hotelmanger.zip部署与排错指南
Java Web教学项目Hotelmanger.zip部署与排错指南

简介:本资源是一个基于Java开发的酒店管理系统实战项目,面向Java初学者与课程设计学习者,解决酒店日常运营中房间管理、入住退房、预订调度、收银结算及权限管控等核心业务场景。压缩包为zip格式,大小1.23MB,虽未提供具… · 2026/9/23 12:14:26

3个API变更踩坑案例:尽量的读音源码解析实战
3个API变更踩坑案例:尽量的读音源码解析实战

3个API变更踩坑案例:尽量的读音源码解析实战 版本升级后 API 全变了,这种绝望感每个写过代码的人都懂。你以为只是改个参数名,结果整个调用链直接崩盘,调试半天才发现是底层逻辑重构了。这时候光看文档不够,得直接看 源码解析… · 2026/9/23 12:14:26

搞定电容换算实战项目:3步解决单位转换痛点
搞定电容换算实战项目:3步解决单位转换痛点

搞定电容换算实战项目:3步解决单位转换痛点 看了一堆教程还是不会写项目?别慌,这确实是很多开发者的通病。理论背得滚瓜烂熟,一到实战项目就卡壳,尤其是遇到像电容换算这种看似简单实则细节极多的场景。… · 2026/9/23 12:14:20

矩生成函数(MGF)详解:从定义、泰勒展开到独立和与中心极限定理的工程实践
矩生成函数(MGF)详解:从定义、泰勒展开到独立和与中心极限定理的工程实践

“矩生成函数”这个名字,我当年第一次在概率论课本里撞见时,心里是有点发怵的——又是矩又是生成函数,听着像要把整个随机变量彻底拆开揉碎,非要先在心里建设半小时才敢往下翻。等后来真正在统计推导、机器学习的指数族分布、甚至… · 2026/9/23 12:14:19

2026最新东方时尚驾校模拟考试技术栈横向对比
2026最新东方时尚驾校模拟考试技术栈横向对比

2026最新东方时尚驾校模拟考试技术栈横向对比 官方文档往往冗长枯燥,几百页的规范没人愿意从头读到尾,大家只想在 2026最新… · 2026/9/23 12:14:13

FPGA vivado环境使用:第一步点灯代码
FPGA vivado环境使用:第一步点灯代码

打开软件,创建工程起一个工程名,路径英文进入工程界面编写v代码创建一个文件 . 编写代码 module LED_TWINKLE( input key, output led ); assign led~key; endmoduleRTL ANALYSIS管脚定义编译生成bit流 Generate Bitstream10.点击Program Device 下载到板… · 2026/9/23 12:14:13

3招搞定手机怎么下载微信面试难题实战项目解析
3招搞定手机怎么下载微信面试难题实战项目解析

3招搞定手机怎么下载微信面试难题实战项目解析 面试被问“手机怎么下载微信”背后的原理,90%的人答不上来。别笑,这看似弱智的问题,实则是考察你对移动应用分发机制、安全校验及网络协议理解的试金石。我带过不少校招新人,他们背了八股文,却连一个A… · 2026/9/23 0:00:03

你有新短消息请注意查收:3个新手避坑指南搞定消息系统选型
你有新短消息请注意查收:3个新手避坑指南搞定消息系统选型

你有新短消息请注意查收:3个新手避坑指南搞定消息系统选型 面试被问“高并发下如何保证消息不丢失”,你张口就是“用Redis”,结果面试官追问“如果Redis宕机了怎么办”,你瞬间卡壳。这种场景太常见了,很多新手在背八股文时,只记住了技术名词… · 2026/9/23 0:00:29

Win7无线热点配置工具源码解析:解决API失效的3个实战技巧
Win7无线热点配置工具源码解析:解决API失效的3个实战技巧

Win7无线热点配置工具源码解析:解决API失效的3个实战技巧 Win7无线热点配置工具在Win10/11上跑不动?不是你的问题,是版本升级后 API 全变了。很多老项目里的 netsh wlan… · 2026/9/23 0:00:36

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码