一、引言:YOLOv11 为何能做安全距离测算?
随着智能交通、工业安防等场景对距离监测需求激增,传统雷达、激光设备因成本高、部署难受限。YOLOv11 作为最新一代目标检测算法,凭借实时性(30+ FPS) 与高精度检测特性,成为视觉测距的理想基座 ------ 其输出的目标边界框坐标,可直接关联几何模型计算真实距离,实现低成本、易部署的安全监测方案。
本文将聚焦单目视觉方案(最通用场景),详解从相机标定到安全预警的全流程,附代码实现与实战案例。

二、核心原理:3 步打通 "检测→测距→判定" 逻辑
2.1 基础:YOLOv11 的检测输出如何支撑测距?
YOLOv11 通过端到端网络输出目标的边界框(x1,y1,x2,y2) 、类别标签与置信度。其中边界框的像素尺寸(宽度 w=x2-x1,高度 h=y2-y1)是测距关键 ------ 基于 "近大远小" 的透视原理,结合相机参数与目标真实尺寸,即可反推距离。
2.2 核心:单目视觉测距的数学模型
单目测距依赖针孔相机模型与相似三角形原理,核心公式仅需 3 个参数:
Matlab
距离Z(米)= (目标实际尺寸H × 相机焦距f) / 目标像素尺寸h
- 参数定义:
-
H:目标真实高度 / 宽度(如轿车宽 1.8 米、行人高 1.7 米)
-
f:相机焦距(像素单位,需标定获取)
-
h:YOLO 检测框的像素高度 / 宽度
推导过程(直观理解):
Matlab
真实场景中:相机焦距f ↔ 目标实际尺寸H → 形成三角形1
图像中:焦距f(像素) ↔ 检测框尺寸h(像素) → 形成三角形2
两三角形相似 → Z/H = f/h → Z = (H×f)/h
2.3 前提:相机标定(关键步骤,误差源头)
未标定的相机将导致测距误差超 30%,标定核心是获取内参矩阵 K:
-
fx/fy:x/y 轴焦距(像素)
-
cx/cy:图像主点坐标(通常为图像中心)
标定实操步骤(OpenCV 实现):
-
打印棋盘格标定板(如 9×6 角点)
-
从不同角度拍摄 15 + 张标定板图像
-
运行标定代码获取参数:
python
import cv2
import numpy as np
# 1. 准备标定板参数
chessboard_size = (9, 6)
square_size = 0.025 # 棋盘格边长(米)
# 2. 提取角点
obj_points = [] # 真实世界坐标
img_points = [] # 图像像素坐标
objp = np.zeros((np.prod(chessboard_size), 3), np.float32)
objp[:, :2] = np.mgrid[0:chessboard_size[0], 0:chessboard_size[1]].T.reshape(-1, 2) * square_size
# 3. 遍历标定图计算
images = ["calib_1.jpg", "calib_2.jpg"] # 标定图像列表
for img_path in images:
img = cv2.imread(img_path)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, corners = cv2.findChessboardCorners(gray, chessboard_size, None)
if ret:
obj_points.append(objp)
img_points.append(corners)
# 4. 计算内参
ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(
obj_points, img_points, gray.shape[::-1], None, None
)
fx, fy = mtx[0, 0], mtx[1, 1] # 提取焦距
cx, cy = mtx[0, 2], mtx[1, 2] # 提取主点坐标
三、实战流程:YOLOv11 安全距离测算 4 步落地
以 "智能交通车辆安全距离监测" 为例(安全阈值设为 5 米),完整实现代码与解析如下:
3.1 环境搭建
bash
# 核心依赖
pip install ultralytics==8.2.0 # YOLOv11需此版本
pip install opencv-python numpy scipy
3.2 模型加载与目标检测
使用预训练 YOLOv11 模型检测车辆,输出边界框信息:
python
from ultralytics import YOLO
# 加载YOLOv11模型
model = YOLO("yolov11n.pt") # 轻量化模型,n/s/m/l可选
def detect_vehicles(frame):
"""检测图像中的车辆,返回边界框与置信度"""
results = model(frame, stream=True)
vehicles = [] # 存储格式:(x1,y1,x2,y2, 置信度)
for r in results:
boxes = r.boxes
for box in boxes:
# 筛选车辆类别(COCO数据集类别2为汽车)
if box.cls == 2 and box.conf > 0.5:
x1, y1, x2, y2 = map(int, box.xyxy[0])
vehicles.append((x1, y1, x2, y2, float(box.conf)))
return vehicles
3.3 距离计算函数实现
结合标定参数与车辆真实尺寸(轿车宽 1.8 米):
python
# 相机标定参数(示例值,需替换为实际标定结果)
FX = 1200.0 # x轴焦距(像素)
VEHICLE_WIDTH = 1.8 # 车辆实际宽度(米)
def calculate_distance(box_width):
"""
计算车辆与相机的距离
box_width: 检测框像素宽度(x2-x1)
"""
if box_width == 0:
return 0.0
# 应用核心公式
distance = (VEHICLE_WIDTH * FX) / box_width
return round(distance, 2)
# 示例:检测框宽100像素时
print(calculate_distance(100)) # 输出:21.60米(符合近大远小逻辑)
3.4 安全判定与结果可视化
标记危险距离并实时显示:
python
import cv2
SAFE_DISTANCE = 5.0 # 安全距离阈值(米)
def draw_results(frame, vehicles):
"""绘制检测框、距离与安全状态"""
for (x1, y1, x2, y2, conf) in vehicles:
# 计算距离与宽度
box_width = x2 - x1
distance = calculate_distance(box_width)
# 判定安全状态
color = (0, 255, 0) if distance >= SAFE_DISTANCE else (0, 0, 255)
label = f"Car: {distance}m"
# 绘制
cv2.rectangle(frame, (x1, y1), (x2, y2), color, 2)
cv2.putText(frame, label, (x1, y1-10),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 2)
return frame
# 视频流处理主逻辑
cap = cv2.VideoCapture("traffic.mp4") # 输入视频/摄像头(0为本地摄像头)
while cap.isOpened():
ret, frame = cap.read()
if not ret:
break
vehicles = detect_vehicles(frame)
frame_with_results = draw_results(frame, vehicles)
cv2.imshow("Safety Distance Monitoring", frame_with_results)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
四、场景扩展:从车辆到多场景适配
4.1 社交距离监测(疫情防控场景)
-
目标:行人(COCO 类别 0)
-
参数调整:行人实际肩宽 0.4 米,安全距离 2 米
-
核心优化:计算行人质心距离(而非边界框宽度):
python
def calculate_centroid_distance(box1, box2):
"""计算两个目标的质心距离(像素)"""
cx1 = (box1[0] + box1[2]) // 2
cy1 = (box1[1] + box1[3]) // 2
cx2 = (box2[0] + box2[2]) // 2
cy2 = (box2[1] + box2[3]) // 2
# 像素距离转实际距离(需标定像素-米比例)
pixel_per_meter = 50 # 1米=50像素(标定获取)
return np.sqrt((cx1-cx2)**2 + (cy1-cy2)** 2) / pixel_per_meter
4.2 工业机械臂安全监测
-
目标:机械臂(自定义训练数据集)
-
参数:机械臂末端实际尺寸 0.2 米,安全距离 1 米
-
进阶功能:结合卡尔曼滤波预测轨迹,提前预警
五、精度优化:解决 90% 的测距误差问题
5.1 常见误差来源与对策
| 误差原因 | 解决方案 |
|---|---|
| 目标尺寸差异 | 按类别设置尺寸库(如卡车宽 2.5 米、轿车 1.8 米) |
| 相机抖动 | 加入卡尔曼滤波平滑距离值 |
| 光照 / 遮挡 | 数据增强训练模型 + NMS 优化检测框 |
| 透视角度偏差 | 引入俯仰角修正公式:Z = h_cam /tan (θ) |
5.2 进阶优化代码(卡尔曼滤波)

python
from filterpy.kalman import KalmanFilter
def init_kalman_filter():
"""初始化卡尔曼滤波器"""
kf = KalmanFilter(dim_x=2, dim_z=1)
kf.x = np.array([[0.], [0.]]) # 初始状态(距离,速度)
kf.F = np.array([[1., 1.], [0., 1.]]) # 状态转移矩阵
kf.H = np.array([[1., 0.]]) # 观测矩阵
kf.R = np.array([[0.1]]) # 观测噪声
kf.P = np.array([[1., 0.], [0., 1.]]) # 协方差矩阵
return kf
# 使用示例
kf = init_kalman_filter()
raw_distance = calculate_distance(box_width)
kf.predict()
kf.update(raw_distance)
smoothed_distance = kf.x[0][0] # 平滑后的距离
六、总结与展望
YOLOv11 的实时检测能力与单目测距的低成本特性,使其成为安全距离监测的优选方案。核心在于 "标定准确参数 + 匹配目标尺寸 + 优化滤波算法"------ 普通场景可直接复用本文代码框架,仅需替换标定参数与目标尺寸库;高精度场景可结合双目视觉(基线 B + 视差 d 计算 Z=f・B/d)进一步提升精度。