当前位置: 首页 > news >正文

用Python和YOLOv5给摄像头装上‘尺子’:一个杯子引发的单目测距实战

用Python和YOLOv5给摄像头装上‘尺子’:一个杯子引发的单目测距实战

当你手边只有一个普通的USB摄像头,却想让它具备测量物体距离的"超能力"时,单目测距技术就是你的魔法棒。这个看似高深的计算机视觉应用,其实用生活中常见的物品(比如一个马克杯)就能轻松实现。本文将带你从零开始,用Python和YOLOv5打造一个低成本、高趣味性的单目测距系统。

1. 环境准备与工具选择

在开始之前,我们需要搭建一个稳定的开发环境。推荐使用Python 3.8或更高版本,这个版本在兼容性和性能上都有不错的表现。以下是需要安装的核心库:

pip install torch torchvision opencv-python numpy matplotlib

对于YOLOv5,我们直接从官方仓库克隆最新版本:

git clone https://github.com/ultralytics/yolov5 cd yolov5 pip install -r requirements.txt

注意:如果使用GPU加速,建议安装CUDA 11.3和对应版本的PyTorch以获得最佳性能。

硬件方面,任何一款支持USB3.0的1080p摄像头都能满足需求。我测试使用的是罗技C920,但几十元的普通摄像头同样可以工作。关键在于标定过程的准确性,而不是设备的高端程度。

2. 摄像头标定:用马克杯当标尺

单目测距的核心在于理解相似三角形原理。我们需要先确定摄像头的焦距,这个过程称为标定。具体步骤如下:

  1. 准备一个已知尺寸的物体(如宽15cm的马克杯)
  2. 将物体放置在距离摄像头20cm处并拍照
  3. 使用YOLOv5检测物体在图像中的像素宽度
  4. 通过公式计算焦距:焦距 = (像素宽度 × 实际距离) / 实际宽度
def calculate_focal_length(known_width, known_distance, pixel_width): return (pixel_width * known_distance) / known_width

实际操作中,建议拍摄多组不同距离的照片求取平均焦距值,这样可以减少测量误差。下表展示了我用马克杯标定时的三组数据:

实际距离(cm)像素宽度(px)计算焦距(px)
20320426.67
25256426.67
30213426.00

可以看到,三组数据计算出的焦距非常接近,最终我们取平均值426.44px作为标定结果。这个值将作为后续所有距离计算的基础。

3. 构建完整的测距流水线

有了焦距参数,我们就可以构建完整的测距系统了。系统工作流程分为三个主要步骤:

  1. 物体检测:使用YOLOv5实时检测视频流中的目标物体
  2. 像素测量:获取物体在图像中的包围框宽度(像素单位)
  3. 距离计算:应用相似三角形原理转换像素距离为实际距离

核心计算函数如下:

def calculate_distance(known_width, focal_length, pixel_width): return (known_width * focal_length) / pixel_width

为了提高实用性,我们可以添加一些增强功能:

  • 多物体支持:通过修改YOLOv5的输出处理,可以同时测量多个物体的距离
  • 单位转换:添加厘米/英寸的单位切换功能
  • 历史记录:保存最近几次的测量结果用于对比分析

一个完整的处理帧函数可能长这样:

def process_frame(frame, model, focal_length, known_width): # 使用YOLOv5进行物体检测 results = model(frame) # 解析检测结果 detections = results.pandas().xyxy[0] for _, det in detections.iterrows(): if det['name'] == 'cup': # 只处理目标类别 pixel_width = det['xmax'] - det['xmin'] distance = calculate_distance(known_width, focal_length, pixel_width) # 在图像上绘制结果 cv2.rectangle(frame, (int(det['xmin']), int(det['ymin'])), (int(det['xmax']), int(det['ymax'])), (0,255,0), 2) cv2.putText(frame, f"{distance:.1f}cm", (int(det['xmin']), int(det['ymin'])-10), cv2.FONT_HERSHEY_SIMPLEX, 0.9, (0,255,0), 2) return frame

4. 误差分析与优化策略

在实际测试中,我发现几个主要误差来源:

  1. 角度偏差:当摄像头与物体不在同一水平面时,测量结果会偏大
  2. 镜头畸变:普通摄像头的桶形畸变会影响边缘区域的测量精度
  3. 标定误差:初始焦距测量的准确性直接影响所有后续结果

针对这些问题,可以采用以下优化策略:

  • 多角度标定法:在不同角度拍摄标定物体,建立角度-距离补偿模型
  • ROI限制:只使用图像中心区域进行测量,减少镜头畸变影响
  • 移动平均滤波:对连续视频帧的结果进行平滑处理
# 简单的移动平均滤波实现 class DistanceFilter: def __init__(self, window_size=5): self.window = [] self.size = window_size def update(self, value): self.window.append(value) if len(self.window) > self.size: self.window.pop(0) return sum(self.window) / len(self.window)

下表对比了优化前后的测量误差(单位:cm):

实际距离原始测量优化后测量
30cm32.4cm30.8cm
50cm56.7cm51.2cm
70cm82.3cm72.6cm

虽然误差随距离增加而增大,但优化后的结果明显更接近真实值。对于日常使用场景,这样的精度已经足够。

5. 创意应用与扩展思路

掌握了基础的单目测距技术后,可以尝试许多有趣的扩展应用:

  • 智能货架监控:实时监测货架上商品的取放情况
  • 互动艺术装置:根据观众距离变化产生不同的视觉效果
  • 简易3D扫描:结合物体移动轨迹重建粗略的3D模型

一个特别实用的扩展是距离警报系统,当物体进入预设的危险距离时会发出警告:

def distance_alert(frame, distance, safe_distance=50): if distance < safe_distance: cv2.putText(frame, "WARNING: Too close!", (50,50), cv2.FONT_HERSHEY_SIMPLEX, 1.5, (0,0,255), 3) # 可以添加声音报警 # import winsound # winsound.Beep(1000, 200) return frame

在实现这些扩展功能时,记得考虑以下几点:

  1. 性能优化:对于实时应用,可以考虑使用YOLOv5s等轻量级模型
  2. 多线程处理:将图像采集、处理和显示放在不同线程提高响应速度
  3. 用户界面:添加简单的GUI让非技术人员也能方便使用
# 简单的多线程处理示例 import threading class VideoProcessor: def __init__(self): self.frame = None self.running = True def capture_thread(self): cap = cv2.VideoCapture(0) while self.running: ret, self.frame = cap.read() def process_thread(self): while self.running: if self.frame is not None: processed_frame = process_frame(self.frame.copy()) cv2.imshow('Result', processed_frame) if cv2.waitKey(1) == ord('q'): self.running = False

6. 实战技巧与常见问题解决

在实际开发过程中,我总结了一些有价值的经验:

  • 光照条件:过强或过弱的光线都会影响检测精度,建议在均匀光照环境下使用
  • 物体选择:高对比度的纯色物体检测效果最好,避免使用图案复杂的物品
  • 摄像头固定:测量时保持摄像头稳定,手持会导致结果波动

遇到检测不稳定的情况时,可以尝试以下调试步骤:

  1. 检查YOLOv5的置信度阈值(默认0.25),适当提高可减少误检
  2. 验证标定过程是否正确,特别是实际距离的测量要精确
  3. 测试不同分辨率,有时降低分辨率反而能提高检测稳定性
# 调整YOLOv5的检测参数 model.conf = 0.5 # 置信度阈值 model.iou = 0.45 # IOU阈值

对于想进一步深入学习的开发者,推荐探索以下方向:

  • 立体视觉:尝试用两个摄像头实现更精确的测距
  • 深度学习:训练自定义的物体检测模型提高特定场景的准确率
  • 传感器融合:结合红外或超声波传感器提升系统鲁棒性

在项目开发过程中,版本控制也很重要。我习惯使用如下目录结构:

mono_distance/ ├── configs/ # 配置文件 ├── data/ # 测试图像和视频 ├── models/ # 训练好的模型 ├── utils/ # 工具函数 ├── main.py # 主程序 └── requirements.txt # 依赖库
http://www.jsqmd.com/news/906806/

相关文章:

  • 微波定向耦合器:原理、指标、架构与设计实例
  • 保姆级教程:在Ubuntu 20.04上从源码编译运行Cartographer ROS(含常见错误排查)
  • 视频中如何添加自定义水印,一招搞定
  • 从P波到T波:如何用Python+OpenCV给心电波形图做“自动体检”?
  • 3个真实场景告诉你:为什么猫抓插件是网页视频下载的终极解决方案?
  • 别再只用准确率了!用Python实战Cohen‘s Kappa评估你的分类模型(附代码避坑指南)
  • 国产化存储实战:在银河麒麟V10 SP1服务器上配置iSCSI多路径(含multipath避坑指南)
  • 2026年当前,谁在定义靠谱优秀的钢制活动柜生产厂商新标准? - 2026年企业资讯
  • 卡牌抽取游戏
  • 北京APP定制开发费用构成与行业选型综合研究
  • 别再死记硬背!彻底搞懂 Java 泛型通配符、协变逆变与 PECS 原理
  • 实测在蜂窝网络下使用Taotoken调用大模型API的成功率与体验
  • 个人认为目前为止java后端面试最有效且快捷的方法
  • 别再死记硬背了!用‘找书’和‘找章节’的比喻,5分钟搞懂Linux内存管理中的一级/二级页表
  • 背包问题 01背包/完全背包/多重背包/分组背包/单调队列优多重背包/二维费用背包
  • 别再只懂Apriori了!用Python手写一个超市购物篮分析,从牛奶面包数据里挖出隐藏的关联规则
  • 番茄小说下载器终极指南:如何轻松下载并离线阅读番茄小说
  • 注塑车间的透明化革命:盘古信息如何重塑注塑成型行业的数字未来?
  • AI营销新纪元:多智能体协作破局
  • 2026年5月口碑好的武汉地下管线漏水检测公司排行榜厂家推荐榜,家庭/厂房/市政管道漏水检测厂家选择指南 - 海棠依旧大
  • Nexknit Gateway v0.2.0:全新采集器与告警系统上线
  • 回民街的坑很多,但洒金桥那条巷子藏着真正的老味道
  • 2026年5月衡水档案柜之选:深度剖析河北精纳金属制品有限公司 - 2026年企业资讯
  • Arduino与Visuino实现电机定时启停:可视化编程与L298N驱动详解
  • Windows系统的用户管理操作
  • 限时解密|金融/医疗/教育三大垂直领域AI语音合成真实落地瓶颈:92%项目因“微表情语音失真”遭客户拒用
  • 知识IP卡在变现第一步:创客匠人用一套陪跑系统回答“谁来陪你落地”
  • 据说刷一个百度热搜的成本在1万以上
  • 制作儿童英文教学视频的AI工具选型指南
  • 面向美区市场直播拍卖,跨境网络链路选型全指南