15 KiB
scan-calibrator 扫描参数标定助手
这个程序用于不同摄像头点位的scan现场标定:
- 通过smart-cam统一接口读取当前海康威视或天地伟业摄像头PTZ;
- 记录扫描区域左上角和右下角;
- 在固定zoom下移动一个候选角度并抓取两张图;
- 用ORB特征和RANSAC单应矩阵定位公共特征,再按当前移动轴的画面位移计算重叠率;
- 自动搜索接近目标重叠率的
pan_step和tilt_step; - 输出可以复制到
config.json的scan配置片段。
程序通过smart-cam已经提供的HTTP接口控制SDK,标定结束会把摄像头恢复到标定起点。
1. 最重要的原理
1.1 PTZ描述的是画面中心,不是四条边
pan = 摄像头光轴中心的水平方向
tilt = 摄像头光轴中心的垂直方向
zoom = 当前光学变焦倍率
只读取一个PTZ,无法直接知道画面左边、右边、上边、下边分别对应多少度。 要知道画面边界,还需要镜头的水平/垂直视场角(HFOV/VFOV)。视场角取决于:
- 摄像头传感器尺寸;
- 镜头实际焦距;
- 当前zoom;
- 镜头畸变;
- 厂商对zoom数值的定义;
- 图像裁剪和电子防抖。
因此不能用一个固定公式在所有摄像头上从zoom直接算step。同一个zoom=500,不同型号的
真实视场角也可能不同。
1.2 step与zoom的关系
zoom越大,视场越窄,step必须越小;zoom越小,视场越宽,step可以越大。
理论关系是:
pan_step ≈ 水平视场角 × (1 - 水平目标重叠率)
tilt_step ≈ 垂直视场角 × (1 - 垂直目标重叠率)
例如水平视场角为10°,目标重叠4%,则:
pan_step ≈ 10° × 0.96 = 9.6° = 960
本程序不依赖厂家标称视场角,而是移动摄像头实拍两张图,通过特征匹配测量实际重叠率。
1.3 推荐重叠率
当前项目要求上下左右重叠不超过5%。工具默认目标为4%,预留1%的测量和云台误差余量:
- 目标4%:当前默认值;
- 实测0%~5%:符合当前项目要求;
- 超过5%:生成器会拒绝该step,要求重新标定;
- 超过35%:通常重复过多,图片数量和扫描时间明显增加;
- 5%重叠的安全余量很小,必须在扫描区域多个位置复核,发现缺口时应由现场人员明确决定是否提高。
1.4 为什么上下和左右会反
PTZ数值增长方向不等于最终大图方向。不同厂商、安装方向和坐标系可能出现:
- pan增加时摄像头视野向左推进;
- pan增加时摄像头视野向右推进;
- tilt增加时向上;
- tilt增加时向下。
所以必须分别确认“从画面左到右”和“从画面上到下”时PTZ是增加还是减少。 第一版验证图中天花板位于地板下面,就是把tilt数值递增错误地当成了从上到下。
2. 文件结构
scan-calibrator/
├── README.md
├── calibrate.sh
├── scan_calibrator.py
├── calibration.json # 运行mark/calibrate后自动生成
├── src/
│ └── measure_overlap.cpp
└── result/
└── scan_config_*.json
3. 完整标定流程
进入目录:
cd /home/zhangw/scan-calibrator
第一步:固定zoom和焦点
左上角和右下角可以按现场覆盖需要分别设置zoom。最终扫描zoom取两个角点读数的算术平均值, step测量必须在这个平均zoom下进行;交互式向导会在第四步自动切换到平均zoom。
注意:zoom是焦段/视场角;focus是对焦清晰度,两者不是同一个参数。
第二步:记录左上角
手动把摄像头移动到要扫描区域的左上角,然后查看PTZ:
./calibrate.sh ptz
确认位置后记录:
./calibrate.sh mark top-left
第三步:记录右下角
手动移动到扫描区域右下角;zoom可以与左上角不同:
./calibrate.sh ptz
./calibrate.sh mark bottom-right
第四步:选择step标定位置
把摄像头移动到扫描区域中间、纹理丰富的位置。不要对着纯天空、纯白墙、水面或大面积 重复栅栏,否则特征匹配可能不可靠。
第五步:确认pan方向
先用较小候选值测一次。例如从视觉上的左向右移动时,如果pan数值应增加:
./calibrate.sh measure pan --direction 1 --delta 300
如果pan数值应减少:
./calibrate.sh measure pan --direction -1 --delta 300
程序会输出重叠率,并根据图像中公共特征的移动方向说明摄像头视野向左还是向右推进。 摄像头随后自动回到起点。
第六步:自动标定pan_step
根据当前zoom选择一个可能覆盖真实step的范围。例如:
单位是0.01°:100=1°,2000=20°。程序会二分测试多个step。为了兼顾拼接安全边
和5%的重叠上限,默认使用4%:
./calibrate.sh calibrate pan \
--direction 1 \
--minimum 100 \
--maximum 2000 \
--target-overlap 0.04
只有几何内点不少于50且内点率不少于45%的匹配才会被接受;低质量结果不会写入配置。
新版会在calibration.json记录overlap_method=axis_shift_v1;旧版二维面积算法产生的step
会在generate阶段被拒绝,必须重新标定,避免误用历史结果。
当目标只有4%~5%时,两张图的公共特征可能太少,自动实拍标定会主动失败,不能退回一个 高重叠结果。若已经有同一zoom下的可靠新版测量,可以用视场角关系反算4%目标:
./calibrate.sh retarget --target-overlap 0.04
反算公式为:
估算视场角 = 旧step / (1 - 旧实测重叠率)
新step = 估算视场角 × (1 - 0.04)
反算结果会标记为axis_shift_v1_retargeted,不是“实测4%”。必须生成配置、完整扫图并在
多个相邻位置复核;任何位置出现缺口时,说明5%要求已经低于该点位的安全余量。
第七步:自动标定tilt_step
先确认从画面上方向下方移动时tilt是增加还是减少,然后执行:
./calibrate.sh calibrate tilt \
--direction -1 \
--minimum 50 \
--maximum 1000 \
--target-overlap 0.04
16:9画面的垂直视场通常小于水平视场,所以tilt_step通常小于pan_step。
第八步:生成scan配置
办公室测试时使用:
./calibrate.sh show
./calibrate.sh generate --mount desktop
野外正常倒挂时使用:
./calibrate.sh generate --mount hanging
生成结果保存在:
/home/zhangw/scan-calibrator/result/scan_config_<安装方式>_YYYYMMDD_HHMMSS.json
程序严格用先记录的top-left和后记录的bottom-right确定扫描区域。因为pan是一个
0~360°的圆周,只给两个数值会存在两条可能的弧,所以--mount用于确定视觉上
“左上角→右下角”对应的pan方向:
desktop:当前办公室实测为视觉左→右时pan递减;hanging:野外正常倒挂按原生方向,视觉左→右时pan递增。
当前scan只支持pan数值递增。对于desktop,生成器会交换两个pan端点,让scan反向遍历
同一个指定区域;这只改变采图先后顺序,不会把小区域变成另一条大弧。程序在输出前显示
指定弧段角度、预计列数、行数和总图片数,便于写入配置前人工核对。
生成器还会按照标定step做整步扩边。扫描范围只能比手动选择的范围大,不能更小:
区间数 = ceil(手动范围跨度 / step)
最终跨度 = 区间数 × step
向外扩展量 = 最终跨度 - 手动范围跨度
例如垂直跨度840、标定step763时,不能直接产生-90、673、750这组三点,因为两个间隔
分别是763和77。生成器保持step763不变,将终点向外扩展686,得到
-90、673、1436。三个位置间距一致,完整包含原来-90~750的手动范围,并且多扫的
范围小于一个step。生成时会明确打印pan和tilt分别向外扩展了多少角度。
例如桌面模式下,先记录的左上角为168.90°,后记录的右下角为153.00°。视觉左→右对应
pan递减,因此用户指定的弧段是15.90°。生成器会输出
pan_start=15300, pan_end=16890,让当前scan反向覆盖这同一段15.90°区域,而不是经过
360°扫描另一段344.10°区域。
4. 如何判断标定结果是否可靠
每次测量会输出:
overlap 沿当前标定轴计算的重叠比例
axis_shift 相邻画面沿当前标定轴移动的画幅比例
cross_axis_shift 非当前标定轴上的漂移比例
polygon_overlap 透视变换后二维多边形交集,仅作为诊断值
good_matches 通过比例测试的特征匹配数
inliers 符合统一几何变换的匹配数
inlier_ratio 几何内点占比
建议:
-
inliers < 50:结果不可靠,程序会拒绝; -
inlier_ratio < 0.45:错误匹配过多,程序会拒绝; -
近距离物体、玻璃反射、重复栅栏和大面积纯色区域容易让单应性失效;
-
step应在扫描区域内至少选择上、中、下三个纹理丰富的位置分别验证,最终取较小的安全值;
-
目标重叠率默认4%,实测必须不超过5%;
-
step标定使用当前移动轴上的中心位移计算重叠率,不再直接用二维多边形交集;
-
cross_axis_shift > 0.20会被视为运动方向不一致并拒绝,常见原因是重复图案误匹配; -
inliers >= 50; -
inlier_ratio >= 0.45; -
推荐step的
overlap位于0%~5%; -
在扫描区域另外1~2个位置用
measure复核同一个step; -
在至少上、中、下三个位置复核;任一位置超过5%时重新标定或增大step;
近距离物体会产生视差,同一个step在不同位置测出的重叠可能不同。正式部署应采用多个位置中 更保守的较小step,而不是只采用最好看的一个测量结果。
手动开启扫描-->测试当前参数是否合理
docker exec smart-cam curl -fsS -X POST http://127.0.0.1:18080/api/v1/scan/start
实时查看扫图进度:
docker logs -f -t --tail 200 smart-cam 2>&1 | grep --line-buffered '\[scan\]'
查看当前扫描状态:
docker exec smart-cam curl -fsS http://127.0.0.1:18080/api/v1/scan/status
5. scan等待、容差和HTTP参数
所有角度相关参数单位均为0.01°,zoom单位为0.01×。
move_wait: 0.5
SDK判断云台已经到位后,额外等待0.5秒再进入对焦阶段,用于消除机械回弹和画面抖动。
- 需要按摄像头单独验证;
- 快速、稳定的球机通常0.3~0.8秒;
- 长焦、大跨度移动、支架晃动时可提高到1~2秒;
- 太小会产生运动模糊,太大只会增加扫描时间。
focus_wait: 1.0
为对焦/镜头稳定预留的等待时间。当前海康链路没有主动改变你设定的zoom,主要作为镜头稳定等待; 天地伟业worker可在这个阶段执行对应focus操作。
- 与摄像头型号、zoom和光照有关,需要现场验证;
- 如果固定焦点且画面稳定,可以缩短;
- 夜间或长焦对焦慢时需要加长。
capture_wait: 1.0
对焦阶段结束后,到真正抓取JPEG之前再等待1秒,避免抓到曝光尚未稳定或关键帧切换中的图像。
- 需要按码流延迟和曝光速度验证;
- 一般0.5~1.5秒;
- 夜间慢曝光可适当增加。
move_timeout: 35
单个PTZ目标允许的最大移动时间,单位秒。超过后本次扫描失败并记录move_timeout。
- 与球机转速、最大移动跨度和网络延迟有关;
- 通常30~45秒;
- 不能用增大timeout掩盖不可达的tilt范围。
pan_tolerance: 70
水平到位容差,70=0.70°。实际pan与目标pan误差小于该值才认为到位。
- 应按每台球机的回读精度配置;
- 必须明显小于
pan_step,建议不超过step的1/4; - 拼接要求高时建议从20~50(0.2°~0.5°)试起。
tilt_tolerance: 45
垂直到位容差,45=0.45°。规则与pan相同。
- 需要按球机回读抖动配置;
- 建议不超过
tilt_step/4; - tilt_step较小时应进一步降低。
zoom_tolerance: 400
zoom到位容差,400=4.00×。对于固定焦段扫描,这个默认值过于宽松,不适合精确拼接。
- 强烈建议每台摄像头单独验证;
- 海康回读稳定时可先使用10~30(0.10×~0.30×);
- 容差过大会让不同焦段的图片混入同一组,视场角不一致,后端很难拼接。
stable_checks: 2
连续多少次PTZ回读都在容差内,才真正认为云台稳定。天地伟业worker会使用该参数; 当前海康Python驱动尚未消费这个字段,因此它在海康配置中只是预留项。
- 推荐2~3次;
- 长焦或支架易抖时使用3;
- 值越大越稳,但每个点耗时更长。
stable_wait_ms: 300
PTZ到位检查之间的间隔,单位毫秒。stable_checks=2时,至少跨越约300ms再次确认。
- 通常200~500ms;
- 网络慢或回读抖动可增加;
- 它也影响到位轮询速度。
HTTP配置
"http": {
"host": "0.0.0.0",
"port": 18080
}
host=0.0.0.0表示监听容器所有网卡,允许同机程序及局域网映射后的Web界面调用;port=18080是scan HTTP服务端口;- 这两个参数与摄像头光学参数无关,不需要每个摄像头单独标定;
- 同一设备只有一个scan服务时保持默认即可;端口冲突或安全策略要求时才修改。
6. 哪些参数必须每台摄像头单独配置
必须或强烈建议逐台/逐点位配置:
pan_start / pan_end
tilt_start / tilt_end
pan_step / tilt_step
zoom
pan_tolerance / tilt_tolerance / zoom_tolerance
move_wait / focus_wait / capture_wait(至少现场验证)
move_timeout(至少验证最大跨度)
通常可使用统一默认值:
stable_checks = 2
stable_wait_ms = 300
http.host = 0.0.0.0
http.port = 18080
即使摄像头型号相同,只要安装高度、观察距离、扫描区域或zoom不同,也应重新标定角点和step。
7. 安装姿态与拼图方向
本工具只负责取得PTZ角点和实测步长,不修改scan的采图顺序,也不会向scan配置输出额外的方向字段。
球机安装姿态由/home/zhangw/scan-calibrator/scan-panorama在拼图时处理:
# 办公室:球机正放在桌面,摄像头后台将画面旋转180度
/home/zhangw/scan-calibrator/scan-panorama/stitch.sh 扫描目录 --mount desktop
# 野外:球机正常倒挂
/home/zhangw/scan-calibrator/scan-panorama/stitch.sh 扫描目录 --mount hanging
desktop只反转网格的行顺序和列顺序;不会修改meta.json,也不会旋转或镜像任何一张小图。
hanging直接按meta.json原始row/col顺序拼图。