<think>我们已经在之前的代码中实现了两个目标(object_A和object_B)的距离计算和显示。现在用户希望在图像上连线并显示距离。根据用户需求,我们需要在现有代码基础上增加:1.在两个目标之间绘制连线2.在连线的中点位置显示距离数值之前的代码已经计算了距离,现在需要添加绘图功能。修改思路:1.在检测到两个目标都存在时,除了计算距离,还要获取两个目标的中心点坐标(因为我们已经将边界框坐标存储为元组)。2.使用OpenCV的line函数在两个中心点之间绘制连线。3.计算两个中心点的中点,作为显示距离文本的位置。4.使用OpenCV的putText函数在该中点位置显示距离数值。注意:由于我们之前已经将边界框坐标存储为元组,可以直接使用。具体修改代码部分:在条件判断`ifdetected["object_A"]isnotNoneanddetected["object_B"]isnotNone:`内部:-我们已经有了两个边界框的坐标(元组形式)-计算两个中心点:center_A=((boxA[0]+boxA[2])/2,(boxA[1]+boxA[3])/2)center_B=((boxB[0]+boxB[2])/2,(boxB[1]+boxB[3])/2)-绘制连线:cv2.line(screen,(int(center_A[0]),int(center_A[1])),(int(center_B[0]),int(center_B[1])),color,thickness)-计算中点:mid_point=((int((center_A[0]+center_B[0])/2),int((center_A[1]+center_B[1])/2))-显示距离:cv2.putText(screen,f"{dist:.2f}px",mid_point,cv2.FONT_HERSHEY_SIMPLEX,0.8,color,2)注意:坐标值需要转换为整数,因为OpenCV绘图函数要求整数坐标。另外,我们可以选择连线的颜色和粗细。我们将修改后的代码完整写出来(只修改了条件判断内部的部分):</think>基于您的要求,我将为您在YOLOv8实时屏幕检测代码中添加目标距离计算、连线和距离显示功能。以下是完整的解决方案:
```python
import cv2
import numpy as np
from mss import mss
from ultralytics import YOLO
import math
# 初始化屏幕捕获
monitor = {"top": 0, "left": 0, "width": 1920, "height": 1080}
sct = mss()
# 初始化YOLOv8模型
model = YOLO("yolov8s.pt").half() # 使用半精度加速
# 目标类别映射
CLASS_MAP = {0: "object_A", 1: "object_B"}
def calculate_distance(box1, box2):
"""计算两个边界框中心点的欧氏距离"""
# 解包坐标值
x1_min, y1_min, x1_max, y1_max = box1
x2_min, y2_min, x2_max, y2_max = box2
# 计算中心点
center1 = ((x1_min + x1_max)/2, (y1_min + y1_max)/2)
center2 = ((x2_min + x2_max)/2, (y2_min + y2_max)/2)
# 欧氏距离计算
return math.sqrt((center2[0]-center1[0])**2 + (center2[1]-center1[1])**2)
def draw_distance_line(img, box1, box2, distance):
"""在图像上绘制目标连线并显示距离"""
# 解包坐标值
x1_min, y1_min, x1_max, y1_max = box1
x2_min, y2_min, x2_max, y2_max = box2
# 计算中心点
center1 = (int((x1_min + x1_max)/2), int((y1_min + y1_max)/2))
center2 = (int((x2_min + x2_max)/2), int((y2_min + y2_max)/2))
# 计算连线中点位置
mid_point = (
int((center1[0] + center2[0])/2),
int((center1[1] + center2[1])/2)
)
# 绘制目标框
cv2.rectangle(img, (int(x1_min), int(y1_min)), (int(x1_max), int(y1_max)), (0, 255, 0), 2)
cv2.rectangle(img, (int(x2_min), int(y2_min)), (int(x2_max), int(y2_max)), (0, 255, 0), 2)
# 绘制连线
cv2.line(img, center1, center2, (255, 0, 0), 2)
# 在连线中点显示距离
cv2.putText(img, f"Distance: {distance:.2f}px",
(mid_point[0] - 70, mid_point[1] - 10),
cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)
# 在目标中心点绘制标记
cv2.circle(img, center1, 5, (255, 0, 255), -1)
cv2.circle(img, center2, 5, (255, 0, 255), -1)
return img
while True:
# 捕获屏幕帧
screen = np.array(sct.grab(monitor))[:, :, :3]
# YOLOv8推理
results = model(screen, imgsz=640, verbose=False)
# 存储检测结果
detected = {"object_A": None, "object_B": None}
# 处理检测结果
for result in results:
for box in result.boxes:
cls_id = int(box.cls.item()) # 类别ID
if cls_id in CLASS_MAP:
# 提取坐标值并存储
xyxy = box.xyxy[0].cpu().numpy()
detected[CLASS_MAP[cls_id]] = tuple(xyxy) # 存储为元组
# 当两个目标都被检测到时
if detected["object_A"] is not None and detected["object_B"] is not None:
# 计算距离
dist = calculate_distance(detected["object_A"], detected["object_B"])
# 绘制连线和距离
screen = draw_distance_line(screen, detected["object_A"], detected["object_B"], dist)
# 显示结果
cv2.imshow("YOLOv8 Distance Detection", screen)
if cv2.waitKey(1) == ord('q'):
break
cv2.destroyAllWindows()
```
### 关键功能实现说明
1. **距离计算函数**:
```python
def calculate_distance(box1, box2):
# 计算两个边界框中心点的欧氏距离
center1 = ((x1_min + x1_max)/2, (y1_min + y1_max)/2)
center2 = ((x2_min + x2_max)/2, (y2_min + y2_max)/2)
return math.sqrt((center2[0]-center1[0])**2 + (center2[1]-center1[1])**2)
```
使用欧氏距离公式计算两点间距离:
$$d = \sqrt{(x_2 - x_1)^2 + (y_2 - y_1)^2}$$
2. **可视化绘制函数**:
```python
def draw_distance_line(img, box1, box2, distance):
# 计算中心点
center1 = (int((x1_min + x1_max)/2), int((y1_min + y1_max)/2))
center2 = (int((x2_min + x2_max)/2), int((y2_min + y2_max)/2))
# 绘制连线
cv2.line(img, center1, center2, (255, 0, 0), 2)
# 显示距离
cv2.putText(img, f"Distance: {distance:.2f}px",
(mid_point[0] - 70, mid_point[1] - 10),
cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)
```
在连线中点位置显示距离值,确保文本清晰可见[^1]
3. **性能优化**:
- 使用`.half()`进行半精度推理加速
- `verbose=False`关闭冗余输出
- 直接操作原始图像减少内存拷贝
### 应用场景扩展
此技术可应用于:
1. **游戏开发**:实现角色与物品的距离检测
2. **工业检测**:监控机械臂与目标的距离
3. **安防系统**:检测人员与危险区域的距离
4. **体育分析**:运动员间距离跟踪[^2]
### 进一步优化建议
1. **距离单位转换**:
```python
# 添加像素到实际距离的转换系数
PIXELS_PER_METER = 100 # 根据实际情况调整
actual_distance = dist / PIXELS_PER_METER
```
2. **多目标处理**:
```python
# 存储所有检测到的目标
all_objects = {}
for box in result.boxes:
cls_id = int(box.cls.item())
if cls_id in CLASS_MAP:
xyxy = tuple(box.xyxy[0].cpu().numpy())
if CLASS_MAP[cls_id] not in all_objects:
all_objects[CLASS_MAP[cls_id]] = []
all_objects[CLASS_MAP[cls_id]].append(xyxy)
# 计算所有同类目标间的距离
for obj_type, boxes in all_objects.items():
for i in range(len(boxes)):
for j in range(i+1, len(boxes)):
dist = calculate_distance(boxes[i], boxes[j])
screen = draw_distance_line(screen, boxes[i], boxes[j], dist)
```
3. **距离阈值报警**:
```python
DISTANCE_THRESHOLD = 100 # 像素单位
if dist < DISTANCE_THRESHOLD:
cv2.putText(screen, "WARNING: Too close!", (10, 60),
cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2)
```
此实现结合了YOLOv8的高效目标检测和OpenCV的实时渲染能力,为您提供了完整的屏幕目标距离检测解决方案[^1][^2]。