(原) 人走茶凉,人来茶热

原创文章,请后转载,并注明出处。

最近买了一个摄像头,考虑结合AI让它发挥点实际作用.这里的功能是: 人走熄屏,人来亮屏

python有很长时间没用了,代码基本也是靠AI给的.

打包: pyinstaller –onefile –add-data “yolov5s.onnx;.” –name=“AutoMonitor” .\888.py

import sys
import cv2
import time
import ctypes
import os
import urllib.request
import argparse

def resource_path(relative_path):
    """ 获取打包后资源文件的绝对路径 """
    try:
        base_path = sys._MEIPASS
    except Exception:
        base_path = os.path.abspath(".")
    return os.path.join(base_path, relative_path)

def download_model(url, save_path):
    print("📥 正在下载 YOLOv5s ONNX 模型(约 14MB)...")
    try:
        urllib.request.urlretrieve(url, save_path)
        print("✅ 下载完成")
    except Exception as e:
        print(f"❌ 下载失败: {e}")
        sys.exit(1)

def main():
    parser = argparse.ArgumentParser(description="AutoMonitor: 基于 YOLOv5 的人体检测自动开关显示器")
    parser.add_argument("--interval", type=int, default=5,
                        help="检测间隔(秒),默认: 5")
    parser.add_argument("--max-miss", type=int, default=3,
                        help="连续无人多少次后关屏,默认: 3")
    parser.add_argument("--model", type=str, default="yolov5s.onnx",
                        help="ONNX 模型文件路径,默认: yolov5s.onnx")
    parser.add_argument("--no-display-control", action="store_true",
                        help="禁用显示器开关(仅打印日志,用于调试)")
    parser.add_argument("--confidence", type=float, default=0.5,
                        help="置信度阈值,默认: 0.5")
    parser.add_argument("--nms", type=float, default=0.4,
                        help="NMS 阈值,默认: 0.4")

    args = parser.parse_args()

    # === 处理模型路径 ===
    MODEL_FILE = resource_path(args.model)
    if not os.path.exists(MODEL_FILE):
        if args.model == "yolov5s.onnx":
            # 自动下载官方模型
            url = "https://github.com/ultralytics/yolov5/releases/download/v7.0/yolov5s.onnx"
            download_model(url, MODEL_FILE)
        else:
            print(f"❌ 模型文件不存在: {MODEL_FILE}")
            sys.exit(1)

    print("👀 AutoMonitor 人走熄屏, 人来亮屏")
    # === 加载模型 ===
    print("🧠 加载 YOLOv5s 模型...")
    net = cv2.dnn.readNet(MODEL_FILE)
    print("✅ 模型加载成功")

    # === 配置 ===
    CHECK_INTERVAL = args.interval
    MAX_NO_PERSON_COUNT = args.max_miss
    CONFIDENCE_THRESHOLD = args.confidence
    NMS_THRESHOLD = args.nms
    DISABLE_DISPLAY = args.no_display_control

    no_person_count = 0
    monitor_on = True

    def wake_up_monitor():
        if not DISABLE_DISPLAY:
            ctypes.windll.user32.mouse_event(0x0001, 0, 0, 0, 0)
        print("💡 唤醒显示器")

    def turn_off_monitor():
        if not DISABLE_DISPLAY:
            ctypes.windll.user32.SendMessageW(0xFFFF, 0x0112, 0xF170, 2)
        print("🌑 关闭显示器")

    def is_person_detected(frame):
        height, width = frame.shape[:2]
        blob = cv2.dnn.blobFromImage(frame, 1/255.0, (640, 640), swapRB=True, crop=False)
        net.setInput(blob)
        outputs = net.forward(net.getUnconnectedOutLayersNames())

        boxes = []
        confidences = []

        for output in outputs:
            if output.ndim == 3:
                output = output[0]

            for detection in output:
                if len(detection) < 85:
                    continue

                x, y, w, h = detection[:4]
                obj_conf = detection[4]
                class_scores = detection[5:85]

                if len(class_scores) != 80:
                    continue

                class_id = int(class_scores.argmax())
                if class_id != 0:  # 只检测 person
                    continue

                confidence = obj_conf * class_scores[class_id]
                if confidence > CONFIDENCE_THRESHOLD:
                    x1 = int((x - w / 2) * width)
                    y1 = int((y - h / 2) * height)
                    x2 = int((x + w / 2) * width)
                    y2 = int((y + h / 2) * height)
                    boxes.append([x1, y1, x2 - x1, y2 - y1])
                    confidences.append(float(confidence))

        indices = cv2.dnn.NMSBoxes(boxes, confidences, CONFIDENCE_THRESHOLD, NMS_THRESHOLD)
        return len(indices) > 0

    # === 主循环 ===
    print(f"   - 检测间隔: {CHECK_INTERVAL}s")
    print(f"   - 连续无人 {MAX_NO_PERSON_COUNT} 次后关屏")
    print(f"   - 置信度阈值: {CONFIDENCE_THRESHOLD}")
    print(f"   - 显示器控制: {'禁用' if DISABLE_DISPLAY else '启用'}\n")

    try:
        while True:
            cap = cv2.VideoCapture(0)
            ret, frame = cap.read()
            cap.release()

            if not ret:
                print("⚠️ 摄像头失败,跳过...")
                time.sleep(CHECK_INTERVAL)
                continue

            start = time.time()
            has_person = is_person_detected(frame)
            elapsed = time.time() - start

            ts = time.strftime("%H:%M:%S")
            print(f"[{ts}] 耗时: {elapsed:.2f}s | 有人: {has_person}")

            if has_person:
                if not monitor_on:
                    wake_up_monitor()
                    monitor_on = True
                no_person_count = 0
            else:
                no_person_count += 1
                print(f"   → 连续无人: {no_person_count}/{MAX_NO_PERSON_COUNT}")
                if no_person_count >= MAX_NO_PERSON_COUNT and monitor_on:
                    turn_off_monitor()
                    monitor_on = False

            time.sleep(CHECK_INTERVAL)

    except KeyboardInterrupt:
        print("\n🛑 程序退出")

if __name__ == "__main__":
    main()

相关文章