用Python+OpenCV给摄像头测距:从A4纸到真实世界的距离感知(附完整代码)

张开发
2026/4/18 18:01:21 15 分钟阅读

分享文章

用Python+OpenCV给摄像头测距:从A4纸到真实世界的距离感知(附完整代码)
用PythonOpenCV实现单目视觉测距从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 numpy1.2 硬件准备清单普通USB摄像头720p以上分辨率效果更佳标准A4纸210×297mm测量工具如卷尺用于初始距离测量均匀光照环境避免强光直射或阴影干扰提示摄像头最好固定在一个位置避免在标定过程中移动。手机摄像头也可以使用但需要通过相应接口获取视频流。2. 核心原理与数学推导单目测距的核心公式基于相似三角形原理F (P × D) / W其中F相机焦距像素单位P物体在图像中的像素宽度D相机到物体的实际距离W物体的实际宽度这个公式的推导过程其实非常直观在初始距离D处拍摄已知宽度W的物体如A4纸测量其在图像中的像素宽度P计算得到焦距F当物体移动时通过检测新的像素宽度P即可计算新的距离D (W × F)/P2.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, keycv2.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_length3.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 distance4. 实战应用与效果优化现在我们已经实现了基础功能接下来让我们看看如何在实际项目中应用并优化这个系统。4.1 完整工作流程初始标定将A4纸放置在距离摄像头30cm处拍摄照片并保存为reference.jpg运行calculate_focal_length函数获取焦距距离测量移动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, keycv2.contourArea) return cv2.minAreaRect(c) else: return None4.3 实际应用场景扩展这个基础技术可以扩展到许多有趣的应用中智能小车避障实时测量前方障碍物距离物品尺寸测量结合已知距离计算物体实际尺寸互动装置基于距离的人机交互界面简易3D扫描多角度距离测量重建物体形状在最近的一个创客项目中我使用这个技术为自动导引车(AGV)开发了低成本避障系统。通过将摄像头安装在车体前方系统能够实时检测2米范围内的障碍物精度达到了±3cm完全满足室内低速导航的需求。

更多文章