摄像头测距方案

Copyright © Quectel Wireless Solutions Co., Ltd. 2026. All rights reserved.


该应用是一个基于Quectel Pi H1智能主控板的双目测距项目:通过双目摄像头采集画面,在预览界面点击目标区域,即可测量摄像头到该物体的实际物理距离(目标深度距离)。

该项目同步采集左右目画面,利用双目视差原理计算目标距离,并提供摄像头标定、相机图像参数调节等辅助功能,可作为双目测距、立体视觉及机器人视觉导航类应用的参考示例。

../../../_images/image_QwQbbClq6oW9cwx1NsqcxuBpnpd.webp

开发资源汇总

开发配件清单

配件名称

数量

规格参数

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代

Micro HDMI线

1

HDMI 2.0;线长:1 米;HDMI-A(公头)转HDMI-D(公头)

CPU散热风扇(可选)

1

树莓派5代官方原装散热器带导热贴

显示屏

1

HDMI显示器

棋盘格标定板

1

9 × 6内角点(可用手机屏幕显示,需在标定脚本中修改每个方格的真实物理边长)

网线

1

线长:1 米;传输速率:千兆

配件实物参考

Quectel套件

../../../_images/image_TnwqbDEk2oWTmVxRUAdcBJuenob.webp

快速上手

开发准备

Quectel Pi H1出厂预装Debian 13操作系统,通常无需重新烧录系统镜像。按照以下步骤操作即可:

硬件连接

显示连接

将Micro HDMI线的Micro HDMI端接入智能主控板的Micro HDMI接口,另一端接入显示器的HDMI接口。

../../../_images/image_H1j1bdG8ooDozdx95SCcCYtFnnf.webp

输入设备连接(可选)

将USB键盘和鼠标接入智能主控板的两个USB-A接口。若USB口不够,推荐使用无线输入设备或触屏。

../../../_images/image_HfYQbLYM2oh5R7x6qhLcneBvnzY.webp

双目摄像头连接

将USB双目摄像头接入智能主控板的USB-A接口。

../../../_images/image_HrjQb4MrMoLiZRxeEPMc0s0Hnjc.webp

网线连接

将网线一端接入智能主控板的千兆网口,另一端接入路由器的网口(确保路由器已联网)。

../../../_images/image_KrYfbOw9uojcrDxATAIcKXApnWd.webp

电源连接

将充电器的USB Type-C口接入智能主控板的电源口(标注 POWER IN),另一端接入电源。

../../../_images/image_DtkLbCxnAo0Uynxo9b0c9VpLneb.webp

项目实现

安装前置

确认网络连接正常后,打开终端并输入以下命令:

sudo apt update && sudo apt install -y v4l-utils python3-pip python3-venv

上述命令会更新软件源并安装系统前置依赖及工具包,包括:

  • v4l-utils:提供 v4l2-ctl 等摄像头工具,用于读取和设置摄像头参数;

  • python3-pip:Python包管理器,用于安装项目依赖;

  • python3-venv:Python虚拟环境。

获取代码

点击 下载代码,然后将代码解压到智能主控板上。

安装Python依赖

cd <项目目录>
# 创建名为venv的Python虚拟环境
python3 -m venv venv
# 激活已创建的虚拟环境
source venv/bin/activate
# 在虚拟环境中安装依赖
pip install -r requirements.txt

依赖包说明:

  • PySide6:Qt6的Python绑定,用于构建图形用户界面;

  • opencv-python:OpenCV图像处理库,用于摄像头采集、图像处理和立体视觉计算;

  • numpy:数值计算库,用于矩阵运算和标定参数处理。

采集标定图像

运行标定图像采集工具:

python3 tools/capture_calib_images.py

程序会自动检测双目摄像头并显示预览画面,按以下提示操作:

  1. 将棋盘格标定板放置在摄像头前方的不同位置,并变换不同角度。

  2. 外接键盘按 S 键保存当前图像对(建议采集15~20对)。

  3. 外接键盘按 Q 键退出采集程序。

生成标定参数

采集完成后,运行标定参数生成工具,方格默认尺寸9 mm,可在 tools 下的脚本文件中找到 SQUARE_SIZE 参数进行修改:

python3 tools/generate_calib_params.py

程序会自动读取标定图像并计算双目标定参数,生成 tools/stereo_calib_params.npz 文件。

运行测距应用

完成标定后,运行主程序:

cd src
python3 main.py

程序启动后将显示图形界面,提供以下功能:

../../../_images/image_YEynbZKlXoDC81xAJRYc2mrgnNc.webp

功能按钮说明

按钮

功能说明

Left Camera Preview

单独预览左摄像头画面

Right Camera Preview

单独预览右摄像头画面

Take Left/Right Picture

双目拍照,用于左右两侧画面对比

Start Ranging Mode

进入测距模式,点击预览画面即可测量目标距离

Save Parameters

保存参数(不同相机参数可能不同,需要自行修改)

Reset Parameters

重置参数(不同相机参数可能不同,需要自行修改)

Stop Camera

停止采集/ 关闭摄像头

日志显示区域

右侧上方区域可输出应用运行过程中的日志信息。

../../../_images/image_ROnYbc4wio9dLYxZA70c9pWonwb.webp

摄像头参数调节

程序右侧提供摄像头参数调节面板,可调节以下参数(范围可根据具体摄像头的可调参数设置):

参数

说明

范围

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

Auto

自动曝光,调整白平衡等

--

进行测距

  1. 点击 Start Ranging Mode 进入测距模式。

  2. 在预览画面上点击目标位置。

  3. 等待顶部提示栏显示距离计算结果。

  4. 若出现 invalid 字样,可在右侧log区域查看具体原因,可能是点击区域纹理不清晰导致。

应用演示

distance_video

注意事项及常见问题

标定图像采集注意事项

图像质量

要求:

  • 清晰度:确保棋盘格在左右两个摄像头画面中完全可见,避免运动模糊。

  • 光照条件:避免强光直射和严重阴影,保证均匀光照。

  • 避免反光:若使用手机屏幕显示棋盘格,注意避免屏幕反光导致角点检测失败。

采集策略:

  • 不同距离:在距摄像头0.3~2 m的范围内变化距离。

  • 不同角度:左右倾斜±30°,上下倾斜±20°,旋转±15°。

  • 不同位置:棋盘格应覆盖画面的左上、右上、左下、右下、中心等不同区域。

  • 数量建议:至少15对有效图像,建议20对以上以提高标定精度。

注意事项:

  • 内角点数量:CHESSBOARD_SIZE 表示内角点数量,不是方格数量。例如9×6的内角点对应10×7的方格。

  • 物理尺寸准确性:SQUARE_SIZE 必须与实际方格边长一致,它直接影响基线距离和测距精度。

  • 打印建议:

    • 打印纸质棋盘格时,确保平整无皱褶。

    • 使用手机屏幕显示时,注意屏幕尺寸测量准确。

    • 推荐方格边长:20~30 mm。

提高精度的方法:

  • 增加标定图像数量(建议20对以上)。

  • 确保图像覆盖更多角度和位置。

  • 提高图像清晰度,避免模糊。

  • 检查棋盘格物理尺寸设置是否正确。

验证要点:

  • 基线距离(Baseline):标定输出的Baseline应与双目摄像头的实际物理间距接近。

  • 重投影误差(RMS):立体标定的重投影均方根误差应≤ 0.5像素,优质标定< 0.3像素;若明显偏大,说明标定发散、结果不可用,需重新标定。

  • 焦距一致性:左右摄像头的焦距应相近,差异过大说明标定存在问题。

  • 畸变系数: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

去除视差图噪点

值越大去噪效果越强

speckleRange

与speckleWindowSize配合,控制散斑判定阈值

WindowSize越大、Range越小时,散斑过滤越强

测距精度影响因素

有效测距范围

# 有效测距范围由最近盲区Z_min与最远有效距离Z_max共同决定
# 视差在降采样图像上计算后再放大回原分辨率(RANGE_DOWNSAMPLE=2),
# 因此原图尺度上的最大视差 = numDisparities × RANGE_DOWNSAMPLE
max_disparity = NUM_DISPARITIES * RANGE_DOWNSAMPLE   # 128 × 2 = 256
min_distance = (f * baseline) / max_disparity        # 最近测距距离(Z_min)
max_distance = (f * baseline) / MIN_RESOLVABLE_DISP  # 最远有效距离(Z_max)

示例计算:

  • 焦距f = 695像素。

  • 基线B = 0.060米(本套件标配约60 mm)。

  • 原图尺度最大视差 = 256。

  • 最近测距距离Z_min =(695 × 0.060)/ 256 ≈ 0.16 米。

  • 最远有效距离Z_max =(f × B)/ d_min,其中d_min为最小可分辨视差。取d_min ≈ 1像素时Z_max ≈ 41.7米(理论上限);实际受亚像素噪声影响,工程可用最远距离约5~8米。

视差有效性过滤

kernel = 9   # 9×9邻域
for dy in range(-kernel//2, kernel//2 + 1):
    for dx in range(-kernel//2, kernel//2 + 1):
        x = raw_point[0] + dx
        y = raw_point[1] + dy
        # 边界裁剪,防止越界
        if 0 <= x < disparity_map.shape[1] and 0 <= y < disparity_map.shape[0]:
            d = disparity_map[y, x]
            if d > 0.5:      # 过滤弱视差噪声
                disparity += d
                valid_count += 1

注意事项:

  • 视差值过小(< 0.5)通常表示无效匹配。

  • 采用5×5邻域平均以减少噪声影响。

  • 有效点数过少时应提示用户重新点击。

距离合理性检查

# 对计算结果进行合理性验证
# 有效距离范围:近端受最大视差限制(Z_min ≈ 0.18 m),远端视差趋于亚像素、误差急剧放大
MIN_VALID_Z = 0.2   # 米
MAX_VALID_Z = 5.0   # 米

z_3d = point_3d[2]
if MIN_VALID_Z < z_3d < MAX_VALID_Z:
    distance = z_3d
else:
    # z_3d 异常时视差必然无效,直接判定测距失败,与 UI 的 Invalid 状态闭环
    distance = 0.0   # UI 显示 Measured distance: Invalid

测距误差来源:

  • 标定误差:基线距离和焦距参数不准确。

  • 视差误差:立体匹配算法精度限制。

  • 图像质量:光照、模糊、纹理不足。

  • 距离因素:距离越远,视差越小,相对误差越大。

常见问题及解决方案

标定相关问题

角点检测失败率高

现象:

Warning: Skip 5th pair - chessboard not detected in left image
Valid image pairs for calibration: 8 (need ≥15)

解决方案:

  • 改善光照条件,避免阴影和反光。

  • 确保棋盘格完全在画面内。

  • 增加图像对比度。

  • 缩短拍摄距离,让标定板占画面1/3 ~ 1/2以上面积。

  • 使用更清晰的棋盘格图像源。

基线距离异常

现象:

Baseline Length: 0.1234 meters

解决方案:

  • 重新测量方格实际物理尺寸。

  • 检查 SQUARE_SIZE 参数设置。

  • 确保棋盘格平面平整。

  • 重新进行标定。

测距相关问题

测距结果为0或Invalid

现象:

# 日志区域显示
Error: Ranging failed - No valid disparity points

原因分析:

  • 点击区域纹理不足或重复纹理。

  • 点击区域过远或过近。

  • 图像质量差(模糊、光照不足)。

  • 未加载标定参数。

解决方案:

# 检查标定参数是否加载
if not self._is_calibrated:
    LogManager.append_log("Warning: No calibration loaded!")
  • 确保已加载标定参数文件。

  • 点选纹理丰富的区域或物体边缘,避免大面积弱纹理(如白墙)。

  • 改善光照条件,避免反光、阴影与运动模糊。

  • 增大 blockSize(扩大特征匹配块)或适当降低 uniquenessRatio(放宽匹配严苛度)。

  • 确认目标在有效测距范围内(过近或过远都会导致视差不可解算)。

测距精度低、误差大

现象:
实际距离1米,测量结果0.8米或1.2米。

解决方案:

  • 检查标定质量:立体标定的重投影RMS应≤ 0.5像素(优质标定< 0.3像素);若偏大说明标定发散,应重新标定。

  • 优化SGBM参数:根据测距范围调整 numDisparities 和 blockSize。

  • 改善图像质量:

# 增强对比度(左右目必须同步处理)
clahe = cv2.createCLAHE(clipLimit=4.0, tileGridSize=(8, 8))
gray_left = clahe.apply(gray_left)
gray_right = clahe.apply(gray_right)

视差图质量差

现象:
视差图充满噪点,无法识别物体轮廓。

解决方案:

  • 调整预处理参数:

# 增强对比度
clahe = cv2.createCLAHE(clipLimit=6.0, tileGridSize=(8, 8))

# 增强降噪(左右目同步,3×3 轻量滤波,避免过度平滑边缘)
gray_left = cv2.GaussianBlur(gray_left, (3, 3), 0)
gray_right = cv2.GaussianBlur(gray_right, (3, 3), 0)
gray_left = cv2.medianBlur(gray_left, 3)
gray_right = cv2.medianBlur(gray_right, 3)
  • 调整SGBM参数:

stereo = cv2.StereoSGBM_create(
    minDisparity=0,                 # 最小视差
    numDisparities=128,             # 视差搜索范围(必须是16的倍数)
    blockSize=11,                   # 匹配块大小(奇数,3-21)
    P1=8*3*11*11,                   # 视差平滑惩罚项 1
    P2=32*3*11*11,                  # 视差平滑惩罚项 2
    disp12MaxDiff=2,                # 左右一致性检查最大差异
    uniquenessRatio=5,              # 唯一性比率
    speckleWindowSize=100,          # 散斑过滤窗口大小
    speckleRange=32,                # 散斑过滤范围
    mode=cv2.STEREO_SGBM_MODE_SGBM  # 速度优先
)
  • 检查标定参数:重新标定以获得更好的校正效果。

技术支持与贡献

如在使用过程中遇到问题,欢迎在 移远通信官方论坛 提交技术咨询,我们的技术支持团队将及时为您解答。

项目开源地址:https://github.com/Quectel-Pi/demo-camera-distance-measurement。

欢迎提交Issue反馈问题或Pull Request贡献代码改进!