12投影模型全景

本页路线图(由浅入深)
  1. 是什么(一 ~ 二),哪些传感器有投影参数 · 鱼眼实例
  2. 为什么(三 ~ 七),交互演示 · 为什么不存在完美模型 · 模型全景 · π 无关 · 和地图投影同源
  3. 怎么用(八 ~ 九),方向辨析 · 选型决策
深入 · 数学根源含对比演示

一、哪些传感器有"投影参数"

先看两台传感器对同一场景的读数差别。相机拍下一帧,一个像素只能说明"这个方向上有个东西", 说不出它有多远;LiDAR 扫一圈,每个读数自带距离,一个读数就对应一个确定的 3D 点。 差别可以收成一条判据:这个传感器的输出是不是「降维且不可逆」的。

相机的读数:   (u, v) 像素
              → 一个像素 = 一条射线 = 无穷多个 3D 点
              → 【不可逆】,丢掉了深度
              → 必须靠"投影参数"才能把像素还原成射线

LiDAR 的读数: (ring, azimuth, range)
              → range 就是深度!
              → 一个读数 = 一个确定的 3D 点
              → 【可逆】,只需要坐标变换参数,不需要"投影参数"
核心一句话

「投影参数」存在的前提,是传感器测不到深度。

相机把 3D 世界"拍扁"成 2D 图像,压掉了深度这一维。 投影参数就是用来描述"这次压扁是怎么压的",补足降维损失的那部分信息。

传感器输出测深度?可逆?有投影参数?
针孔相机(u,v)❌❌✅ 必须有
鱼眼 / 全景相机(u,v)❌❌✅ 必须有,还要指定投影模型
深度相机 RGB-D(u,v) + depth✅(自己测的)✅✅ 有(用于反投影)
LiDAR (3D)角度 + 距离✅✅❌ 只有坐标变换参数
LiDAR (2D)角度 + 距离✅✅❌
毫米波雷达距离+方位+多普勒✅✅❌(但有角度标定)
超声波只有距离✅❌ 连方向都没有❌
IMU / 编码器 / 力 / 触觉标量 / 向量——❌ 与投影无关

一个漂亮的反转:LiDAR 的原始数据也是 2D 网格

LiDAR 的原始测量:
  (ring_index, azimuth_index) → range
       ↑              ↑
    垂直索引        水平索引
  = 一个【2D 数组】!   // 结构上和一个图像一模一样

区别在于:
  图像的 2D 数组:   (u, v)      → 【没有】深度 → 不可逆 → 需要投影参数
  LiDAR 的 2D 数组: (ring, az)  → 【有】range   → 可逆   → 不需要

所以 LiDAR 的输出也叫 "range image"(距离图像),它长得像图,但每个像素自带深度。 这就是为什么相机需要标定一堆参数、LiDAR 只需要一个外参。

投影参数的标准形态:P,一个 3×4 矩阵

Foxglove 的 CameraCalibration schema 里,有个字段的名字就叫"投影矩阵":

P  : float64[12]  ——  "Projection/camera matrix (3x4 row-major matrix)"

    ⌊ fx'  0  cx'  Tx ⌋
P = |  0  fy' cy'  Ty |
    ⌊  0   0   1    0 ⌋

给定 3D 点 [X Y Z]¹,投影到(校正后)图像的 (x, y):
    [u v w]¹ = P · [X Y Z 1]¹      x = u/w      y = v/w

P 把内参和外参一次性合成了一个矩阵,这就是 KITTI 里的 P_rect。

K / R / P 三个矩阵,最容易搞混

字段名字是什么
KIntrinsic camera matrix (3×3)原始(带畸变的)图像的内参
RRectification matrix (3×3)立体校正旋转,让两台相机的极线平行
PProjection matrix (3×4)校正后图像的内参 + 立体基线平移
DDistortion parameters畸变系数

官方原文说得很清楚:K 是 raw (distorted) 图像的内参; P 的左边 3×3 部分是校正后(rectified)图像的内参, "这些值可能与 K 中的不同"。单目相机通常 Tx = Ty = 0, R = 单位阵,P[:, :3] = K。

物理镜头 → K + D 描述(真实存在的那个相机)
   ↓ 立体校正(把图像重投影到理想平行极线的虚拟像平面)
虚拟相机 → P 描述(你实际拿去算几何的那个)
所以

这正是"投影参数"和"内参"不是一回事的原因,P 描述的是一个可能不存在的虚拟相机。

两个实用的细节

① 相机坐标系约定(Foxglove 官方原文):frame_id 字段说明里明确写了 "The origin of the frame is the optical center of the camera. +x points to the right in the image, +y points down, and +z points into the plane of the image.",原点在光心,x 右、y 下、z 指进画面。

② K[0] == 0 表示"未标定":Foxglove 沿用了 ROS 的约定 "Foxglove also treats K[0] == 0.0 as indicating an uncalibrated camera, and calibration data will be ignored." 这是个真实会咬人的坑:如果你的投影怎么都不对,先看一眼 K 是不是全零,被忽略了,不报错。

"投影模型"这一维:鱼眼为什么参数更多

Foxglove 支持的畸变模型(很好的证据):

distortion_model参数适用
plumb_bobk1, k2, p1, p2, k3(5 个)普通镜头
rational_polynomialk1…k8(8 个)超广角
kannala_brandtk1, k2, k3, k4(4 个)鱼眼,支持到 180° FOV
fisheye62k0…k3, p0, p1 (+crit_theta)超过 180° 的鱼眼(Project Aria 的模型)

注意最后两个是"投影模型",不是"畸变模型",这是两回事:

普通镜头:  先用针孔模型投影(x = X/Z),再叠加小畸变修正
鱼眼镜头:  针孔模型【根本不成立】(180° 的视场没法用 x=X/Z 表示)
            → 必须换一个"球面 → 平面"的映射函数本身
回到"投影"这个词的本义

"投影"(projection)这个词在相机领域,和"地图投影"是同一个词。

地球是球面  →  地图是平面  →  必须选一种"投影方式"
                              墨卡托 / 等积 / 等距 …

方向的球面  →  图像是平面  →  也必须选一种"投影方式"
                              等距 / 等积 / 等立体角 / 立体投影 …

鱼眼镜头的几种模型就是不同的球面→平面映射:

等距投影 (equidistant):   r = f·θ
等立体角 (equisolid):     r = 2f·sin(θ/2)
正交投影 (orthographic):  r = f·sin(θ)
立体投影 (stereographic): r = 2f·tan(θ/2)

每种都是一个不同的 r(θ) 函数,这就是"投影模型"。 所以鱼眼镜头的"投影参数"里,选对模型比调数字更重要。

二、鱼眼实例:内参、外参、投影参数的分工

具体画面:一辆车装了四台鱼眼镜头做 360° 环视,标定文件里躺着一串数字。 这串数字分成三堆,描述镜头自己怎么成像的(内参)、 描述它相对车身装在哪、朝向如何(外参)、 以及把像素还原成射线要用的那套规则(投影参数)。 下面这张表先给总览,后面逐项展开。

是什么具体内容数量
内参相机自身的映射fx, fy, cx, cy + k1, k2, k3, k4 + "kannala_brandt"8 个数 + 1 个字符串
外参相机相对于谁[R | t](4×4),例如 T_cam_lidar6 自由度
投影参数⚠️ 鱼眼没有单一的投影矩阵,只能拆成「内参 + 模型名 + 外参」三件套—

内参:8 个数 + 1 个字符串

fx = 600.0   fy = 600.0          // 焦距(像素)
cx = 960.0   cy = 960.0          // 主点(光心在图像上落在哪)
k1 = -0.05   k2 = 0.01
k3 = -0.002  k4 = 0.0005         // 投影/畸变系数
distortion_model = "kannala_brandt"   // 必须一起给,不能省
针孔鱼眼
系数个数k1 k2 p1 p2 k3(5 个,含切向 p1 p2)k1 k2 k3 k4(4 个,纯径向)
skew有时有没有
模型名一般默认 plumb_bob必须显式给

⚠️ 坑:鱼眼的 fx 和针孔的 fx 含义不一样

针孔:  u - cx = fx · (X/Z)        // fx 是【像素 / 单位斜率】
鱼眼:  u - cx = fx · θ_d        // fx 是【像素 / 弧度】

同一个符号,物理意义不同。小角度时两者几乎相等,所以看不出来;大角度时分道扬镳:

      θ(离轴角)          鱼眼            针孔       比值
  ------------------------------------------------------
         5°          52.3px          52.5px    0.997   ← 几乎一样
        10°         104.6px         105.8px    0.988
        20°         208.2px         218.4px    0.953
        30°         310.1px         346.4px    0.895   ← 开始分道
        45°         458.3px         600.0px    0.764
        60°         600.2px        1039.2px    0.578
        75°         736.7px        2239.2px    0.329
        89°         863.4px       34374.0px    0.025
        90°         872.7px          ∞               ← 针孔发散
  ------------------------------------------------------

所以:把鱼眼的 fx 塞进针孔公式,中心附近看不出问题,画面边缘会错得离谱。

外参:和普通相机定义一样

鱼眼在外参上的特别之处不在"定义",而在"使用场景":

场景外参需求
单目鱼眼 + LiDAR1 个外参
车载环视(4~6 个鱼眼)每个相机一个外参,且需要统一的参考系
全景拼接所有相机外参 + 重叠区对齐

车载环视是鱼眼的主场,因为要用尽量少的相机覆盖 360°,必须用超广角。

投影参数:鱼眼没有投影矩阵

用一个定义性质就能证明:3×4 投影矩阵的本质是「射影变换」, 而射影变换的定义性质是把直线映射成直线。所以只要找到一条 3D 直线, 投影后变弯了,就证明它不可能是任何 3×4 矩阵。

【偏离光轴的直线 (y=1.5, z=3, x:-6..6)】
  相机模型          离直线最大偏差          判定
  针孔                  0.000 px          直线 ✓
  鱼眼                 62.983 px          弯曲 ✗

【穿过光轴的直线 (x=0, z=3, y:-4..4)】   ← 对照组
  针孔                  0.000 px          直线 ✓
  鱼眼                  0.000 px          直线 ✓

鱼眼把一条直线弯了 63 像素。而图像才 1920px 宽,63px 是肉眼一眼可见的弯曲。 (鱼眼照片里常见的"门框/地平线朝外弯",就是这件事。)

为什么弯
针孔:  [u v w]¹ = P · [X Y Z 1]¹          // 全是乘加,【线性】
鱼眼:  r = √(a²+b²)
        θ = atan(r)                        // 超越函数
        θ_d = θ(1 + k1θ² + k2θ⁴ + k3θ⁶ + k4θ⁸)   // θ 的 4 次、8 次项

线性变换可以用矩阵表示;非线性变换不能。 这不是"还没找到合适的矩阵",是数学上的不可能。

而且穿过光轴的直线不会弯,因为沿这条线 θ 只是一维单调函数,不产生弯曲。 这顺便解释了一个现象:鱼眼的畸变看起来总是"径向"的, 所有的弯曲都发生在离轴的方向上。

P 的用武之地:校正之后

你手上是用哪些参数
鱼眼原图(带畸变)K + D + distortion_model,没有 P
已校正成针孔图P(3×4),因为那已经是一台虚拟针孔相机
鱼眼原图  ──[校正:为虚拟针孔相机逐像素采样]──►  针孔图
                                                      ↓
                                             这时的投影是线性的
                                             → 可以有 3×4 的 P

官方对 R 字段的说明正好印证:"一个旋转矩阵,把相机坐标系对齐到理想立体像平面, 使两台相机的极线平行。"

⚠️ 校正不是免费的

代价说明
丢视场针孔表示不了 180°。必须选一个更小的 FOV 来"装"进针孔模型
重采样损失逐像素插值,图像质量下降一次
超出 180° 更麻烦Foxglove 明确写了:kannala_brandt 只支持到 180°,超过 180° 要用 fisheye62

最后一条是硬约束:如果你的鱼眼 FOV > 180°,kannala_brandt 连校正都做不了。这不是精度问题,是模型本身在 θ→π 时退化。

三、交互演示:五种投影模型对比

下面五张图显示同一个世界网格(3D 空间里的直线方格)通过五种投影模型的样子。 所有模型都归一化到「θ_max 落在同一半径」,所以差别纯粹来自映射方式本身。

DEMO 4 · 五种投影模型对比 调视场角 · 切换网格 / 等角环

从演示里能读出的三件事

  1. 等距(equidistant)的环是均匀的,因为它的 r(θ) 是线性的。 其他所有模型的环都疏密不均,这就是"畸变"的可视化。
  2. 针孔(gnomonic)在中心极挤、边缘极疏 等价于说"针孔把边缘的面积放大得离谱"。
  3. 正射(orthographic)在边缘挤成一团,因为 sin(θ) 在 90° 附近导数为 0。

四、为什么不存在完美的畸变模型

原因有四层,一层比一层根本。

第一层(最根本):球面无法展平,这是个定理

先看一个具体画面:墨卡托世界地图上,格陵兰看起来和非洲差不多大;换成等积投影, 面积终于对了,但大陆的形状又被拉歪。每一张世界地图都在变形,只是变形的方式不同。

相机在做的事情是:
把「方向的球面」  ──映射──►  「平面的像面」
        ↑                          ↑
   高斯曲率 = 1/R² ≠ 0        高斯曲率 = 0

高斯绝妙定理 (Theorema Egregium):高斯曲率是内蕴量, 等距映射(保距映射)必须保持它。

定理

球面的高斯曲率 ≠ 0,平面 = 0 → 球面与平面之间不存在等距映射。

这不是"模型还不够好",这是微分几何里的一个定理。

而"投影"这个词的本义就在这里:地球是球面,地图是平面,必然变形 墨卡托保角度但面积失真,等积投影保面积但形状失真, 不存在同时保角又保面积的地图投影。

方向球面 → 图像平面,是同一件事。

第二层:参数模型的数值极限

最常见的 plumb_bob(Brown-Conrady)是这样的:

r_d(r) = r (1 + k1 r² + k2 r⁴ + k3 r⁶)        其中 r = tan(θ)

物理约束:离轴角越大 → 像素半径必须越大(单调递增)。 一旦多项式开始下降,就意味着"更大的角度 → 更小的半径",几何上不可能。

判据是解 dr_d/dr = 1 + 3k1·r² + 5k2·r⁴ = 0, 取首次失去单调的那个根:

  系数组                        k1     k2    首次失去单调 r      对应 FOV        判定
  --------------------------------------------------------------------------
  普通镜头 (35mm eq.)         -0.10   0.01           —      > 152°      单调 ✓
  广角 (24mm eq.)           -0.25   0.04           —      > 152°      单调 ✓
  超广角 (16mm eq.)          -0.40   0.05       1.0360      92.03°      崩溃 ✗
  更激进的超广角                 -0.50   0.10       1.0000      90.00°      崩溃 ✗
  --------------------------------------------------------------------------
单调性的判据是「首次过零」

描述"模型从哪一点开始失效",正确的量是导数第一次穿过零处的 r: 在它之前投影半径随离轴角单调递增(物理上成立),在它之后出现折叠(几何上不可能)。

对比另一个也"看起来合理"的量 argmin(dr_d/dr)(折叠最厉害的位置): 那个点落在折叠区间内部,模型早已失效,用它当判据会把崩溃点报得太晚。

多项式在这里还有一个病态行为(以 k1=-0.40, k2=0.05 为例):

第 1 个零点: r=1.0360  θ=46.01°  FOV=92.0°     ← 模型从这里开始失效
第 2 个零点: r=1.9305  θ=62.62°  FOV=125.2°    ← 又变回单调了

→ 在 r ∈ (1.0360, 1.9305) 区间内导数 < 0(非单调,"折叠")
→ 之后又恢复单调

一个"折叠后又展开"的投影模型显然不是物理的 这正是多项式拟合的典型病态:在拟合区间内表现很好,往外推就完全失控。

k1 越负(桶形畸变越强),单调性崩溃来得越早。 这就是为什么 plumb_bob 只适合中窄视场。

换成 θ 参数化就好很多:θ_d(θ) = θ(1 + k1θ² + …),关键优势是 θ 是有界的(θ ∈ [0, π]),而 tan(θ) 在 90° 就发散。

第三层:180° 的拓扑障碍

  theta =  170°  ->  像素半径   5293.5 px
  theta =  179°  ->  像素半径   7765.1 px
  theta =  180°  ->  像素半径   8109.3 px
  theta =  181°  ->  像素半径   8469.6 px   <-- 超过 180°,方向开始折返

原因在于:θ → 180° 时光线几乎从正后方来,投影映射不再是单射: 图像上的一个点可能对应两个方向(前面一个、后面一个)。这不是拟合不好,是拓扑退化。

第四层:就算理论够好,实践还是不够好

因素后果
每台相机的制造公差、装配偏心不同出厂标称参数只能参考,必须逐台标定
变焦镜头:畸变随焦距变化24mm 下标的参数,70mm 下不适用
对焦距离影响畸变(尤其近距)拍 0.3m 和拍 10m,畸变场不同
温度 → 镜筒和元件热胀冷缩车载场景冬夏差异可达可测级别
传感器封装倾斜引入不在模型里的非径向误差

要做到"完美",只能放弃函数形式:非参数化

做法说明
稠密畸变查找表 (dense LUT)存每个像素的位移量。640×480×2 floats ≈ 2.4 MB。相机 ISP 里真实就是这么干的
密网格 + 样条插值薄板样条 (TPS) 可以任意逼近
光学光线追迹直接用镜头的设计模型计算,不拟合

这是"完美"的(在采样精度内),因为它不假设任何函数形式。代价是: 存储大(相比 8 个浮点数)、不可解释(出问题不知道是哪个参数错了)、 不能外推(表里没有的方向就是没有)、每台相机/每个焦距/每个对焦距离都要一张表。

所以工程上永远是"参数化模型的近似" vs "非参数表的精确",前者赢在可用性。

五、投影模型全景表

它们分成两类,这个区分很重要:

A. 理想投影模型(对应真实的光学设计思路)

模型公式保住什么FOV
直线 (rectilinear)r = f·tan θ直线< 180°(实用 ~120°)
等距 (equidistant)r = f·θ角度→半径线性~180°
等立体角 (equisolid)r = 2f·sin(θ/2)面积> 180°
正交 (orthographic)r = f·sin θ—180°
立体 (stereographic)r = 2f·tan(θ/2)角度(共形)< 360°

B. 拟合模型(参数没有物理意义,纯粹是拟合)

下面按「多项式(或映射)建在哪个变量上」分组 这是决定 FOV 天花板的那一件事,比「有几个参数」重要得多。 最后一列标出你会在哪儿遇到它。

模型 参数 建在 实用 FOV 常见实现 / 说明
① tan θ 基:针孔 + 修正  →  天花板 < 180°
plumb_bob
= radtan / Brown-Conrady
k1 k2 p1 p2 k3 tan θ ≈ 120° ROS camera_calibration 默认、OpenCV CALIB_STANDARD、Kalibr pinhole-radtan、Colmap OPENCV、VINS / OpenVINS radtan
rational_polynomial k1…k6 p1 p2 tan θ
有理式
≈ 165° ROS rational_polynomial、OpenCV CALIB_RATIONAL。分母可能出奇点
thin_prism k1…k6 p1 p2 s1…s4 tan θ ≈ 170° OpenCV CALIB_THIN_PRISM、Colmap THIN_PRISM_FISHEYE。多 4 个薄棱镜项,治装配偏心
tilted 基础模型参数 + tauX tauY tan θ 同基础模型 OpenCV 4.5+ CALIB_TILTED。显式建模传感器不垂直于光轴
② θ 基:鱼眼多项式  →  天花板 180°,再往外要加项
equidistant
= Aria「Spherical」
fx fy cx cy θ 180° Kalibr pinhole-equi、OpenVINS / VINS equidistant、Colmap SIMPLE_RADIAL_FISHEYE 的基。只有一个解析式 r = fθ,没有多余参数
fov
Devernay–Faugeras
fx fy cx cy + ω θ
解析
≈ 180° Kalibr pinhole-fov、Colmap FOV。单个 ω 描述整个畸变场,极简
kannala_brandt
= KB4 / OpenCV fisheye
k1 k2 k3 k4 θ ≤ 180° OpenCV cv::fisheye、ROS fisheye、Kalibr kb4、Basalt KB4、Colmap OPENCV_FISHEYE。Foxglove 官方:支持到 180°
KB3
KannalaBrandtK3
k0 k1 k2 k3(9 阶) θ ≤ 180° Project Aria 的眼动相机用它。形式:r(θ) = θ + k0θ³ + k1θ⁵ + k2θ⁷ + k3θ⁹
fisheye62 k0 k1 k2 k3 p0 p1
+ crit_theta(可选)
θ + 切向 > 180° 就是 Project Aria 的 FisheyeRadTanThinPrism。Foxglove 明确写:超过 180° 就用它
fisheye624 6 径向 + 2 切向 + 4 薄棱镜 θ + 更多项 > 180° Aria 的完整版;nerfstudio 直接叫它 FISHEYE624,Blender Cycles 也加了它
③ 球面 / 统一模型(Unified):把像面当成球的一部分  →  > 180°
ucm
= omni (Mei)
ξ(+ 可选 k1 k2 p1 p2) 球面 ≈ 185° Kalibr omni-radtan。只多 1 个参数就跨过 180°,性价比最高的一个
eucm α β 球面 > 180° Kalibr eucm、Basalt EUCM。闭式反投影,工程上很好用
double_sphere
= DS / DS+
ξ α 双球面 > 180° Kalibr ds、Basalt DS。无三角函数,速度快
OCamCalib r(θ) 反函数多项式 + 仿射 c d e θ 的反函数 > 200° Scaramuzza。超大 FOV 的经典选择,但需要特制靶标
④ 非参数 / 全景
稠密 LUT 无参数 — 任意 OpenCV initUndistortRectifyMap + remap。不需要模型,但存储大、不可解释、不能外推
ERP / 等距柱状 — 球面 360° 全景相机。已经不是「相机模型」而是「球面展开」

为什么 FOV 有「天花板」,看模型建在哪个变量上

上面这张表最反直觉的一点是:一个模型能覆盖多广,主要不取决于它有「几个」参数, 而取决于它把多项式建在哪个变量上。

建在这个变量最大能到多少于是 FOV 天花板
tan θθ → 90° 时 趋向无穷永远到不了 180°
θ最大 π(= 180°),有界正好 180°
球面映射 / 反函数有界且平滑超过 180°

所以「换个模型」的本质,不是「多加几个参数」,而是换一个在更大的 θ 范围里不发散的映射。 表里最漂亮的反例就是 ucm:只多 一个 参数 ξ,就把天花板从 180° 抬到了 185° 以上。

0°60°120°180°220°
① tan θ 基  →  天花板 < 180°
针孔 (linear)
≈100°
plumb_bob
≈120°
rational_polynomial
≈165°
thin_prism
≈170°
② θ 基  →  天花板 180°,再往外要加项
equidistant
180°
fov (Devernay)
≈180°
kannala_brandt / KB3
≤180°
fisheye62
>180°
fisheye624
>180°
③ 球面 / 统一模型  →  跨过 180°
ucm / omni
≈185°
eucm
>180°
double_sphere
>180°
OCamCalib
>200°
④ 非参数 / 全景
稠密 LUT
任意
三个必须说清的前提

① 这里的 FOV 是「全视场角」(对角),不是半角。半角 = FOV ÷ 2。 180° 的全视场对应 90° 半角,正好是 tan 发散的地方。这就是那条黄色虚线的位置。

② 上面的「实用 FOV」是量级参考,不是硬规格。真正能标到多少还取决于镜头本身、靶标覆盖、标定质量。 「≈120°」的意思是再大就开始不划算了,不是「数学上不可能」。

③ 参数个数不决定覆盖面。ucm 只多 1 个参数就跨过了 180°; 而 rational_polynomial 有 8 个,仍然过不去。 决定因素是「建在哪个变量上」,不是「有几项」。

A 类是"设计一个这样的镜头",B 类是"拟合一个已有的镜头"。 而 B 类不可能完美,原因就是第一层:用一个有限维函数族去拟合一个任意光滑的畸变场, 只有当真实畸变恰好落在这个函数族里才能精确,而它不会。

六、为什么这跟 π 是不是无理数无关

先做一个手边就能做的实验:把一张纸卷成圆柱面,纸能平顺贴合,一个褶皱都没有; 把同一张纸拿去包一个球,无论怎么剪、怎么压,总会起皱。 而圆柱的周长公式 2πr 里,明晃晃地就带着 π。

把纸卷成圆柱   → 平滑贴合,一个褶皱都没有
把纸卷成圆锥   → 平滑贴合,一个褶皱都没有
把纸包住一个球 → 【必然起褶皱】,怎么剪都不行

每个试过用包装纸包球的人都知道这件事。而且注意: 这个现象跟用什么单位、算到多少位小数,完全无关,它就是不行。

所以本节的结论可以直接看出来:π 在不在场,和"能不能零失真展平"是两件无关的事。 下面把这个手感换成能逐项核对的数字。

决定性反例:圆柱和圆锥满是 π,却能零失真展平

圆柱侧面:
    周长 = 2πr                    ← 含 π
    高斯曲率 K = 0                ← 可展曲面
    沿一条母线剪开 → 展平成矩形     ← 零失真,精确

圆锥侧面:
    底圆周长 = 2πr                ← 含 π
    高斯曲率 K = 0                ← 可展曲面
    沿一条母线剪开 → 展平成扇形     ← 零失真,精确

π 就在里面,但它们展平完全没有失真。 可展与不可展的分界在曲率(K=0 vs K≠0),不在 π 在不在场。

两类不同的「不可能」
π 的无理性球面无法展平
是什么问题精度 / 可构造性存在性
说的是"精确数值写不出来""那个映射根本不存在"
提高精度有用吗✅ 有用❌ 完全没用

高斯-博内定理:π 在等号两边,它约掉了

    ∫∫ K dA  =  2π χ
     ↑            ↑
  高斯曲率积分   欧拉示性数(拓扑量)

球面: K=1/R², χ=2  →  左边积出 4π,右边 2π·2 = 4π
平面: K=0,    χ=0  →  左边 0,右边 0

π 在等式两边都出现,它是个公共因子。真正区分球面和平面的, 是 K≠0 vs K=0 和 χ=2 vs χ=0 一个是曲率(几何),一个是拓扑。

三角形内角和:最直观的证据

  边长 s           内角和      平面值 180°           超出量
  ------------------------------------------------------------------
       1°     180.0076°           180°       0.0076°
       5°     180.1891°           180°       0.1891°
      10°     180.7586°           180°       0.7586°
      30°     187.0437°           180°       7.0437°
      60°     211.5863°           180°      31.5863°
      90°     270.0000°           180°      90.0000°
  ------------------------------------------------------------------
平面三角形的内角和 = 恰好 π
球面三角形的内角和 = π + 超出量

π 在等号两边都有,它是基准线,不是差异。差异是那个超出量 (spherical excess),它等于三角形的面积。

而且这个实验顺便解释了"为什么小角度时鱼眼 ≈ 针孔": 边长 1° 时超出量只有 0.0076°,球面局部看起来就是平的。 差异不是来自"π 算不精确",是来自"曲率累积起来了"。

反例的另一面:无理数确实会造成另一类「不可能」

例子为什么不可能
化圆为方π 是超越数(Lindemann 1882)→ 尺规作不出来
无理旋转转 π 的无理数倍 → 格点不再映射到格点(离散对称被破坏)
精确等分任意角涉及不可构造数
精确的十进制表示π 的小数位永不终止

但这些全是「构造问题」或「离散对称问题」,不是「映射存在性问题」。

化圆为方:  『造不出那个正方形』          ← 存在,但造不出来(可构造性)
展平球面:  『那个映射根本不存在』        ← 不存在(存在性)
判别方法

一个简单的判别标准:提高精度 / 用更强的计算能力,能不能解决它?

能 → 精度问题(π 的无理性在这一类)
不能 → 存在性问题(球面展平在这一类)

球面展平,哪怕给无限精度、无限算力、上帝的计算器,也做不到。

七、和地图投影是同一套数学

下面这张表可以直接对位读:左边是镜头投影模型,右边是制图学里的方位投影。

不是"类似",是"同一批公式"
镜头投影模型对应的地图方位投影说明
gnomonic日晷投影 / 球心投影针孔相机就是这个
stereographic球极投影(保角)鱼眼镜头的一种
equidistant等距方位投影最常见的鱼眼
equisolidLambert 等积方位投影与前者只差系数 2
orthographic正射投影180° 鱼眼的极限形态

光学和制图学各自独立发现了同一批数学。这不是巧合 因为两者在解决同一个问题:把球面摊平到平面。

把"取舍"量化:面积放大率

面积放大率 = r(θ)·r'(θ) / sin(θ),等于 1 表示"面积不失真":

    θ       gnomonic  stereographic    equidistant      equisolid   orthographic
  ------------------------------------------------------------------------------
     10°          1.047          1.015          1.005          1.000          0.985
     20°          1.205          1.063          1.021          1.000          0.940
     30°          1.540          1.149          1.047          1.000          0.866
     40°          2.225          1.282          1.086          1.000          0.766
     50°          3.765          1.482          1.139          1.000          0.643
     60°          8.000          1.778          1.209          1.000          0.500
     70°         24.995          2.221          1.300          1.000          0.342
     80°        190.981          2.904          1.418          1.000          0.174
  ------------------------------------------------------------------------------
模型保住什么牺牲什么FOV
gnomonic / 针孔保直线面积 80° 放大 191 倍实用 < ~120°
stereographic保角度/形状面积 80° 放大 2.9 倍可到 ~360°
equidistant角度→半径线性面积 80° 放大 1.42 倍~180°
equisolid保面积严格 = 1> 180°
orthographic—边缘压缩到 0.17恰 180°

191 倍这个数字解释了为什么针孔做不了广角 画面角落的一个像素代表的世界面积,是画面中心的 191 倍。这就是"针孔广角的边缘拉伸"。

不可能三角(可以严格证明)

  假设一个投影【同时】保角和保面积:
    保角  → 局部线性缩放因子 λ(θ) 各方向相同
    保角  → 面积缩放因子 = λ²      // 因为两个方向都缩放 λ
    保面积 → 面积缩放因子 = 1
    => λ² = 1  =>  λ = 1 处处成立
    => 这就是【等距映射】
    => 但球面到平面不存在等距映射(高斯绝妙定理)
    => 矛盾。□

  所以:保角、保面积、保距 三者【至多取一】。

八、球面到平面 vs 平面到球面:「方向反了」为什么不成立

想判断"信息有没有丢",最直接的办法是跑一遍往返:鱼眼把方向投成像素、再反解回方向; 地图把经纬度投到平面、再反查回经纬度。两组实验的结果如下。

实验 A:鱼眼 —— 方向 → 像素 → 方向
    2000 个方向往返
    最大角误差 = 1.479e-06 度      ← 数值精度级别
    >>> 方向【完全可以精确还原】,鱼眼画面没丢任何方向信息

实验 B:地图 —— 经纬度 → 平面 → 经纬度
    墨卡托往返
    最大纬误差 = 3.817e-14 度      ← 解析逆函数,精确
    >>> 地图同样【完全可以反查经纬度】

两组数字都回到数值精度级别:两个方向都是精确可逆的。 墨卡托的逆函数是写得出公式的:φ = 2·atan(e^y) - π/2。 镜头也一样,像素反解方向就是数值反解 θ_d(θ),而它是单调的,所以逆唯一。

所以「方向反了」这个说法并不成立,真正的差别不在方向,而在别的维度上。 把两类不同的"还原不了"放在一起对照,混乱就消失了。

"不可能"从来不是关于可逆性的,而是关于度量的
可逆性(能不能反查)
  → 地图 ✅    镜头 ✅
  → 两者都没问题

度量(能不能保住 距离/面积/角度)
  → 地图 ❌    镜头 ❌
  → 高斯绝妙定理:三者至多保一个

✓ 但这两件事【毫无关系】

一个映射可以完全可逆,同时严重失真。墨卡托就是这样:能精确查回经纬度, 但格陵兰在地图上跟非洲一样大。

真正的混乱来源:有两个不同的"无法还原"

① 度量失真② 深度丢失
谁有地图和镜头共有只有相机有,和地图完全无关
内容不能同时保住 保角 / 保面积 / 保距一个像素 = 一条射线 = 无穷多个 3D 点
丢信息吗不丢,正反向都可逆丢了深度
和投影模型的关系正是投影模型在描述的毫无关系,哪怕数学上完美的模型也还原不出深度
"还原不了"指的是什么?
  → 还原出【方向】(射线)   ✅ 能,精确可还原
  → 还原出【3D 点】(位置)  ❌ 不能,但原因是【缺深度】,不是投影失真

地图没有对应的第二类问题 —— 地图不装深度,它只有"度量失真"这一件事。

唯一真实的不对称:切缝

FOV ≤ 180°(普通相机 / 鱼眼):
    半球  →  圆盘
    双射,【不需要切缝】
    ✅ 比地图还【好处理】—— 因为只覆盖半个球

FOV = 360°(全向相机 / 等距柱状全景图):
    整球  →  矩形
    【必须切缝】—— 等距柱状图的左右两条边缘,就是"日期变更线"
    ⚠️ 这时和地图问题【完全同构】

半球不需要切缝,原因在曲面的开闭:

球面是【闭曲面】(紧致无边)
    → 连续映射到有界的平面区域,必然"粘"在一起
    → 必须切一刀才能摊开(否则所有经线在极点挤成一团)

半球是【开曲面】(有边界)
    → 边界正好对应图像的外圈
    → 天然可以摊开,不需要切
精确的说法

不是"方向反了",而是"覆盖范围不同"。

覆盖半球时,相机反而比地图简单(不用切缝);覆盖整球时,两者完全一样。

这也顺便解释了 360° 全景图为什么上下两端被拉得那么可怕 那正是世界地图在两极的畸变,是同一个现象。

完整对位表

地图制作者相机使用者
有球面(地球)平面(图像)
想要平面(地图)球面(方向)
能正向映射✅✅
能反查✅ φ = 2atan(e^y) - π/2✅ 数值反解 θ_d(θ)
丢信息吗❌ 不丢❌ 不丢(方向层面)
不可能在哪保角/保面积/保距至多一个同一条定理
额外难题整球必须切缝① FOV≤180° 无需切缝(比地图简单)
② 丢深度(与投影无关)

九、实践中的选型决策

① 按 FOV 选模型:
     < 90°    → plumb_bob(最通用,工具链支持最全)
     < 180°   → kannala_brandt / rational_polynomial
     > 180°   → fisheye62 / double_sphere / OCamCalib
     需要研究级精度 → OCamCalib 或稠密 LUT

② 按最在乎的性质选:
     保直线        → 直线透镜(但 FOV 受限)
     保面积        → 等立体角
     保形状(共角)  → 立体投影
     纯测量精度    → 等距

③ 按验收标准选:
     看【重投影误差在画面边缘有多大】
     边缘误差明显大于中心 → 模型阶数不够 or 模型类型不对
诊断决策树里的一条硬结论

"中心对齐、边缘错位"的成因里有一条是模型族选错了。

而且这一条不能靠调参数解决,参数再优化也跳不出函数族。必须换模型。

一句话总结
投影参数属于谁:
  只有「输出降维且不可逆」的传感器 —— 也就是【测不到深度】的
  相机 ✅   LiDAR ❌   IMU/编码器 ❌
  标准形态 P = K[R|t](3×4),只对针孔类模型存在

鱼眼:
  内参 = fx fy cx cy + k1..k4 + 模型名(8 个数 + 1 个字符串)
  外参 = [R|t],和普通相机一样
  投影参数 = 没有矩阵 —— 投影是非线性的,直线会弯 63px
            只有【校正成针孔】之后才有 P,代价是丢 FOV + 重采样

为什么没有完美模型(四层):
  ① 数学:球面无法无失真展平(高斯绝妙定理)—— 定理,不是工程问题
  ② 数值:多项式会单调性崩溃(超广角在 92.03° 附近就崩)
  ③ 拓扑:θ→180° 时映射非单射
  ④ 工程:每台相机不同、随焦距/对焦/温度变化

不是 π 的锅:
  圆柱/圆锥满是 π,却零失真展平 → π 在场 ≠ 不能展平
  π 在高斯-博内等式两边都有,约掉了
  球面三角形内角和 = π + 超出量 → π 是基准,超出量才是差异
  拿纸包球必然起皱,跟算多少位无关
  区分:精度问题(π) vs 存在性问题(展平)

和地图投影:
  同一批公式。针孔相机 = 日晷投影(gnomonic)
  不可能三角:保角/保面积/保距 至多取一
  两者【都可逆】,不可能的不是可逆性,是度量
  真正的不对称是【切缝】:FOV≤180° 半球不需要切(比地图简单)
                        FOV=360° 整球必须切(和地图完全同构)
← 06 内外参与投影
下一模块 08 算法流程与模型架构 →
← 上一页 ·  下一页 →
京ICP备19013239号