【机器视觉】人物安全距离监测

目标

实现的功能:

  1. 使用YOLOv8模型检测视频中的人物
  2. 计算人物之间的距离(基于检测框中心点的欧氏距离)
  3. 当人物之间距离小于设定的安全阈值时,标记为红色并绘制连接线
  4. 显示人物之间的实时距离值
  5. 显示当前的安全距离阈值

程序特点:

  • 从摄像头实时获取视频流进行处理
  • 使用绿色框标记安全距离内的人物,红色框标记距离过近的人物
  • 通过红色线条连接距离过近的人物,并显示距离数值
  • 按'q'键可退出程序
    测试结果: 程序运行正常,可以成功检测人物并计算距离,当人物距离过近时会进行适当标记。

看效果

实现思路

  1. 创建新的Python文件yoloCrowdDistance.py
  2. 复制yoloUltralytics.py的基本结构
  3. 添加距离计算功能
  4. 添加过近人物标记功能
  5. 测试程序

贴源码

python 复制代码
import cv2
from ultralytics import YOLO
import numpy as np
import os
import platform
from PIL import ImageFont, ImageDraw, Image

def draw_chinese_text(image, text, position, font_size, color):
    """
    使用PIL在图像上绘制中文文本
    """
    try:
        # 将OpenCV图像转换为PIL图像
        pil_image = Image.fromarray(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
        draw = ImageDraw.Draw(pil_image)
        
        # 选择字体
        font_path = None
        system = platform.system()
        if system == "Windows":
            # Windows系统默认字体路径(使用原始字符串)
            font_path = r"C:\Windows\Fonts\simhei.ttf"  # 黑体
            if not os.path.exists(font_path):
                font_path = r"C:\Windows\Fonts\simsun.ttc"  # 宋体
                if not os.path.exists(font_path):
                    font_path = r"C:\Windows\Fonts\msyh.ttc"  # 微软雅黑
        elif system == "Darwin":  # macOS
            font_path = "/Library/Fonts/PingFang.ttc"
        elif system == "Linux":
            font_path = "/usr/share/fonts/truetype/wqy/wqy-zenhei.ttc"
        
        if font_path and os.path.exists(font_path):
            font = ImageFont.truetype(font_path, font_size)
            print(f"✅ 使用字体: {font_path}")
        else:
            font = ImageFont.load_default()
            print("⚠️ 使用默认字体,中文可能无法正常显示")
        
        # 绘制文本
        draw.text(position, text, font=font, fill=color)
        
        # 将PIL图像转换回OpenCV图像
        return cv2.cvtColor(np.array(pil_image), cv2.COLOR_RGB2BGR)
    except Exception as e:
        print(f"⚠️ 绘制中文文本时出错: {e}")
        # 如果绘制中文失败,使用OpenCV的putText(可能显示为方框)
        cv2.putText(image, text, position, cv2.FONT_HERSHEY_SIMPLEX, font_size/20, color, 2)
        return image

def calculate_distance(box1, box2):
    """
    计算两个检测框之间的距离(使用中心点之间的欧氏距离)
    box1, box2: 检测框坐标 (x1, y1, x2, y2)
    """
    # 计算两个检测框的中心点
    center1_x = (box1[0] + box1[2]) / 2
    center1_y = (box1[1] + box1[3]) / 2
    center2_x = (box2[0] + box2[2]) / 2
    center2_y = (box2[1] + box2[3]) / 2
    
    # 计算欧氏距离
    distance = np.sqrt((center1_x - center2_x) ** 2 + (center1_y - center2_y) ** 2)
    return distance

def main():
    print("开始加载YOLO模型进行人群距离监测...")

    try:
        # 加载YOLOv8模型
        model = YOLO('yolov8n.pt')
        print("✅ 模型加载成功!")

        # 打开摄像头
        cap = cv2.VideoCapture(0)
        if not cap.isOpened():
            print("❌ 无法打开摄像头")
            return

        print("🎥 摄像头已开启,按 'q' 键退出...")
        # 设定安全距离阈值(像素单位)
        safe_distance = 100

        while True:
            ret, frame = cap.read()
            if not ret:
                print("❌ 无法读取视频帧")
                break

            # 使用模型进行预测
            results = model(frame)
            person_boxes = []

            # 遍历每一帧的检测结果
            for r in results:
                # 获取检测框的坐标、置信度和类别ID
                boxes = r.boxes
                if boxes is not None and len(boxes) > 0:
                    for box in boxes:
                        # 获取坐标
                        x1, y1, x2, y2 = box.xyxy[0].tolist()
                        conf = box.conf[0].item()  # 置信度
                        cls_id = int(box.cls[0].item())  # 类别ID
                        class_name = model.names[cls_id]  # 类别名称

                        # 只关注人物类别(COCO数据集中类别ID为0)
                        if cls_id == 0 and conf > 0.5:
                            # 保存人物检测框
                            person_boxes.append((x1, y1, x2, y2))
                            # 绘制人物边界框
                            cv2.rectangle(frame, (int(x1), int(y1)), (int(x2), int(y2)), (0, 255, 0), 2)
                            # 绘制标签
                            label = f"{class_name} {conf:.2f}"
                            cv2.putText(frame, label, (int(x1), int(y1) - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5,
                                        (0, 255, 0), 2)

            # 检测过近距离的人物对
            if len(person_boxes) > 1:
                for i in range(len(person_boxes)):
                    for j in range(i + 1, len(person_boxes)):
                        box1 = person_boxes[i]
                        box2 = person_boxes[j]
                        distance = calculate_distance(box1, box2)
                        
                        # 如果距离小于安全阈值,标记为危险
                        if distance < safe_distance:
                            # 绘制人物框为红色
                            cv2.rectangle(frame, (int(box1[0]), int(box1[1])), (int(box1[2]), int(box1[3])), (0, 0, 255), 2)
                            cv2.rectangle(frame, (int(box2[0]), int(box2[1])), (int(box2[2]), int(box2[3])), (0, 0, 255), 2)
                            
                            # 绘制连接线
                            center1_x = int((box1[0] + box1[2]) / 2)
                            center1_y = int((box1[1] + box1[3]) / 2)
                            center2_x = int((box2[0] + box2[2]) / 2)
                            center2_y = int((box2[1] + box2[3]) / 2)
                            cv2.line(frame, (center1_x, center1_y), (center2_x, center2_y), (0, 0, 255), 2)
                            
                            # 显示距离
                            mid_x = int((center1_x + center2_x) / 2)
                            mid_y = int((center1_y + center2_y) / 2)
                            cv2.putText(frame, f"{distance:.1f}px", (mid_x, mid_y), cv2.FONT_HERSHEY_SIMPLEX, 0.5,
                                        (0, 0, 255), 2)

            # 显示安全距离阈值信息
            frame = draw_chinese_text(frame, f"安全距离阈值: {safe_distance}px", (10, 30), 20, (255, 255, 255))
            
            # 显示视频帧
            cv2.imshow('YOLO 人群距离监测', frame)

            # 按'q'键退出
            if cv2.waitKey(1) & 0xFF == ord('q'):
                break

        # 释放资源
        cap.release()
        cv2.destroyAllWindows()
        print("✅ 程序正常退出")

    except Exception as e:
        print(f"❌ 程序执行出错: {e}")


if __name__ == "__main__":
    main()
相关推荐
2501_941333102 分钟前
【工业视觉检测】基于YOLOv8的皮带输送机关键部件检测与识别系统完整实现
人工智能·yolo·视觉检测
ZCXZ12385296a2 分钟前
水下红色目标检测与定位实战:基于改进YOLOv8-Seg-GoldYOLO的实现
yolo·目标检测·目标跟踪
知行合一。。。6 分钟前
程序中的log4j、stderr、stdout日志
python·单元测试·log4j
wxin_VXbishe9 分钟前
springboot旅游信息管理系统-计算机毕业设计源码21675
java·c++·spring boot·python·spring·django·php
格林威10 分钟前
Baumer相机电池极耳对齐度检测:提升叠片工艺精度的 5 个实用方案,附 OpenCV+Halcon 实战代码!
人工智能·opencv·机器学习·计算机视觉·视觉检测·工业相机·堡盟相机
sg_knight10 分钟前
原型模式(Prototype)
python·设计模式·开发·原型模式
weixin_4331793312 分钟前
Python - 软件对象
开发语言·python
Want59516 分钟前
Python新春烟花代码
开发语言·python·pygame
storyseek20 分钟前
对Qwen3:8b进行QLora微调实现分类操作
python·深度学习·机器学习
&星痕&20 分钟前
人工智能:深度学习:0.pytorch安装
人工智能·python·深度学习