用Python+OpenCV实现单目视觉测距:从A4纸标定到实战应用

在计算机视觉领域,单目测距一直是个既基础又实用的技术方向。想象一下,你只需要一个普通的USB摄像头和一张随处可见的A4纸,就能让计算机"看懂"物体距离——这听起来像是科幻场景,但通过OpenCV和Python的组合,我们完全可以在自己的电脑上实现这个功能。不同于需要昂贵硬件设备的深度相机方案,单目测距技术以其低成本、易实现的特性,成为许多创客、机器人爱好者和计算机视觉初学者的首选方案。

1. 环境准备与基础概念

在开始编码前,我们需要先理解几个核心概念。单目测距的基本原理其实源于初中物理的光学知识——相似三角形原理。当我们在固定焦距下拍摄已知尺寸的物体时,物体在图像中的像素尺寸与实际距离存在确定的数学关系。

1.1 必备工具安装

首先确保你的Python环境已经就绪(推荐Python 3.6+),然后通过pip安装必要的库:

pip install opencv-python numpy

对于国内用户,如果下载速度较慢,可以使用清华镜像源:

pip install -i https://pypi.tuna.tsinghua.edu.cn/simple opencv-python numpy

1.2 硬件准备清单

  • 普通USB摄像头(720p以上分辨率效果更佳)
  • 标准A4纸(210×297mm)
  • 测量工具(如卷尺,用于初始距离测量)
  • 均匀光照环境(避免强光直射或阴影干扰)

提示:摄像头最好固定在一个位置,避免在标定过程中移动。手机摄像头也可以使用,但需要通过相应接口获取视频流。

2. 核心原理与数学推导

单目测距的核心公式基于相似三角形原理:

F = (P × D) / W

其中:

  • F:相机焦距(像素单位)
  • P:物体在图像中的像素宽度
  • D:相机到物体的实际距离
  • W:物体的实际宽度

这个公式的推导过程其实非常直观:

  1. 在初始距离D处拍摄已知宽度W的物体(如A4纸),测量其在图像中的像素宽度P
  2. 计算得到焦距F
  3. 当物体移动时,通过检测新的像素宽度P',即可计算新的距离D' = (W × F)/P'

2.1 实际测量中的误差来源

在实际应用中,我们需要考虑多种误差因素:

误差类型 影响程度 缓解方法
镜头畸变 使用cv2.calibrateCamera进行相机标定
测量不准确 使用精确测量工具,多次测量取平均
光照变化 保持稳定光照条件,或使用自适应阈值
角度偏差 确保相机与目标平面平行

3. 完整代码实现与分步解析

下面我们来实现一个完整的单目测距系统。代码分为三个主要部分:标记检测、焦距计算和距离测量。

3.1 标记检测函数

import cv2
import numpy as np

def find_marker(image):
    # 转换为灰度图并降噪
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    gray = cv2.GaussianBlur(gray, (5, 5), 0)
    
    # 边缘检测
    edged = cv2.Canny(gray, 35, 125)
    
    # 寻找轮廓
    contours, _ = cv2.findContours(edged.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
    
    # 获取面积最大的轮廓
    c = max(contours, key=cv2.contourArea)
    
    # 返回最小外接矩形
    return cv2.minAreaRect(c)

3.2 焦距计算函数

def calculate_focal_length(known_width, known_distance, image_path):
    # 读取参考图像
    image = cv2.imread(image_path)
    marker = find_marker(image)
    
    # 计算焦距
    focal_length = (marker[1][0] * known_distance) / known_width
    
    print(f"计算得到的焦距: {focal_length:.2f} pixels")
    return focal_length

3.3 距离测量函数

def distance_to_camera(known_width, focal_length, per_width):
    return (known_width * focal_length) / per_width

def measure_distance(image_path, focal_length, known_width):
    image = cv2.imread(image_path)
    marker = find_marker(image)
    
    # 计算距离
    distance = distance_to_camera(known_width, focal_length, marker[1][0])
    
    # 绘制边界框和距离信息
    box = cv2.boxPoints(marker)
    box = np.int0(box)
    cv2.drawContours(image, [box], -1, (0, 255, 0), 2)
    cv2.putText(image, f"{distance:.2f}cm", 
                (image.shape[1] - 300, image.shape[0] - 20),
                cv2.FONT_HERSHEY_SIMPLEX, 2.0, (0, 255, 0), 3)
    
    cv2.imshow("Distance Measurement", image)
    cv2.waitKey(0)
    return distance

4. 实战应用与效果优化

现在我们已经实现了基础功能,接下来让我们看看如何在实际项目中应用并优化这个系统。

4.1 完整工作流程

  1. 初始标定

    • 将A4纸放置在距离摄像头30cm处
    • 拍摄照片并保存为reference.jpg
    • 运行calculate_focal_length函数获取焦距
  2. 距离测量

    • 移动A4纸到不同位置
    • 对每个位置拍照并运行measure_distance函数
    • 比较测量结果与实际距离

4.2 提高精度的实用技巧

  • 多角度标定法:在不同距离下拍摄多张参考图像,计算平均焦距
  • 动态阈值调整:根据光照条件自动调整Canny边缘检测的阈值
  • 轮廓过滤:只处理符合A4纸长宽比的轮廓,排除干扰物体
  • 移动平均滤波:对视频流中的连续帧进行平均,减少瞬时误差
# 改进版的标记检测函数,增加轮廓过滤
def find_marker_enhanced(image):
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    gray = cv2.GaussianBlur(gray, (5, 5), 0)
    edged = cv2.Canny(gray, 35, 125)
    
    contours, _ = cv2.findContours(edged.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
    
    valid_contours = []
    for c in contours:
        rect = cv2.minAreaRect(c)
        width, height = rect[1]
        aspect_ratio = max(width, height) / min(width, height)
        
        # A4纸的长宽比约为1.414 (297/210)
        if 1.3 < aspect_ratio < 1.5:
            valid_contours.append(c)
    
    if valid_contours:
        c = max(valid_contours, key=cv2.contourArea)
        return cv2.minAreaRect(c)
    else:
        return None

4.3 实际应用场景扩展

这个基础技术可以扩展到许多有趣的应用中:

  • 智能小车避障:实时测量前方障碍物距离
  • 物品尺寸测量:结合已知距离,计算物体实际尺寸
  • 互动装置:基于距离的人机交互界面
  • 简易3D扫描:多角度距离测量重建物体形状

在最近的一个创客项目中,我使用这个技术为自动导引车(AGV)开发了低成本避障系统。通过将摄像头安装在车体前方,系统能够实时检测2米范围内的障碍物,精度达到了±3cm,完全满足室内低速导航的需求。

Logo

小龙虾开发者社区是 CSDN 旗下专注 OpenClaw 生态的官方阵地,聚焦技能开发、插件实践与部署教程,为开发者提供可直接落地的方案、工具与交流平台,助力高效构建与落地 AI 应用

更多推荐