用Python和YOLOv5做个‘尺子’:手把手教你实现单目测距(附完整代码)

用Python和YOLOv5做个‘尺子’:手把手教你实现单目测距(附完整代码) 用Python和YOLOv5打造智能测距仪从原理到落地的完整实践指南在智能家居和工业自动化领域物体距离测量一直是个有趣且实用的技术挑战。传统测距工具如卷尺或激光测距仪虽然精确但缺乏智能化元素。本文将带您用普通摄像头和YOLOv5模型构建一个能自动识别常见物体并计算距离的Python工具。这个项目完美融合了计算机视觉的趣味性与实用性特别适合想深入理解单目视觉原理的技术爱好者。1. 环境搭建与工具准备工欲善其事必先利其器。我们需要配置一个稳定的Python环境来运行YOLOv5和OpenCV。推荐使用Python 3.8版本这个版本在兼容性和性能上都有不错的表现。首先创建并激活虚拟环境python -m venv distance_measure source distance_measure/bin/activate # Linux/Mac distance_measure\Scripts\activate # Windows安装核心依赖库pip install torch torchvision opencv-python matplotlib numpy注意如果使用GPU加速需要安装对应版本的PyTorch CUDA版本YOLOv5的获取很简单直接从官方仓库克隆即可git clone https://github.com/ultralytics/yolov5 cd yolov5 pip install -r requirements.txt常见问题排查报错ImportError: libGL.so.1: cannot open shared object file解决方案sudo apt install libgl1-mesa-glx(Ubuntu)报错DLL load failed while importing cv2解决方案重新安装OpenCVpip install --force-reinstall opencv-python-headless2. 相机标定获取关键参数单目测距的核心公式是距离 (物体实际宽度 × 焦距) / 图像中的像素宽度要计算距离我们需要先确定相机的焦距。这里介绍一种实用的标定方法准备一个已知尺寸的物体如15cm宽的杯子在已知距离如20cm处拍摄该物体用YOLOv5检测物体的像素宽度代入公式计算焦距焦距计算代码实现def calculate_focal_length(known_width, known_distance, pixel_width): return (pixel_width * known_distance) / known_width # 示例杯子实际宽度15cm拍摄距离20cm检测到像素宽度为300px focal_length calculate_focal_length(15, 20, 300) print(f计算得到的焦距{focal_length:.2f}像素)标定质量检查表[ ] 物体与相机保持水平[ ] 拍摄环境光线充足[ ] 物体占据图像合理比例(建议30%-70%)[ ] 多次测量取平均值3. YOLOv5目标检测集成YOLOv5提供了简洁的API接口我们可以轻松集成到测距系统中。以下是一个检测并返回边界框的示例import torch # 加载预训练模型 model torch.hub.load(ultralytics/yolov5, yolov5s, pretrainedTrue) def detect_objects(image_path): # 执行检测 results model(image_path) # 提取杯子类别的检测结果(杯子在COCO数据集中类别为41) cups results.pred[0][results.pred[0][:, 5] 41] if len(cups) 0: # 返回第一个检测到的杯子的边界框[x1,y1,x2,y2] return cups[0][:4].cpu().numpy() else: return None常见检测问题优化问题现象可能原因解决方案检测不到物体物体太小调整拍摄距离或使用更高分辨率误检测率高背景复杂使用更精确的模型(yolov5m/l)边界框抖动视频帧处理添加简单的跟踪算法4. 距离计算与可视化有了焦距和检测框距离计算就水到渠成了。我们还需要考虑一些实际因素来提高精度def calculate_distance(known_width, focal_length, pixel_width, angle_correction1.0): 计算物体到相机的距离 :param known_width: 物体实际宽度(cm) :param focal_length: 相机焦距(像素) :param pixel_width: 图像中物体宽度(像素) :param angle_correction: 角度校正因子(0.9-1.1) :return: 距离(cm) base_distance (known_width * focal_length) / pixel_width return base_distance * angle_correction def visualize_result(image, bbox, distance): 在图像上绘制检测框和距离信息 x1, y1, x2, y2 bbox cv2.rectangle(image, (x1, y1), (x2, y2), (0, 255, 0), 2) label f{distance:.1f}cm cv2.putText(image, label, (x1, y1-10), cv2.FONT_HERSHEY_SIMPLEX, 0.9, (0, 255, 0), 2) return image精度提升技巧多物体平均检测同一物体的多个实例取平均值多帧平滑视频流中使用移动平均减少抖动高度补偿同时使用宽度和高度信息进行交叉验证5. 完整系统集成与优化将各个模块整合成一个完整的测距系统以下是主程序的逻辑流程import cv2 from detection import detect_objects from calibration import calculate_focal_length class DistanceMeasurer: def __init__(self, known_width, calibration_distance): self.known_width known_width self.calibration_distance calibration_distance self.focal_length None def calibrate(self, calibration_image): bbox detect_objects(calibration_image) if bbox is not None: pixel_width bbox[2] - bbox[0] self.focal_length calculate_focal_length( self.known_width, self.calibration_distance, pixel_width) return True return False def measure(self, image_path): if self.focal_length is None: raise ValueError(请先校准相机) bbox detect_objects(image_path) if bbox is not None: pixel_width bbox[2] - bbox[0] distance calculate_distance( self.known_width, self.focal_length, pixel_width) image cv2.imread(image_path) return visualize_result(image, bbox, distance) return None系统优化方向性能优化使用ONNX或TensorRT加速模型推理功能扩展添加对多种物体的支持书本、手机等交互改进开发简单的GUI界面部署方案打包为独立可执行文件6. 实际应用与误差分析在实际测试中我们发现几个影响精度的关键因素测试数据示例杯子宽度15cm实际距离(cm)测量距离(cm)误差率(%)3031.24.05052.85.6100108.38.3误差主要来源相机镜头畸变物体与相机不平行检测框位置偏差标定时的测量误差降低误差的实用技巧使用棋盘格进行相机畸变校正保持被测物体与相机平行多次测量取平均值对不同距离区间使用不同的校正系数在智能家居场景中这个系统可以用来测量快递包裹尺寸监控物品摆放位置辅助机器人导航避障智能储物空间管理