3. 相机模型与内参

做3D视觉的人,天天跟相机打交道。但说实话,很多人用了很久的相机,对相机到底怎么成像的,还是一知半解。我刚开始做Halcon标定时也踩过不少坑,后来才明白——搞懂相机模型和内参,是深度图标定的地基。地基不稳,后面全白搭。

这一章,咱们就把针孔模型、畸变模型、内参矩阵这几个核心概念彻底讲透。我会结合项目经验,告诉你每个参数到底在说什么,以及它们怎么影响你的点云精度。

3.1 针孔模型:相机成像的“理想世界”

先问个问题:相机是怎么把三维世界“拍”成二维图像的?

最经典的模型就是针孔模型。说白了,它假设光线从物体出发,穿过一个小孔,投射到后面的成像平面上。这个小孔就是光心,成像平面就是传感器。

这个模型有三个关键坐标系:

  • 世界坐标系:物体在真实世界的位置,单位是mm或m
  • 相机坐标系:以光心为原点,Z轴指向物体方向
  • 图像坐标系:成像平面上的像素位置,单位是pixel

从世界坐标到像素坐标,中间经历两次变换:

  1. 刚体变换:世界坐标 → 相机坐标(旋转+平移,即外参)
  2. 透视投影:相机坐标 → 图像坐标(用内参矩阵)

透视投影的公式很简单:

x = f * (X / Z)
y = f * (Y / Z)

其中f是焦距,X、Y、Z是相机坐标系下的坐标。你看,Z在分母上——这就是“近大远小”的数学本质。

我的经验: 针孔模型是理想情况,实际相机都有畸变。但标定时,我们先用针孔模型做初始估计,再拟合畸变参数。这个顺序不能乱。

3.2 畸变模型:现实世界的“不完美”

理想很丰满,现实很骨感。实际镜头不是完美的小孔,光线穿过透镜会发生折射,导致图像变形。这就是畸变。

畸变主要分两类:

畸变类型 表现 数学模型 典型参数
径向畸变 直线变弯,越靠近边缘越明显 多项式:k1, k2, k3 桶形畸变(负值)、枕形畸变(正值)
切向畸变 镜头与传感器不平行,图像倾斜 p1, p2 镜头装配误差导致

径向畸变的校正公式:

x_corrected = x * (1 + k1*r² + k2*r⁴ + k3*r⁶)
y_corrected = y * (1 + k1*r² + k2*r⁴ + k3*r⁶)

其中r是像素到光心的距离。你看,r越大(越靠边缘),畸变越严重。

避坑指南: 我曾经在一个项目中,用广角镜头做深度图标定,只用了k1和k2两个参数,结果边缘误差一直降不下来。后来加上k3,误差直接减半。记住:广角镜头必须用3个径向畸变参数。

3.3 内参矩阵:相机的“身份证”

内参矩阵,说白了就是相机的“出厂配置”。它描述了相机内部的光学特性,一旦标定好,只要焦距和分辨率不变,内参就不变。

内参矩阵的数学形式:

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

每个参数的物理意义:

参数 物理意义 单位 典型值(以1920×1080为例)
fx x方向焦距(像素单位) pixel ~1200-1400
fy y方向焦距(像素单位) pixel ~1200-1400
cx 主点x坐标(光心在图像上的位置) pixel ~960
cy 主点y坐标 pixel ~540

这里有个关键点:fx和fy通常不相等。为什么?因为传感器像素不一定是正方形。我见过很多新手以为fx=fy,结果标定出来的点云在x和y方向尺度不一致。

核心理解: 内参矩阵的本质,是把相机坐标系下的三维点,映射到图像坐标系下的二维像素点。它决定了“一个三维点,到底落在图像的哪个像素上”。

3.4 从内参到深度图标定:为什么重要?

你可能会问:内参跟深度图标定有什么关系?

关系大了。深度图标定的核心,就是建立深度值(Z)与像素坐标(u,v)之间的映射关系。而这个映射,必须以内参矩阵为基础。

具体来说:

  1. 内参矩阵告诉你每个像素对应的光线方向
  2. 深度图告诉你该方向上的距离
  3. 两者结合,才能算出三维坐标

公式如下:

X = (u - cx) * Z / fx
Y = (v - cy) * Z / fy
Z = 深度值

你看,如果fx、fy、cx、cy标不准,算出来的X、Y坐标全错。这就是为什么我反复强调:内参标定是深度图标定的第一步,也是最关键的一步。

我的习惯: 每次做深度图标定前,我都会先用Halcon的calibrate_cameras算子重新标定一次内参。哪怕相机参数没变,也建议每半年重新标定一次——温度、振动都会让内参漂移。

3.5 知识结构总览

为了让你更直观地理解这一章的知识体系,我画了一张结构图:

相机模型与内参知识体系 相机模型 针孔模型 畸变模型 内参矩阵 透视投影:x = f·X/Z 三个坐标系:世界→相机→图像 径向畸变:k1, k2, k3 切向畸变:p1, p2 fx, fy:焦距(像素单位) cx, cy:主点坐标 深度图标定:内参 + 深度值 → 三维坐标 核心公式:X = (u - cx) * Z / fx, Y = (v - cy) * Z / fy 内参不准 → 三维坐标全错 → 点云精度崩盘

3.6 Halcon中的内参标定实战

理论讲完了,咱们看看Halcon里怎么操作。我个人习惯用标定板法,精度最高。

核心算子就这几个:

* 创建标定数据模型
create_calib_data ('calibration_object', 1, 1, CalibDataID)

* 设置相机内参初始值
set_calib_data_cam_param (CalibDataID, 0, 'area_scan_division', [0.008, 0, 0.000008, 0, 0, 640, 480, 1280, 960])

* 添加标定板描述
set_calib_data_calib_object (CalibDataID, 0, 'caltab_30mm.descr')

* 标定
calibrate_cameras (CalibDataID, Errors)

* 获取标定结果
get_calib_data (CalibDataID, 'camera', 0, 'params', CameraParam)

标定完成后,CameraParam里就包含了内参矩阵和畸变系数。你可以用tuple_select提取各个参数:

* CameraParam格式:[fx, fy, cx, cy, k1, k2, p1, p2, k3]
fx := CameraParam[0]
fy := CameraParam[1]
cx := CameraParam[2]
cy := CameraParam[3]
k1 := CameraParam[4]
k2 := CameraParam[5]
p1 := CameraParam[6]
p2 := CameraParam[7]
k3 := CameraParam[8]
避坑指南: 我曾经遇到一个情况,标定出来的fx和fy相差超过5%。一开始以为是标定板不平,反复标了5次都一样。后来才发现——传感器像素不是正方形。这种情况在工业相机里很常见,千万别强行把fx和fy设成相等。

3.7 内参标定的常见问题

问题 表现 原因 解决方案
重投影误差大 标定误差 > 0.5像素 标定板图像太少或角度不够 拍15-20张不同角度的标定板图像
fx/fy差异大 差异 > 3% 传感器像素非正方形 确认相机规格,正常现象
主点偏移大 cx, cy偏离图像中心 > 5% 镜头装配误差或传感器移位 重新标定,检查镜头安装
畸变参数不稳定 多次标定结果差异大 标定板图像质量差或光照不均 改善光照,使用高对比度标定板
我的建议: 标定完成后,一定要做验证。拿一个已知尺寸的物体放在场景中,用标定结果测量它的尺寸。如果误差在0.1mm以内,说明内参标定合格。如果误差大,别急着调深度图——先回头检查内参。

嗯,这一章的内容就到这里。内参是深度图标定的基石,搞懂了针孔模型、畸变模型和内参矩阵,后面的路就好走了。记住:内参标定不是一次性的工作,每次更换镜头、调整焦距、甚至环境温度变化,都可能需要重新标定。