相机标定_角点检测_重投影误差_总结

相机标定、棋盘格角点检测与重投影误差通俗总结

目录

  1. 标定到底在做什么
  2. 棋盘格为什么有自己的坐标系
  3. 斜着拍时为什么棋盘格坐标的 Z 仍为 0
  4. OpenCV 的"实际检测角点"是什么
  5. 没有畸变参数时怎样检测角点
  6. "模型预测角点位置"是什么意思
  7. 预测时输入序号还是具体坐标
  8. 检测点不是真值,为什么还能标定
  9. 左目、右目和双目 RMS 的原理
  10. RMS 和极线误差的区别
  11. 去畸变前后对角点检测的影响
  12. 完整标定流程
  13. 最核心的理解

1. 标定到底在做什么

相机标定的目的,是找到一套数学参数,尽可能准确地描述真实相机的成像过程。

主要参数包括:

  • 焦距:fx、fy
  • 主点:cx、cy
  • 畸变参数:k1、k2、p1、p2、k3...
  • 每张标定图中棋盘格相对于相机的旋转和平移:Ri、ti

可以把整个过程理解为:

text 复制代码
已知棋盘格在现实中的规则结构
+
检测棋盘格角点在照片中的像素位置
+
建立一个虚拟相机模型
        ↓
不断调整相机参数
        ↓
让虚拟相机预测的位置尽量靠近照片中的检测位置

2. 棋盘格为什么有自己的坐标系

棋盘格是一块尺寸已知、平整、不会变形的标定板。

假设每个格子边长是 30 mm,可以人为把第一个内部角点定义为原点:

text 复制代码
编号0       编号1       编号2
(0,0,0)    (30,0,0)    (60,0,0)

编号3       编号4       编号5
(0,30,0)   (30,30,0)   (60,30,0)

每个角点都有一个具体的三维坐标:

P_{board}=(X_b,Y_b,Z_b)

因为所有角点都在同一块平板上,所以:

Z_b=0

这里的 Zb=0 只表示:

角点没有离开棋盘格平面。

它不表示角点距离相机为 0。


3. 斜着拍时为什么棋盘格坐标的 Z 仍为 0

这是两个不同坐标系的问题。

3.1 棋盘格坐标系

无论棋盘格怎么移动和旋转,某个角点在棋盘格自身坐标系里的位置不变。

例如:

P_b=(60,30,0)

你把棋盘格正放、斜放、竖放,这个角点依然是 (60,30,0),因为它相对于棋盘格原点没有移动。

3.2 相机坐标系

同一个点在相机坐标系中的位置为:

P_c=RP_b+t

其中:

  • R:棋盘格相对于相机的旋转
  • t:棋盘格相对于相机的平移
  • Pc=(Xc,Yc,Zc):角点在相机坐标系中的坐标

斜着拍时,虽然所有角点的棋盘格坐标 Zb=0,但它们在相机坐标系中的深度 Zc 通常不同。

例如:

text 复制代码
棋盘格左侧角点:Zc = 900 mm
棋盘格右侧角点:Zc = 1100 mm

所以:

text 复制代码
棋盘格坐标系中的 Zb = 0
不等于
相机坐标系中的 Zc 相同

4. OpenCV 的"实际检测角点"是什么

标准标定时,OpenCV 直接在原始、带畸变的图像中检测角点。

text 复制代码
原始带畸变图像
        ↓
转为灰度图
        ↓
检测黑白棋盘格交叉位置
        ↓
得到角点的二维像素坐标

例如:

p_{obs}=(500.4,300.2)

它表示:

OpenCV 在原始照片中观察到,这个棋盘格交叉点位于横坐标 500.4、纵坐标 300.2。

坐标可以是小数,因为 OpenCV 可以使用亚像素优化,例如 cornerSubPix

"实际检测位置"更准确的叫法是:

观测位置。

它不是绝对无误的真值,仍然可能受到模糊、噪声、反光等影响。


5. 没有畸变参数时怎样检测角点

角点检测不需要提前知道焦距或畸变参数。

它主要依赖局部像素的亮暗变化。

棋盘格角点附近通常是:

text 复制代码
白 白 白 │ 黑 黑 黑
白 白 白 │ 黑 黑 黑
─────────┼─────────
黑 黑 黑 │ 白 白 白
黑 黑 黑 │ 白 白 白

它的特点是:

  • 水平方向亮度明显变化
  • 垂直方向亮度也明显变化
  • 四个象限呈现黑白交替结构

可以通俗地理解为:

text 复制代码
只有一个方向亮度变化明显 → 边缘
两个方向亮度都变化明显   → 角点

镜头畸变会把角点搬到别的位置,也会让方格发生变形,但局部的黑白交叉结构通常仍然存在,因此 OpenCV 可以直接在原始图中检测。


6. "模型预测角点位置"是什么意思

模型预测不是再看一次图像,而是一个纯数学计算。

假设某个角点在棋盘格坐标系中的位置是:

P_b=(60,30,0)\\text{ mm}

OpenCV 当前有一套估计参数:

text 复制代码
相机内参:fx、fy、cx、cy
畸变参数:k1、k2、p1、p2...
棋盘格姿态:R、t

它进行以下计算:

text 复制代码
棋盘格三维坐标 (60,30,0)
        ↓ 使用 R、t
转换到相机坐标系
        ↓ 使用 K
进行针孔透视投影
        ↓ 使用 D
加入镜头畸变
        ↓
得到原始图中的预测像素位置

例如预测得到:

p_{proj}=(500.9,299.8)

这表示:

如果当前的焦距、主点、畸变和棋盘格姿态都是正确的,那么这个角点应该出现在原始照片的 (500.9,299.8)

预测时会加入畸变,因为预测结果要和原始畸变图中的观测位置比较。


7. 预测时输入序号还是具体坐标

真正参与投影计算的是角点的具体三维坐标,不是单独的序号。

例如:

text 复制代码
编号6
对应棋盘格三维坐标:(60,30,0) mm
对应图像观测坐标:  (500.4,300.2) px

序号的作用只是保证三维点和二维点正确配对:

text 复制代码
object_points[6] ↔ image_points[6]

例如:

python 复制代码
object_points = [
    [0,  0, 0],
    [30, 0, 0],
    [60, 0, 0],
    [0, 30, 0],
    [30,30, 0],
    [60,30, 0],
]

二维检测结果:

python 复制代码
image_points = [
    [220.3,180.1],
    [265.7,176.8],
    [309.4,173.2],
    [224.8,221.5],
    [269.1,217.3],
    [312.2,213.0],
]

真正的几何对应关系是:

text 复制代码
(60,30,0) mm ↔ (312.2,213.0) px

8. 检测点不是真值,为什么还能标定

你的疑问是:

如果角点检测本身有误差,OpenCV 让预测结果靠近错误检测点,不就学错了吗?

答案是:

会受到影响,但 OpenCV 不是只依赖一个点,而是利用大量角点和大量图片寻找整体最合理的参数。

例如:

text 复制代码
30 张图片
每张 54 个角点
总共 1620 个二维观测

不同角点的检测误差可能是:

text 复制代码
角点1:偏左 0.2 px
角点2:偏右 0.3 px
角点3:偏上 0.1 px
角点4:偏下 0.2 px

如果这些误差主要是随机的,它们不会全部把参数推向同一个错误方向。

同时,一套相机参数必须解释:

  • 所有角点
  • 所有图像位置
  • 所有距离
  • 所有倾斜角度

某一套错误参数也许能很好解释一张图片,但很难同时解释几十张不同姿态的图片。

因此 OpenCV 做的是:

找到一套让全部观测总体误差最小的参数,而不是让某一个点完全重合。

但如果存在系统性错误,例如:

  • 棋盘格不平整
  • 棋盘格打印尺寸不准
  • 图像普遍严重模糊
  • 所有角点都因反光向同一方向偏
  • 标定板只出现在图像中央
  • 使用了错误的镜头模型

那么标定结果确实可能有偏差。

所以 RMS 小不代表绝对真值正确,只代表模型对当前检测数据拟合得较好。


9. 左目、右目和双目 RMS 的原理

9.1 单个角点误差

假设观测位置:

p_{obs}=(500.4,300.2)

模型预测位置:

p_{proj}=(500.9,299.8)

横向误差:

\\Delta u=500.4-500.9=-0.5

纵向误差:

\\Delta v=300.2-299.8=0.4

单个角点的二维重投影误差:

e=\\sqrt{(\\Delta u)\^2+(\\Delta v)\^2}

代入:

e=\\sqrt{(-0.5)^2+0.4^2}\\approx0.64\\text{ px}

9.2 整体 RMS

所有角点的误差平方后求平均,再开平方:

[

\mathrm{RMS}

\sqrt{

\frac{

\sum_{i=1}^{N}

\left(u_i-\\hat u_i)\^2+(v_i-\\hat v_i)\^2\\right

}{N}

}

]

先平方的原因是:

  • 正负误差不会互相抵消
  • 大误差会受到更强惩罚

9.3 左目 RMS

例如:

text 复制代码
left_rms_px = 0.54196

表示:

所有左目标定图、所有左目角点的观测位置与预测位置之间,整体 RMS 约为 0.542 像素。

9.4 右目 RMS

例如:

text 复制代码
right_rms_px = 0.50535

表示:

所有右目标定图、所有右目角点的观测位置与预测位置之间,整体 RMS 约为 0.505 像素。

9.5 双目 RMS

例如:

text 复制代码
stereo_rms_px = 0.55299

在固定左右内参时,OpenCV 主要估计左右相机之间固定的外参:

R_{left\\rightarrow right},\\quad T_{left\\rightarrow right}

同时要求:

text 复制代码
同一块棋盘格
+
同一对左右图
+
固定的左右内参
+
所有图片共用同一个双目 R、T

能够同时解释左右图中的角点。

所以双目 RMS 是:

左右相机所有重投影误差,在统一双目刚性关系约束下的整体 RMS。

双目 RMS 比单目 RMS 略大是正常现象,因为双目标定增加了约束,自由度更少。


10. RMS 和极线误差的区别

重投影 RMS 衡量的是:

text 复制代码
已知棋盘格三维点
→ 使用 K、D、R、t 投影到图像
→ 和实际检测点比较

极线误差衡量的是双目矫正后:

e_{epi}=\|v_L^{rect}-v_R^{rect}\|

指标 含义
左目 RMS 左相机模型对左目角点的拟合程度
右目 RMS 右相机模型对右目角点的拟合程度
双目 RMS 固定双目刚性关系后,左右联合拟合程度
极线误差 双目矫正后对应点是否位于同一水平线

因此:

\\text{stereo RMS}\\neq\\text{极线误差}


11. 去畸变前后对角点检测的影响

不能简单说完全没有影响。

11.1 角点是否还是同一个

是同一个物理角点,但它在两个图像坐标系中的位置不同。

例如:

text 复制代码
原始畸变图中: (500.4,300.2)
去畸变图中:   (520.1,306.5)

这不代表一个对、一个错,只是坐标系不同。

11.2 检测成功率

畸变较小时:

text 复制代码
原图可以检测
去畸变图也可以检测

差别可能不大。

畸变很大时,边缘方格会严重拉伸、压缩或弯曲,去畸变后形状变规则,可能提高检测成功率。

11.3 定位精度不一定提高

去畸变需要重映射和插值:

text 复制代码
原始像素
→ 映射到新位置
→ 新位置不是整数像素
→ 使用附近像素进行插值

这可能导致:

  • 边缘变软
  • 插值模糊
  • 噪声重新分布
  • 边缘区域被拉伸

所以去畸变后,几何形状更规则,但不保证角点亚像素定位一定更准确。

定位精度可能:

  • 提升
  • 基本不变
  • 略微下降

11.4 标定时为什么使用原始图

标准流程仍然是:

text 复制代码
原始畸变图
→ 直接检测角点
→ 拟合 K、D

原因是:

  • 原图是传感器直接采集的数据
  • 没有额外重采样
  • 标定本来就是要学习原始图的畸变
  • 在求出畸变参数前,也无法正确去畸变

12. 完整标定流程

12.1 数据准备

已知棋盘格:

  • 内部角点行列数
  • 每个格子的真实尺寸
  • 棋盘格为平面刚体

生成棋盘格三维坐标:

text 复制代码
(0,0,0)
(30,0,0)
(60,0,0)
...
(0,30,0)
(30,30,0)
...

12.2 在原始图中检测角点

text 复制代码
原始带畸变图
→ 根据黑白像素变化检测角点
→ 亚像素优化
→ 得到 imagePoints

12.3 建立对应关系

text 复制代码
棋盘格三维点 objectPoints
            ↕
图像二维观测 imagePoints

12.4 优化参数

OpenCV 同时估计:

text 复制代码
所有图片共享:
K、D

每张图片独立:
Ri、ti

目标是让:

text 复制代码
三维点经过 R、t、K、D 投影后的预测位置
尽量靠近
图像中检测到的观测位置

12.5 输出结果

输出:

  • 相机内参
  • 畸变参数
  • 每张图片的棋盘格姿态
  • 重投影 RMS

双目标定还会输出:

  • 左右相机之间的旋转 R
  • 左右相机之间的平移 T

12.6 独立验证

不要只看 RMS,还应使用未参与标定的新图片验证:

  • 去畸变后直线是否变直
  • 双目矫正后极线是否水平
  • 中央与四角误差是否一致
  • 已知尺寸测量是否准确
  • 动态情况下是否受同步和滚动快门影响

13. 最核心的理解

13.1 三种坐标不要混淆

text 复制代码
棋盘格坐标:
角点在标定板上的真实位置
例如 (60,30,0) mm

相机坐标:
角点相对于相机的位置
例如 (-120,-50,900) mm

图像坐标:
角点在照片中的像素位置
例如 (500.4,300.2) px

它们之间的关系是:

P_c=RP_b+t

然后:

P_c\\xrightarrow{K,D}p_{image}

13.2 角点检测与相机参数是两件事

text 复制代码
角点检测:
从照片的黑白像素变化中找到交叉点
不需要 K、D

模型预测:
使用棋盘格三维坐标、R、t、K、D
计算角点应该出现在原图哪里

13.3 畸变位置不是错误位置

原始畸变图中的角点位置,是镜头真实成像后的结果。

标定要学习的是:

什么样的镜头模型,能够把规则棋盘格投影成照片中观察到的样子。

13.4 标定结果是估计值

OpenCV 并不知道绝对真值,它利用:

text 复制代码
已知的棋盘格几何结构
+
大量二维观测
+
不同角度、距离和图像区域
+
相机成像模型

求出一套整体最合理的参数。


最终一句话总结

棋盘格告诉 OpenCV 每个角点在现实中怎么排列;原始图像告诉 OpenCV 这些角点经过真实镜头后落在了哪些像素位置;标定程序则不断调整焦距、主点、畸变和棋盘格姿态,让虚拟相机的预测尽量贴近真实图像中的观测。

相关推荐
u0103055271 小时前
智能素材归档检索Agent实战方案腾讯元气6G参赛
人工智能
大模型momo1 小时前
AI 编程工程化:从 Prompt 到 Harness
人工智能·prompt·编程·agent
小白说大模型1 小时前
Python 工程化设计模式:AI 项目中的异步流水线与策略模式实战
人工智能·python·设计模式
来者皆善1 小时前
【位RAW图像处理五】任意位深位图像的中值模糊快速实现及其应用。
图像处理·人工智能·算法
happyprince1 小时前
第三观 · 深刻不忘观 —— AngelSpec 哲学与升华
人工智能·算法
AI多Agent协作实战派1 小时前
AI多Agent协作系统实战(二十八):顶栏统一战争——从1个页面异常到31个页面全量对齐
数据库·人工智能·uni-app
Kevinten101 小时前
OpenOctopus:领域原生 AI 家庭助手系统,Summon 功能将实体转化为智能 Agent
人工智能·ai·开源·开发工具·智能体
zdl6862 小时前
EasyMarkets:“芯片波动考验科技估值”
数据库·人工智能·科技
阿童木写作2 小时前
TikTok Shop视频翻译工具实战测评
人工智能·python·音视频