news 2026/9/23 18:41:53

Kornia 传感器相机模型实现解读:Brown-Conrady、Kannala-Brandt K3 与 Orthographic 的可微投影管线

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Kornia 传感器相机模型实现解读:Brown-Conrady、Kannala-Brandt K3 与 Orthographic 的可微投影管线
  • 计算机视觉
  • 人工智能
  • 深度学习
  • 图像处理

【免费下载链接】kornia

🐍 Geometric Computer Vision Library for Spatial AI

项目地址:https://gitcode.com/gh_mirrors/ko/kornia
点击查看免费下载

导读

本文围绕 Kornia 仓库中 changelog.d/+migration-003.added.md 记录的迁移变更展开:Kornia 在其实验性传感器子模块kornia.sensors.camera中正式实现了Brown-Conrady、Kannala-Brandt K3、Orthographic三种可导出相机模型,连同 Pinhole 在内共四种模型类型,统一了畸变(distortion)与投影(projection)的管线组合、内参矩阵(intrinsic matrix)生成以及批量 project/unproject 支持。读完本文,你将掌握CameraModelCameraModelBase的两种构造方式、四种模型各自的参数布局与适用场景、project/unproject的底层调用链,以及如何在批处理点云中正确使用这套 API。

一、变更背景:sensors.camera 模块的定位

该变更(关联 PR #4284、#4377)落点在 kornia/sensors/camera/ 目录下,包含三个核心实现文件:

  • camera_model.py —— 相机模型组装层,定义CameraModelType枚举、CameraModelBase基类、CameraModel门面类及四种具体模型;
  • distortion_model.py —— 畸变层,提供AffineTransformBrownConradyTransformKannalaBrandtK3Transform三种畸变/去畸变变换;
  • projection_model.py —— 投影层,提供Z1Projection(透视除法)与OrthographicProjection(正射投影)。

从源码注释与文档(见 docs/source/sensors.camera.rst)可知,kornia.sensors.camera实验性 API,其设计目标是把"已知相机模型"(Pinhole、Kannala-Brandt 等)统一表达为"畸变类型 × 投影类型"的可组合组件,并保证全程可微。该模块将来会取代kornia.geometry.camera,但当前两者按设计保持分离:数学映射一致,却在输入类型(Vector对象 vs 裸张量)、相机轴广播方式、投影舍入、零/近零深度处理上存在差异(记录于 issue #4274)。

二、四种相机模型类型与参数布局

2.1CameraModelType枚举

CameraModelType 定义在kornia/sensors/camera/camera_model.py

枚举值数值说明
PINHOLE0标准透视投影,无畸变
BROWN_CONRADY1径向 + 切向畸变模型,常用于广角镜头
KANNALA_BRANDT_K32鱼眼畸变模型,采用 9 阶多项式等距投影近似
ORTHOGRAPHIC3平行投影,光线垂直于像平面,无透视效果

2.2 每种模型的参数向量长度与顺序

参数向量params尾维长度由畸变模型决定,这是整套 API 的硬约束。源码中通过_PARAMS_LEN_FOR_DISTORTION字典(camera_model.py)将畸变类型映射到参数长度:

模型类畸变/投影组件参数形状参数顺序
PinholeModelAffineTransform+Z1Projection(4,)(B, 4)(fx, fy, cx, cy)
OrthographicAffineTransform+OrthographicProjection(4,)(B, 4)(fx, fy, cx, cy)
BrownConradyModelBrownConradyTransform+Z1Projection(12,)(B, 12)(fx, fy, cx, cy, k1, k2, p1, p2, k3, k4, k5, k6)
KannalaBrandtK3KannalaBrandtK3Transform+Z1Projection(8,)(B, 8)(fx, fy, cx, cy, kb0, kb1, kb2, kb3)

其中 Brown-Conrady 的前 4 个值为内参、后 8 个为畸变系数;Kannala-Brandt K3 的后 4 个为鱼眼多项式系数。参数长度由各类型化构造器强制校验:PinholeModel.__init__BrownConradyModel.__init__KannalaBrandtK3.__init__Orthographic.__init__均会检查尾维长度且拒绝秩大于 2 的张量,否则抛出ValueError(例如"params must be of shape (B, 12) for BROWN_CONRADY Camera")。在直接构造CameraModelBase的路径上,基类__init__也会通过_validate_params施加同样的校验,避免出现"参数过短延迟到畸变模型内部抛IndexError"的隐蔽错误。

三、两种构造方式:CameraModel 与 CameraModelBase

3.1 通过CameraModel门面类(按类型枚举选择)

CameraModel是面向用户的入口,接收image_sizemodel_typeparams,内部通过get_model_from_type分发到具体模型类,并以__getattr__透明转发全部属性与方法:

import torch from kornia.image import ImageSize from kornia.sensors.camera import CameraModel, CameraModelType # Pinhole:fx, fy, cx, cy cam = CameraModel(ImageSize(480, 640), CameraModelType.PINHOLE, torch.tensor([328., 328., 320., 240.])) # Brown-Conrady:12 参数(4 内参 + 8 畸变系数) cam = CameraModel( ImageSize(480, 640), CameraModelType.BROWN_CONRADY, torch.tensor([1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0]), ) # Kannala-Brandt K3:8 参数(4 内参 + 4 鱼眼系数) cam = CameraModel( ImageSize(480, 640), CameraModelType.KANNALA_BRANDT_K3, torch.tensor([1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0]), ) # Orthographic:4 参数 cam = CameraModel(ImageSize(480, 640), CameraModelType.ORTHOGRAPHIC, torch.tensor([328., 328., 320., 240.])) print(cam.params) # tensor([328., 328., 320., 240.])

3.2 通过CameraModelBase自由组合(自定义模型)

CameraModelBase接受显式的畸变与投影组件,适用于定义自定义相机模型:

import torch from kornia.image import ImageSize from kornia.sensors.camera import CameraModelBase from kornia.sensors.camera.distortion_model import AffineTransform from kornia.sensors.camera.projection_model import Z1Projection cam = CameraModelBase(AffineTransform(), Z1Projection(), ImageSize(480, 640), torch.tensor([328., 328., 320., 240.]))

CameraModelBase.__init__的签名是(distortion, projection, image_size, params)。由于畸变有 3 种、投影有 2 种,理论上可自由组合出 6 种模型;仓库内置的 4 种模型正是其中 4 个合理的组合,Pinhole 与 Orthographic 共用AffineTransform(仅内参),区别只在于投影层。

3.3 参数校验规则

  • params必须是秩 1 的(N,)或秩 2 的(B, N)
  • 尾维长度必须等于对应畸变模型读取的长度(4 / 12 / 8);
  • 违反时抛出带明确模型名与形状信息的ValueError(camera_model.py);
  • 测试侧对该规则有完整覆盖,见 tests/sensors/camera/test_camera_model.py 中针对四种模型类型分别验证非法参数抛ValueError的用例。

四、内参矩阵:matrix() 与 K() 别名

所有相机模型通过CameraModelBase.matrix()返回(*, 3, 3)的内参矩阵KK()是等价别名):

K = [[fx, 0, cx], [0, fy, cy], [0, 0, 1]]

其实现从params中逐项取出fx/fy/cx/cyfxfycxcy属性分别返回params[..., 0..3]),堆叠三行后把右下角置 1。矩阵携带params的 batch 轴,因此批量相机得到(B, 3, 3)。源码文档特别指出:这与kornia.geometry.camera.pinhole.PinholeCamera存储的(B, 4, 4)intrinsics不同——后者需要通过camera_matrix属性取出(B, 3, 3)块。即sensors.camera直接给出 3×3 的 K,无 4×4 包装层

此外PinholeModel.scale(scale_factor)提供缩放能力:返回新模型,焦距、主点与图像尺寸全部乘以缩放因子(fx' = s·fxcx' = s·cx的半像素规则),例如cam.scale(2)params变为[656., 656., 640., 480.]

五、project / unproject 管线:畸变与投影的组合调用链

5.1 核心组合公式

CameraModelBaseprojectunproject是两个方向的组合调用(camera_model.py):

def project(self, points: Vector3) -> Vector2: # 先透视投影到 z=1 归一化平面,再做畸变到像素 return self.distortion.distort(self.params, self.projection.project(points)) def unproject(self, points: Vector2, depth: torch.Tensor) -> Vector3: # 先像素去畸变回 z=1 归一化平面,再按深度抬升回相机系 return self.projection.unproject(self.distortion.undistort(self.params, points), depth)

调用链可拆解为:

project: 相机系3D点 (Vector3) → Z1/Orthographic 投影 → z=1 归一化平面 (Vector2) → Affine/BrownConrady/KannalaBrandt 畸变 → 像素坐标 (Vector2) unproject: 像素坐标 (Vector2) → 畸变模型去畸变 → z=1 归一化平面 → 投影模型按 depth 抬升 → 相机系3D点 (Vector3)

5.2 三个畸变层的实现

  • AffineTransform:纯内参映射,u = fx·x + cxv = fy·y + cy(distort)与x = (u − cx)/fxy = (v − cy)/fy(undistort)。unproject 侧有闭式逆,无迭代(distortion_model.py)。
  • BrownConradyTransform:从params拆分出 K 与后 8 个畸变系数params[..., 4:],底层委托给kornia.geometry.calibration.distort_points/undistort_points,并以单位矩阵作为new_K(distortion_model.py)。
  • KannalaBrandtK3Transform:鱼眼模型,底层委托kornia.geometry.camera.distortion_kannala_brandt模块的distort_points_kannala_brandt/undistort_points_kannala_brandt(distortion_model.py)。

5.3 两个投影层的实现

  • Z1Projection:透视除法xy / z,无 epsilon、无校验——z = 0的点投影为无穷(分子亦为 0 时得到nan),z < 0(相机后方)的点得到有限坐标。unprojectdepth相机系 z 坐标,结果第三维等于传入的 depth 而非欧氏射线长度;Python 标量 depth 会自动提升为与 points 同设备同 dtype 的一元素张量(projection_model.py)。
  • OrthographicProjection:保留 x、y 不变并丢弃 z,物体不随距离缩小;底层委托project_points_orthographic/unproject_points_orthographic(projection_model.py)。

5.4 使用示例

from kornia.geometry.vector import Vector2, Vector3 # project:相机系点 → 像素 points = Vector3(torch.tensor([1.0, 1.0, 1.0])) cam = CameraModel(ImageSize(480, 640), CameraModelType.PINHOLE, torch.tensor([328., 328., 320., 240.])) cam.project(points) # x: 648.0, y: 568.0 # unproject:像素 + depth → 相机系点 pts = Vector2(torch.tensor([1.0, 1.0])) cam.unproject(pts, torch.tensor([1.0])) # x ≈ -0.9726, y ≈ -0.7287, z = 1.0

5.5 与 kornia.geometry.camera 的差异(重要)

源码的 Convention 块明确列出了与kornia.geometry.camera的几点关键差异:

  1. 输入类型:本 API 只接受Vector对象,裸torch.Tensor会触发AttributeErrorgeometry侧接受裸张量。两套类型系统按设计分离(issue #4274)。
  2. 投影实现project直接除以 z,而project_points乘以 z 的倒数并在abs(z) <= 1e-8时跳过除法——阈值附近舍入结果可能不同,[1, 2, 0]在本 API 得到无穷、在 geometry 侧得到有限像素(issue #4267)。
  3. 广播语义:对(B, N, 3)/(B, N, 2)点云,本 API 将(B,)的内参分量直接作用于(B, N)坐标(对齐点轴);geometry 函数则插入单点轴、沿相机 batch 轴应用内参。当B == N > 1时两套 API 会把内参与不同点关联;B = 2, N = 3时本 API 直接抛RuntimeError因此仅更换点容器与 depth 形状不足以完成批量点云迁移

六、批量支持与验证

6.1 批量参数与批量点

所有模型构造器均接受(B, N)形式的批量参数;project/unproject支持带前导 batch 维的点。基础校验逻辑在_validate_params中统一处理:秩 1/2 之外的形状直接拒绝,杜绝了"rank-3 的(B, 1, N)张量被静默投影成错误的(1, 1, 2)结果"这类隐患。

6.2 测试覆盖

仓库测试位于 tests/sensors/camera/ 下三个文件,分别覆盖相机模型、畸变模型与投影模型:

  • test_camera_model.py:使用非对称 fixture(fx=100 ≠ fy=50cx=4 ≠ cy=3、非方形 6×8 图像)验证参数顺序读取、非法参数抛ValueError、四种模型类型的 smoke test 等,共 641 行;
  • test_distortion_model.py 与 test_projection_model.py:分别验证三类畸变变换与两类投影的前后向一致性。

七、当前 API 的注意事项与限制

  1. 实验性状态kornia.sensors.camera为实验性 API,未来可能变化,最终将取代kornia.geometry.camera,但目前两者并存、按设计分离。
  2. 参数长度强约束:不同模型对params尾维有硬性长度要求(4/8/12),批量时须保持(B, N)形状,切勿传入(B, 1, N)
  3. z=0 行为:透视投影对z = 0的点不报错而是产出无穷/NaN,若需稳健行为请在调用侧自行过滤深度。
  4. 批处理点云广播:批量点云场景下,本 API 与kornia.geometry.camera的广播语义不同,混用两套 API 处理同一批数据可能得到错误关联,迁移前务必阅读源码中的 Convention 块(camera_model.py)。

结语

+migration-003这次变更把 Kornia 的传感器相机能力从单一的 Pinhole 扩展为Pinhole / Brown-Conrady / Kannala-Brandt K3 / Orthographic 四种可导出模型,并通过"畸变 × 投影"的可组合架构、CameraModel/CameraModelBase双入口、严格参数校验、Vector类型化的 project/unproject 与批量支持,为 Spatial AI 中的相机标定、多传感器融合与可微渲染提供了统一的底层基础设施。如需继续深入,建议阅读 camera_model.py 的完整 Convention 块、distortion_model.py 中三类畸变的数学实现,以及 docs/source/sensors.camera.rst 的 API 文档与三个测试文件中的数值校验用例。

  • 计算机视觉
  • 人工智能
  • 深度学习
  • 图像处理

【免费下载链接】kornia

🐍 Geometric Computer Vision Library for Spatial AI

项目地址:https://gitcode.com/gh_mirrors/ko/kornia
点击查看免费下载

相关推荐

上一篇:Element Plus颜色选择器:ColorPicker颜色选择与自定义
下一篇:彻底解决SmartDNS 53端口冲突:从原理到实战的完美方案

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/23 18:41:54

360网神选型避坑指南:5个最佳实践解决代码跑不通难题

360网神选型避坑指南:5个最佳实践解决代码跑不通难题 复制来的代码跑不通不知道怎么调,这种崩溃感谁懂?别急着骂人,大概率是环境配置和依赖版本没对齐。做技术选型和后端开发, 最佳实践…

作者头像 李华
网站建设 2026/9/23 18:41:31

小米盒子mini折腾全记录:3步搞定,新手避坑指南

小米盒子mini折腾全记录:3步搞定,新手避坑指南 配置环境就卡半天?别急,很多兄弟买回小米盒子mini,对着说明书发呆,连投屏都连不上。 这真不是你的问题。硬件是死的,系统是活的,网络环境更是千差万别。今天不整虚的,直接上干货。 咱们目标很明确:把这台小铁盒子从“吃灰神器”变成“全能终端”。…

作者头像 李华
网站建设 2026/9/23 18:41:31

5个最佳实践搞定手机微信打不开

5个最佳实践搞定手机微信打不开 复制来的代码跑不通,报错信息像天书,新手常陷调试泥潭。本文拆解手机微信打不开的高频考点,用最佳实践帮你从入门到精通,面试不慌。 考点梳理 手机微信打不开是移动端面试高频题,考察网络、缓存、权限三大维度。应届生易忽略底层机制,只记表面现象。 核心考点:…

作者头像 李华
网站建设 2026/9/23 18:41:20

告别配置地狱:11110实战最佳实践

告别配置地狱:11110实战最佳实践 配置环境就卡半天?这是无数开发者在接手新项目时的真实写照。依赖版本冲突、环境变量缺失、本地与生产环境差异巨大,这些琐碎问题往往比写业务逻辑更耗时。想要彻底解决这个痛点,不能只靠玄学,必须建立一套可复现、标准化的 最佳实践 。 今天我们要从零搭建一个基于…

作者头像 李华
网站建设 2026/9/23 18:41:19

3个坑避开440449改版,高频面试题不再丢分

3个坑避开440449改版,高频面试题不再丢分 版本升级后 API 全变了,代码跑不通,心里发慌。这是很多开发者在接触 440449 相关技术栈时的真实写照。尤其是准备面试时,面试官抛出的 高频面试题 往往直接指向底层机制的变化,答不上来直接出局。 别慌。今天不聊虚的,我们直接拆解 440449…

作者头像 李华
网站建设 2026/9/23 18:40:50

比较运算符底层避坑指南:3个隐藏陷阱让代码更稳

比较运算符底层避坑指南:3个隐藏陷阱让代码更稳 官方文档翻了三遍,关于比较运算符的章节还是像天书一样绕。很多开发者觉得 == 就是等于, != 就是不等,直到生产环境出现数据对不上的 Bug,才意识到这行代码里藏着多少玄机。这份避坑指南不堆砌理论,直接拆解底层逻辑,帮你把比较运算符的底层原理吃透。…

作者头像 李华