1. YOLOv5与单目测距技术概述在计算机视觉领域目标检测和距离测量是两个非常实用的功能。YOLOv5作为目前最流行的目标检测算法之一以其速度快、精度高著称。而单目测距技术则允许我们仅用普通摄像头就能估算物体到相机的距离这在机器人导航、智能监控等场景中非常有用。我第一次接触这个技术组合是在开发一个智能仓储机器人项目时。当时需要让机器人自动识别货架上的物品并估算距离但预算有限无法使用昂贵的激光雷达。经过多次尝试发现YOLOv5单目测距的方案既经济又实用测距误差可以控制在5%以内。单目测距的核心原理其实很直观 - 就像人类用一只眼睛判断距离一样。当你知道某个物体的实际大小比如一个人的平均身高又知道它在图像中占据了多少像素时结合相机的焦距参数就能通过三角形相似原理计算出距离。这个看似简单的原理在实际工程化时会遇到不少挑战比如如何准确获取相机焦距、如何处理不同类别物体的尺寸差异等。2. 环境搭建与模型准备2.1 基础环境配置建议使用Python 3.8和PyTorch 1.7环境。这是我验证过最稳定的组合conda create -n yolo_distance python3.8 conda activate yolo_distance pip install torch1.7.1cu110 torchvision0.8.2cu110 -f https://download.pytorch.org/whl/torch_stable.html其他依赖库可以通过以下命令安装pip install opencv-python numpy matplotlib tqdm2.2 YOLOv5模型获取与验证直接从官方仓库克隆最新代码git clone https://github.com/ultralytics/yolov5 cd yolov5我推荐使用yolov5s.pt这个轻量级模型作为起点它在速度和精度之间取得了很好的平衡。下载预训练模型wget https://github.com/ultralytics/yolov5/releases/download/v6.0/yolov5s.pt测试模型是否正常工作python detect.py --source data/images/bus.jpg --weights yolov5s.pt如果一切顺利你会在runs/detect/exp目录下看到检测结果图片。这个步骤验证了基础检测功能正常接下来我们要加入测距功能。3. 单目测距算法实现3.1 测距原理详解单目测距的核心公式是距离 D (焦距 F × 物体实际高度 W) / 图像中物体高度 P这个公式基于相似三角形原理。想象你站在路边看远处的电线杆电线杆实际高度是固定的离你越远它在你的视野中就显得越小。通过量化这个关系我们就能反推出距离。在实际应用中需要确定三个关键参数焦距(F)这是相机的固有参数通常以像素为单位。可以通过相机标定获得或者用已知距离的物体反推计算。物体实际高度(W)需要预先设定不同类别物体的典型尺寸。比如行人1.7米轿车1.5米高度自行车1.1米高度图像中物体高度(P)这是YOLOv5检测框的高度以像素为单位。3.2 代码实现与集成在YOLOv5的utils目录下新建distance.py文件实现测距函数# 相机焦距(根据实际相机调整) FOCAL_LENGTH 1420 # 典型物体高度(米) PERSON_HEIGHT 1.7 CAR_HEIGHT 1.5 BICYCLE_HEIGHT 1.1 def calculate_distance(detection_class, box_height): 根据检测类别和框高度计算距离 if detection_class person: return (FOCAL_LENGTH * PERSON_HEIGHT) / box_height elif detection_class car: return (FOCAL_LENGTH * CAR_HEIGHT) / box_height elif detection_class bicycle: return (FOCAL_LENGTH * BICYCLE_HEIGHT) / box_height else: return 0然后在plots.py中修改plot_one_box函数在绘制检测框时调用测距函数def plot_one_box(x, img, colorNone, labelNone, line_thickness3, nameNone): # 获取检测框坐标 c1, c2 (int(x[0]), int(x[1])), (int(x[2]), int(x[3])) # 计算框高度 box_height c2[1] - c1[1] # 调用测距函数 distance calculate_distance(name, box_height) # 在标签中添加距离信息 if distance 0: label f {distance:.2f}m # 绘制检测框 cv2.rectangle(img, c1, c2, color, thicknessline_thickness) # 绘制标签 if label: tf max(line_thickness - 1, 1) t_size cv2.getTextSize(label, 0, fontScaleline_thickness/3, thicknesstf)[0] c2 c1[0] t_size[0], c1[1] - t_size[1] - 3 cv2.rectangle(img, c1, c2, color, -1) cv2.putText(img, label, (c1[0], c1[1] - 2), 0, line_thickness/3, [225, 255, 255], thicknesstf, lineTypecv2.LINE_AA)4. 相机标定与参数调优4.1 焦距标定方法焦距(F)是最关键的参数我推荐使用以下两种方法标定已知距离法将一个已知高度的物体(如30cm的标定板)放置在已知距离(如2米)处拍照并测量物体在图像中的像素高度根据公式 F (P × D)/W 计算焦距视场角法查找相机规格书中的水平视场角(θ)和图像宽度(w)使用公式 F w/(2×tan(θ/2)) 计算焦距我在实际项目中发现不同焦距设置对测距精度影响很大。下面是一个对比实验数据焦距值(pixel)1米处误差5米处误差10米处误差13008%12%15%14202%3%5%1500-5%-8%-10%4.2 物体高度参数优化不同场景下物体的实际高度会有差异。比如亚洲成年人平均身高约1.65米欧美成年人平均身高约1.75米儿童身高可能在1.2-1.5米之间为了提高精度可以针对特定场景收集统计数据对不同子类别使用不同高度值(如区分成年人和儿童)添加高度估计模型来动态调整5. 工程部署与性能优化5.1 多线程处理在实际部署中我发现单线程处理很难满足实时性要求。下面是改进后的多线程架构import threading from queue import Queue class ProcessingThread(threading.Thread): def __init__(self, input_queue, output_queue): threading.Thread.__init__(self) self.input_queue input_queue self.output_queue output_queue def run(self): while True: frame self.input_queue.get() # 执行检测和测距 results detect_and_measure(frame) self.output_queue.put(results)5.2 模型量化加速为了在边缘设备上部署可以使用PyTorch的量化功能# 量化模型 model torch.quantization.quantize_dynamic( model, {torch.nn.Linear}, dtypetorch.qint8 ) # 保存量化模型 torch.save(model.state_dict(), yolov5s_quantized.pt)量化后的模型大小可以减少约4倍推理速度提升2-3倍而精度损失通常在1-2%以内。5.3 实际部署注意事项相机安装高度建议安装在2-3米高度俯角10-30度为宜光照条件避免强逆光和极端低光环境帧率设置一般15-30FPS足够过高会增加计算负担温度监控边缘设备长时间运行可能过热需要添加散热措施我在一个智能停车场项目中部署时发现夏季高温会导致NVIDIA Jetson设备降频。后来通过添加散热风扇和优化推理间隔解决了这个问题。
【YOLO实战测距】从原理到部署:基于YOLOv5的单目深度估计算法工程化实践
1. YOLOv5与单目测距技术概述在计算机视觉领域目标检测和距离测量是两个非常实用的功能。YOLOv5作为目前最流行的目标检测算法之一以其速度快、精度高著称。而单目测距技术则允许我们仅用普通摄像头就能估算物体到相机的距离这在机器人导航、智能监控等场景中非常有用。我第一次接触这个技术组合是在开发一个智能仓储机器人项目时。当时需要让机器人自动识别货架上的物品并估算距离但预算有限无法使用昂贵的激光雷达。经过多次尝试发现YOLOv5单目测距的方案既经济又实用测距误差可以控制在5%以内。单目测距的核心原理其实很直观 - 就像人类用一只眼睛判断距离一样。当你知道某个物体的实际大小比如一个人的平均身高又知道它在图像中占据了多少像素时结合相机的焦距参数就能通过三角形相似原理计算出距离。这个看似简单的原理在实际工程化时会遇到不少挑战比如如何准确获取相机焦距、如何处理不同类别物体的尺寸差异等。2. 环境搭建与模型准备2.1 基础环境配置建议使用Python 3.8和PyTorch 1.7环境。这是我验证过最稳定的组合conda create -n yolo_distance python3.8 conda activate yolo_distance pip install torch1.7.1cu110 torchvision0.8.2cu110 -f https://download.pytorch.org/whl/torch_stable.html其他依赖库可以通过以下命令安装pip install opencv-python numpy matplotlib tqdm2.2 YOLOv5模型获取与验证直接从官方仓库克隆最新代码git clone https://github.com/ultralytics/yolov5 cd yolov5我推荐使用yolov5s.pt这个轻量级模型作为起点它在速度和精度之间取得了很好的平衡。下载预训练模型wget https://github.com/ultralytics/yolov5/releases/download/v6.0/yolov5s.pt测试模型是否正常工作python detect.py --source data/images/bus.jpg --weights yolov5s.pt如果一切顺利你会在runs/detect/exp目录下看到检测结果图片。这个步骤验证了基础检测功能正常接下来我们要加入测距功能。3. 单目测距算法实现3.1 测距原理详解单目测距的核心公式是距离 D (焦距 F × 物体实际高度 W) / 图像中物体高度 P这个公式基于相似三角形原理。想象你站在路边看远处的电线杆电线杆实际高度是固定的离你越远它在你的视野中就显得越小。通过量化这个关系我们就能反推出距离。在实际应用中需要确定三个关键参数焦距(F)这是相机的固有参数通常以像素为单位。可以通过相机标定获得或者用已知距离的物体反推计算。物体实际高度(W)需要预先设定不同类别物体的典型尺寸。比如行人1.7米轿车1.5米高度自行车1.1米高度图像中物体高度(P)这是YOLOv5检测框的高度以像素为单位。3.2 代码实现与集成在YOLOv5的utils目录下新建distance.py文件实现测距函数# 相机焦距(根据实际相机调整) FOCAL_LENGTH 1420 # 典型物体高度(米) PERSON_HEIGHT 1.7 CAR_HEIGHT 1.5 BICYCLE_HEIGHT 1.1 def calculate_distance(detection_class, box_height): 根据检测类别和框高度计算距离 if detection_class person: return (FOCAL_LENGTH * PERSON_HEIGHT) / box_height elif detection_class car: return (FOCAL_LENGTH * CAR_HEIGHT) / box_height elif detection_class bicycle: return (FOCAL_LENGTH * BICYCLE_HEIGHT) / box_height else: return 0然后在plots.py中修改plot_one_box函数在绘制检测框时调用测距函数def plot_one_box(x, img, colorNone, labelNone, line_thickness3, nameNone): # 获取检测框坐标 c1, c2 (int(x[0]), int(x[1])), (int(x[2]), int(x[3])) # 计算框高度 box_height c2[1] - c1[1] # 调用测距函数 distance calculate_distance(name, box_height) # 在标签中添加距离信息 if distance 0: label f {distance:.2f}m # 绘制检测框 cv2.rectangle(img, c1, c2, color, thicknessline_thickness) # 绘制标签 if label: tf max(line_thickness - 1, 1) t_size cv2.getTextSize(label, 0, fontScaleline_thickness/3, thicknesstf)[0] c2 c1[0] t_size[0], c1[1] - t_size[1] - 3 cv2.rectangle(img, c1, c2, color, -1) cv2.putText(img, label, (c1[0], c1[1] - 2), 0, line_thickness/3, [225, 255, 255], thicknesstf, lineTypecv2.LINE_AA)4. 相机标定与参数调优4.1 焦距标定方法焦距(F)是最关键的参数我推荐使用以下两种方法标定已知距离法将一个已知高度的物体(如30cm的标定板)放置在已知距离(如2米)处拍照并测量物体在图像中的像素高度根据公式 F (P × D)/W 计算焦距视场角法查找相机规格书中的水平视场角(θ)和图像宽度(w)使用公式 F w/(2×tan(θ/2)) 计算焦距我在实际项目中发现不同焦距设置对测距精度影响很大。下面是一个对比实验数据焦距值(pixel)1米处误差5米处误差10米处误差13008%12%15%14202%3%5%1500-5%-8%-10%4.2 物体高度参数优化不同场景下物体的实际高度会有差异。比如亚洲成年人平均身高约1.65米欧美成年人平均身高约1.75米儿童身高可能在1.2-1.5米之间为了提高精度可以针对特定场景收集统计数据对不同子类别使用不同高度值(如区分成年人和儿童)添加高度估计模型来动态调整5. 工程部署与性能优化5.1 多线程处理在实际部署中我发现单线程处理很难满足实时性要求。下面是改进后的多线程架构import threading from queue import Queue class ProcessingThread(threading.Thread): def __init__(self, input_queue, output_queue): threading.Thread.__init__(self) self.input_queue input_queue self.output_queue output_queue def run(self): while True: frame self.input_queue.get() # 执行检测和测距 results detect_and_measure(frame) self.output_queue.put(results)5.2 模型量化加速为了在边缘设备上部署可以使用PyTorch的量化功能# 量化模型 model torch.quantization.quantize_dynamic( model, {torch.nn.Linear}, dtypetorch.qint8 ) # 保存量化模型 torch.save(model.state_dict(), yolov5s_quantized.pt)量化后的模型大小可以减少约4倍推理速度提升2-3倍而精度损失通常在1-2%以内。5.3 实际部署注意事项相机安装高度建议安装在2-3米高度俯角10-30度为宜光照条件避免强逆光和极端低光环境帧率设置一般15-30FPS足够过高会增加计算负担温度监控边缘设备长时间运行可能过热需要添加散热措施我在一个智能停车场项目中部署时发现夏季高温会导致NVIDIA Jetson设备降频。后来通过添加散热风扇和优化推理间隔解决了这个问题。