摄像头测距方案
该应用是一个基于 Quectel Pi H1 智能主控板,通过双目摄像头采集画面,在预览界面点击目标区域,测量摄像头到该物体的真实世界距离的项目。
该项目通过调用双目摄像头同时采集左右目画面,利用双目视差原理计算目标距离,并提供了摄像头标定、参数调节等辅助功能,可作为双目测距、立体视觉及机器人视觉导航类应用的参考示例。
开发资源汇总
开发配件清单
| 配件名称 | 数量 | 规格参数 |
|---|---|---|
| Quectel Pi H1 智能主控板 | 1块 | Quectel Pi H1智能生态开发板 |
| USB双目摄像头 | 1个 | 推荐分辨率:2560×720(左右各1280×720);输出格式:YUYV/MJPG |
| USB-C 电源线充电器 | 1个 | 27W USB Type-C接口充电器 1.2米线长中规电源PD电源 适用于树莓派5代 |
| USB-C DP 显示线 /HDMI 线 | 1根 | 规格:DP 1.4;线长:1m;接口:USB-C(公头)- USB-C(公头) 规格:HDMI 2.0;线长:1m;接口:HDMI-A(公头)-HDMI-D(公头) |
| CPU 散热风扇(可选) | 1个 | 树莓派5代官方原装散热器带导热贴 |
| 显示屏 | 1个 | 24英寸HDMI显示器 |
| 棋盘格标定板(可选) | 1个 | 规格:9×6 内角点(可用手机屏幕显示) |
配件实物参考
Quectel套件
双目摄像头
棋盘标定板
快速上手
开发准备
Quectel Pi H1智能主控板出厂默认搭载 Debian 13 系统镜像,因此无需再次烧录镜像,仅需按照如下步骤操作即可。
硬件连接
显示连接
将 HDMI 线一端接入智能主控板的 HDMI 接口,另一端接入显示器的 HDMI 接口。
输入设备连接
将 USB 键盘、鼠标接入智能主控板的两个 USB-A 接口上,若用无线输入设备,将接收器插入 USB 口即可。
双目摄像头连接
将 USB 双目摄像头接入智能主控板的 USB-A 接口。
网线连接
将网线一端接入智能主控板的千兆网口,另一端接入路由器的网口(确保路由器已联网)。
电源连接
将 USB-A 电源线的 USB-A 端接入电源适配器,USB-C 端接入智能主控板的电源口(通常标注POWER IN)。
项目实现
安装前置
确认有网络连接后,打开终端输入命令:
sudo apt update && sudo apt install -y v4l-utils python3-pip
上述命令将更新软件源并安装项目运行所需的一些库,具体包括:
- v4l-utils:提供
v4l2-ctl等摄像头工具,用于读取和设置摄像头参数; - python3-pip:Python 包管理器,用于安装项目依赖。
获取代码
代码解压到设备
安装 Python 依赖
pip install -r requirements.txt
依赖包说明:
- PySide6:Qt6 的 Python 绑定,用于构建图形用户界面;
- opencv-python:OpenCV 图像处理库,用于摄像头采集、图像处理和立体视觉计算;
- numpy:数值计算库,用于矩阵运算和标定参数处理。
操作步骤
标定流程(首次使用)
首次使用需要进行摄像头标定,以获取准确的测距参数。
第一步:采集标定图像
运行标定图像采集工具:
python3 tools/capture_calib_images.py
程序会自动检测双目摄像头并显示预览画面,按照提示操作:
- 将棋盘格标定板放置在摄像头前方不同位置和角度
- 按
s键保存当前图像对(建议采集 15-20 对) - 按
q键退出采集程序
第二步:生成标定参数
采集完成后,运行标定参数生成工具:
python3 tools/generate_calib_params.py
程序会自动读取标定图像并计算双目标定参数,生成 tools/stereo_calib_params.npz 文件。
运行测距应用
完成标定后,运行主程序:
cd src
python3 main.py
程序启动后将显示图形界面,提供以下功能:
功能按钮说明
| 按钮 | 功能说明 |
|---|---|
| Left Camera Preview | 左摄像头单独预览,观察画面 |
| Right Camera Preview | 右摄像头单独预览,观察画面 |
| Take Left/Right Picture | 双目拍照,检查左右画面是否存在偏移,有偏移说明双目摄像头工作正常 |
| Start Ranging Mode | 进入测距模式,点击预览画面即可测量目标距离 |
测距操作
- 点击 "Start Ranging Mode" 进入测距模式
- 在预览画面上点击目标位置
- 等待距离计算结果显示在顶部提示栏
摄像头参数调节
程序右侧提供摄像头参数调节面板,可调节以下参数(也可根据具体摄像头可调节参数设置范围):
| 参数 | 说明 | 范围 |
|---|---|---|
| Brightness | 亮度 | -64 ~ 64 |
| Contrast | 对比度 | 0 ~ 95 |
| Saturation | 饱和度 | 0 ~ 100 |
| Hue | 色调 | -2000 ~ 2000 |
| Gamma | 伽马值 | 100 ~ 300 |
| Sharpness | 锐度 | 1 ~ 7 |
| Backlight Comp | 背光补偿 | 0 / 1 |
| Exposure Time | 曝光时间 | 3 ~ 2047 |
| WB Temp | 白平衡色温 | 2800 ~ 6500 |
日志显示区域
右侧上方区域可输出应用运行过程中的日志信息
应用演示
双目摄像头标定过程注意事项
标定图像采集注意事项
图像质量
要求:
- 清晰度保证:确保棋盘格在左右两个摄像头中完全可见,避免运动模糊
- 光照条件:避免强光直射和严重阴影,保证均匀光照
- 避免反光:如果使用手机屏幕显示棋盘格,注意避免屏幕反光导致角点检测失败
采集策略:
- 不同距离:在摄像头前0.3m-2m范围内变化距离
- 不同角度:左右倾斜±30°,上下倾斜±20°,旋转±15°
- 不同位置:棋盘格应覆盖画面的左上、右上、左下、右下、中心等不同区域
- 数量建议:至少15对有效图像,建议20对以上以提高标定精度
注意事项:
- 内角点数量:
CHESSBOARD_SIZE表示内角点数量,不是方格数量。例如9×6的内角点对应10×7的方格 - 物理尺寸准确性:
SQUARE_SIZE必须与实际方格边长一致,直接影响基线距离和测距精度 - 打印建议:
- 打印纸质棋盘格时,确保平整无皱褶
- 使用手机屏幕显示时,注意屏幕尺寸测量准确
- 推荐方格边长:8-12mm
提高精度的方法:
- 增加标定图像数量(建议20对以上)
- 确保图像覆盖更多角度和位置
- 提高图像清晰度,避免模糊
- 检查棋盘格物理尺寸设置是否正确
验证要点:
- 基线距离:
baseline应与实际双目摄像头物理间距接近(通常40-120mm) - 焦距一致性:左右相机焦距应相近,差异过大说明标定有问题
- 畸变系数:
dist_l和dist_r数值应在合理范围内(通常绝对值<1)
双目测距过程注意事项
测距原理与公式
# 测距公式:Z = (f × B) / d
# 其中:
# - f: 焦距(像素)
# - B: 基线距离(米)
# - d: 视差(像素)
distance = (f * self._baseline) / disparity
影响测距精度的关键因素:
- 视差计算准确性:受立体匹配算法和图像质量影响
- 标定参数准确性:基线距离和焦距参数
- 目标点特征:纹理丰富度影响视差计算
SGBM立体匹配参数调优
stereo = cv2.StereoSGBM_create(
minDisparity=0, # 最小视差
numDisparities=16*12, # 视差搜索范围(必须是16的倍数)
blockSize=11, # 匹配块大小(奇数,3-21)
P1=8*3*11*11, # 视差平滑惩罚项1
P2=32*3*11*11, # 视差平滑惩罚项2
disp12MaxDiff=1, # 左右一致性检查最大差异
uniquenessRatio=10, # 唯一性比率
speckleWindowSize=100, # 散斑过滤窗口大小
speckleRange=32, # 散斑过滤范围
mode=cv2.STEREO_SGBM_MODE_HH # 高精度模式
)
参数调优建议:
| 参数 | 调优原则 | 影响 |
|---|---|---|
numDisparities |
根据最近测距距离调整,值越大计算越慢 | 影响最近测距距离 |
blockSize |
纹理少时增大,纹理丰富时减小 | 影响匹配精度和速度 |
P1/P2 |
P2应大于P1,通常P2=4×P1 | 影响视差图平滑度 |
uniquenessRatio |
值越大匹配越严格 | 减少误匹配 |
speckleWindowSize |
去除视差图噪点 | 值越大去噪效果越强 |
测距精度影响因素
有效测距范围
# 测距范围受视差搜索范围限制
max_disparity = numDisparities # 192 (16*12)
min_distance = (f * baseline) / max_disparity
示例计算:
- 焦距 f = 695 像素
- 基线 B = 0.0735 米
- 最大视差 = 192
- 最近测距距离 = (695 × 0.0735) / 192 ≈ 0.27米
视差有效性过滤
# 代码中的视差过滤逻辑
for dy in range(-kernel//2, kernel//2 + 1):
for dx in range(-kernel//2, kernel//2 + 1):
d = disparity_map[y, x]
if d > 0.5: # 过滤弱视差噪声
disparity += d
valid_count += 1
注意事项:
- 视差值过小(<0.5)通常表示无效匹配
- 采用5×5邻域平均减少噪声影响
- 有效点数过少时应提示用户重新点击
距离合理性检查
# 对计算结果进行合理性验证
z_3d = point_3d[2]
if 0.01 < z_3d < 100.0:
distance = z_3d
else:
# Z不合理时用公式计算
distance = (f * self._baseline) / disparity
测距误差来源:
- 标定误差:基线距离和焦距参数不准确
- 视差误差:立体匹配算法精度限制
- 图像质量:光照、模糊、纹理不足
- 距离因素:距离越远,视差越小,相对误差越大
常见问题及解决方案
标定相关问题
角点检测失败率高
现象:
Warning: Skip 5th pair - chessboard not detected in left image
Valid image pairs for calibration: 8 (need ≥10)
解决方案:
- 改善光照条件,避免阴影和反光
- 确保棋盘格完全在画面内
- 增加图像对比度
- 减小棋盘格尺寸或增大拍摄距离
- 使用更清晰的棋盘格图像源
基线距离异常
现象:
Baseline Length: 0.1234 meters (应该约为0.06米)
解决方案:
- 重新测量方格实际物理尺寸
- 检查
SQUARE_SIZE参数设置 - 确保棋盘格平面平整
- 重新进行标定
测距相关问题
测距结果为0或无效
现象:
Error: Ranging failed - No valid disparity points
原因分析:
- 点击区域纹理不足或重复纹理
- 点击区域过远或过近
- 图像质量差(模糊、光照不足)
- 未加载标定参数
解决方案:
# 检查标定参数是否加载
if not self._is_calibrated:
LogManager.append_log("Warning: No calibration loaded!")
- 确保已加载标定参数文件
- 点击纹理丰富的区域
- 改善光照条件
- 调整SGBM参数增大
numDisparities
测距精度低、误差大
现象:
实际距离1米,测量结果0.8米或1.2米
解决方案:
- 检查标定质量:重投影误差应<1.0
- 优化SGBM参数:根据测距范围调整
numDisparities和blockSize - 改善图像质量:
# 增强对比度 clahe = cv2.createCLAHE(clipLimit=6.0, tileGridSize=(8, 8))
视差图质量差
现象:
视差图充满噪点,无法识别物体轮廓
解决方案:
调整预处理参数:
# 增强对比度 clahe = cv2.createCLAHE(clipLimit=6.0, tileGridSize=(8, 8)) # 增强降噪 gray_left = cv2.GaussianBlur(gray_left, (5, 5), 0) gray_left = cv2.medianBlur(gray_left, 5)调整SGBM参数:
# 增强匹配严格性 uniquenessRatio=15 speckleWindowSize=150检查标定参数:重新标定以获得更好的校正效果