Camera Calibration
这部分文档包含相机标定的内容,以及多个场景下的相机标定。
Before reading this document, you should read the OpenCV-Python Tutorials of Camera Calibration carefully.
Some Tips
- Use a chessboard as big as possible.
- Use a chessboard as rigid as possible.
- You must keep the same resolution during all the steps.
0. Prepare your chessboard
下载OpenCV官网上的棋盘格,或自己生成一个,去附近的文印店,告诉老板需要打到一个大的KT板上。并告诉老板需要一格有多长。
1. 相机内参标定
1.1 获取图像
文件目录组织保持树状结构,所有的图片都保存在images
目录下
<seq>
└── images
├── 1
│ ├── 000000.jpg
│ ├── 000001.jpg
│ ├── 000002.jpg
│ └── ...
├── 2
│ ├── 000000.jpg
│ ├── 000001.jpg
│ ├── 000002.jpg
│ └── ...
├── ...
├── ...
├── 8
│ ├── 000000.jpg
│ ├── 000001.jpg
│ ├── 000002.jpg
│ └── ...
└── 9
├── 000000.jpg
├── 000001.jpg
├── 000002.jpg
└── ...
1.2 检测棋盘格
首先需要检测棋盘格,对于一个(9, 6)
的棋盘格,每一个格子的长度为0.1m
,使用以下命令创建与检测棋盘格:
# detect chessboard
python3 apps/calibration/detect_chessboard.py ${data} --out ${data}/output/calibration --pattern 9,6 --grid 0.1 --seq
参数名称 | 可选值 | 含义 |
---|---|---|
pattern | 9,6 | 棋盘格的角点数 |
grid | 0.1 | 棋盘格的每格的长度 |
seq | bool, 默认False | 如果拍的是一段视频,那么使用这个选项可以加速棋盘格的检测,会通过二分法去查找棋盘格 |
棋盘格并不是一个中心对称图形,其中的(9, 6)指的是角点的数目,而不是格子的数目。如果打印的棋盘格是中心对称的,那么肯定打印错了。
对于一张有棋盘格的图像,检测会比较快,如果图像中没有棋盘格,那么检测会很慢,所以需要尽量保证需要检测的图像中包含棋盘格
检测结果会以json
格式存在${data}/chessboard
中,可视化的结果会存在${data}/output/calibration
中。

棋盘格检测结果
1.3 内参标定
棋盘格提取之后,计算相机内参。
python3 apps/calibration/calib_intri.py ${data} --num 200 --share_intri
参数名称 | 可选值 | 含义 |
---|---|---|
ext | .jpg, .png | 图像后缀 |
num | >0 | 使用的图像数量 |
share_intri | bool, 默认False | 是否共享所有相机的内参 |
运行完成后,程序会输出intri.yml
到${data}/output
目录。
这一步如果使用200张图需要花费大概2小时
2. 相机外参标定
相机外参标定步骤用于确定各个相机的在世界坐标中的位置。通常会使用一些标志点来确定世界坐标。最简单的方式是使用棋盘格,对于大场景无法使用棋盘格的,可以使用场景中的标志点,并测量其实际物理坐标。
2.1 使用棋盘格
对于多个相机可以拍到地面的情况,首先将棋盘格放置到地面,确保每一个相机都能看到。接着抓取一帧图片,如图所示。

将棋盘格放置在地面
检测棋盘格:
python3 apps/calibration/detect_chessboard.py ${data} --out ${data}/output/calibration --pattern 9,6 --grid 0.1 --debug
使用标注工具检查检测的棋盘格是否有问题:
python3 apps/annotation/annot_calib.py ${data} --annot chessboard --mode chessboard
按键 | 功能 |
---|---|
q /Q |
退出标注/不保存直接退出 |
空格 |
切换到下一个点 |
b |
切换到上一个点 |
e |
对于选定的矩形框,进行检测 |
标定外参,注意在这里需要指定之前标定的相机内参的路径:
python3 apps/calibration/calib_extri.py ${data} --intri <path/to/intri>/intri.yml
相机外参将会输出到${data}
目录下。
LightStage
对于LightStage数据,需要使用2048分辨率下的图片
python3 apps/calibration/calib_extri.py ${data} --intri data/camera/intri_lightstage_2048.yml
# 对输出的相机参数缩小一半,得到1024分辨率下的相机参数
python3 apps/calibration/transform_camera.py ${data} ${data}/1024 --scale 0.5
此时的${data}/1024
目录下即为所需的输出。
Hikvision
2.2 使用标志点
创建标志点
python3 apps/calibration/create_marker.py ${data} --N 100
手动标注:
python3 apps/annotation/annot_calib.py ${data} --annot chessboard --mode marker
按键 | 功能 |
---|---|
单击 | 点中一个点 |
空格 |
确认当前选中的点,并切换到下一个点 |
b |
切换到上一个点 |
此时的可视化为5个点为1组,依次连接。
标定外参,使用BA
2.3 使用人体关键点
TODO
2.4 BA优化
在多相机的情况下,可以利用多视角的一致性信息。

棋盘格在至少三个相机内可见
data=/path/to/img
# 以下三种情况选择其中一个
# 1. 只优化相机的RT
python3 apps/calibration/calib_ba.py ${data} --init ${data}/../ground --ground ${data}/../ground --out ${data}/output-ba
# 1. 优化相机的RT,同时优化K
python3 apps/calibration/calib_ba.py ${data} --init ${data}/../ground --ground ${data}/../ground --out ${data}/output-ba-optK --optK
# 1. 优化相机的RT,同时优化K, D
python3 apps/calibration/calib_ba.py ${data} --init ${data}/../ground --ground ${data}/../ground --out ${data}/output-ba-optKD --optK --optD
参数名称 | 可选值 | 含义 |
---|---|---|
init | path | 初始化的相机内参与外参的路径 |
ground | path | 拍摄的棋盘格放在地面的文件路径 |
out | path | 标定结果输出路径 |
optK | bool | 是否优化相机的焦距、光心,默认False |
optD | bool | 是否优化相机的畸变参数,默认False |
单目情况
对于单目的情况,无法使用多视角标定,可直接创建空白的相机,这个相机的焦距会根据输入的图像形状指定,光心在图像中心,旋转为单位阵,位置为0。注意,这样指定的相机无法用于多视角重建的代码,只能用于单视角重建。
python3 apps/calibration/create_blank_camera.py ${data} --shape 2160 3840
3. 检查
可视化检查
cube:
out=/path/to/output
python3 apps/calibration/check_calib.py ${data} --out ${out} --mode grid --show

可视化虚拟的立方体
立方体的顶点0坐标为(0, 0, 0)
,顶点1坐标为(1, 0, 0)
,顶点3坐标为(0, 1, 0)
,顶点4坐标为(0, 0, 1)
。
human:
设置data
为人体Tpose的数据,检查人体重投影误差
python3 apps/calibration/check_calib.py ${data} --out ${data} --mode human --show
如果检测了手的关键点,可以增加--hand
标志来加入手部关键点。

可视化关键点重投影;绿色的为检测的位置,红色的为重投影的位置
定量结果
如果使用了BA来进行标定,可以通过这一步定量计算所有帧的平均标定误差。
out=/path/to/output
python3 apps/calibration/check_calib.py ${data} --out ${out} --mode match --show