前言
前面9篇我们已经完成了完整工业视觉检测闭环:
图像预处理 → YOLO实时检测 → ROI区域限制 → RTSP视频流 → 自动抓拍 → 日志留存 → EXE工控部署
但是!纯后台检测、默默保存图片现场根本没人发现违规。
真正能落地、能提升安全管理效率的工业系统,必须具备:实时声光告警能力。
本章作为进阶增值实战篇,给系统补上三大核心工程功能:
-
人声语音实时播报(未戴安全帽、未穿工装、裸露违规)
-
可视化弹窗告警提示
-
智能重复告警过滤(防疯狂播报、防噪音扰民)
学完本篇,你的项目从"后台记录工具"升级为真正可用的智能安防预警系统,验收加分、项目质感直接拉满。
一、功能工程价值
-
语音播报:现场工人实时听到提醒,即时整改,降低安全事故
-
弹窗告警:监控室可视化提醒,值守人员快速发现违规
-
告警过滤:杜绝一秒播报多次、噪音刷屏、磁盘刷屏
-
分类播报:不同违规类型,对应不同语音提示
二、环境依赖安装
使用 pyttsx3 离线语音库,无需联网、无需API、完全本地播报、打包EXE可用,工业项目首选。
pip install pyttsx3
三、离线语音播报工具类封装(工业稳定版)
封装全局语音引擎,防止重复初始化导致卡顿、崩溃,适配视频流实时循环。
import pyttsx3 # 全局语音引擎,只初始化一次 engine = pyttsx3.init() # 设置语速、音量(工业适中参数) engine.setProperty('rate', 180) engine.setProperty('volume', 1.0) def voice_broadcast(text): """ 离线语音播报 :param text: 播报内容 """ engine.say(text) engine.runAndWait()
四、智能告警防抖逻辑(核心工程算法)
如果不做时间锁:每秒触发一次播报,现场噪音爆炸、程序卡死。
工业标准方案:同一违规类型 5 秒内只播报一次。
import time # 告警时间锁(防重复播报) last_voice_time = { "no_hat": 0, "no_suit": 0, "bare_skin": 0 } def need_broadcast(warn_type, interval=5): """ 判断是否需要播报 :param warn_type: 违规类型 :param interval: 间隔秒数 :return: True/False """ now = time.time() if now - last_voice_time[warn_type] > interval: last_voice_time[warn_type] = now return True return False
五、违规类型对应语音文案
def get_warn_text(warn_type): msg_dict = { "no_hat": "警告,请佩戴安全帽", "no_suit": "警告,请穿戴工作服", "bare_skin": "警告,检测到皮肤裸露,请注意作业规范" } return msg_dict.get(warn_type, "检测到作业违规")
六、弹窗告警实现(可视化提醒)
结合OpenCV窗口文字闪烁高亮,实现画面红色告警文字置顶提示。
def draw_warn_text(frame, warn_text): # 绘制红色警告大字 cv2.putText(frame, warn_text, (180, 80), cv2.FONT_HERSHEY_SIMPLEX, 1.2, (0, 0, 255), 3) return frame
七、完整版整合:检测+抓拍+日志+语音+弹窗告警
下面是 可直接替换上线的最终工程代码,整合本篇所有新功能,兼容前面所有逻辑、兼容EXE打包、兼容工控机。
import os import time import sys import cv2 import numpy as np import pyttsx3 from datetime import datetime from ultralytics import YOLO # ===================== 打包适配配置 ===================== os.environ["OPENCV_VIDEOIO_MSMF_ENABLE_HW_TRANSFORMS"] = "0" # 全局路径适配 def get_root_path(): if getattr(sys, 'frozen', False): return os.path.dirname(sys.executable) return os.path.dirname(os.path.abspath(__file__)) ROOT_PATH = get_root_path() MODEL_PATH = os.path.join(ROOT_PATH, "best.onnx") # ===================== 语音播报初始化 ===================== engine = pyttsx3.init() engine.setProperty('rate', 180) engine.setProperty('volume', 1.0) def voice_broadcast(text): engine.say(text) engine.runAndWait() # ===================== 告警防抖控制 ===================== last_warn_time = { "no_hat": 0, "no_suit": 0, "bare_skin": 0 } last_voice_time = { "no_hat": 0, "no_suit": 0, "bare_skin": 0 } def need_broadcast(warn_type, interval=5): now = time.time() if now - last_voice_time[warn_type] > interval: last_voice_time[warn_type] = now return True return False def get_warn_text(warn_type): msg_dict = { "no_hat": "警告,请佩戴安全帽", "no_suit": "警告,请穿戴工作服", "bare_skin": "警告,检测到皮肤裸露,请注意作业规范" } return msg_dict.get(warn_type, "检测到作业违规") # ===================== 日志与抓拍模块 ===================== def get_save_dir(): today = datetime.now().strftime("%Y-%m-%d") save_path = os.path.join(ROOT_PATH, "warn_save", today) if not os.path.exists(save_path): os.makedirs(save_path) return save_path def get_time_str(): return datetime.now().strftime("%Y-%m-%d %H:%M:%S") def draw_time_text(frame): time_str = get_time_str() cv2.putText(frame, time_str, (20, 35), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (255, 255, 255), 2) return frame def write_log(warn_type, img_name): log_time = get_time_str() log_dir = get_save_dir() log_path = os.path.join(log_dir, "log.txt") log_text = f"[{log_time}] 违规类型:{warn_type} 抓拍文件:{img_name}\n" with open(log_path, "a", encoding="utf-8") as f: f.write(log_text) def save_warn_image(frame, warn_type): now = time.time() if now - last_warn_time[warn_type] < 3: return False last_warn_time[warn_type] = now save_dir = get_save_dir() file_name = datetime.now().strftime("%H%M%S") + f"_{warn_type}.jpg" save_path = os.path.join(save_dir, file_name) cv2.imwrite(save_path, frame) write_log(warn_type, file_name) print(f"✅ 违规抓拍:{file_name}") return True # ===================== 工业预处理流水线 ===================== def industrial_preprocess(frame): h, w = frame.shape[:2] mask = np.zeros_like(frame) x1, y1 = int(w*0.1), int(h*0.2) x2, y2 = int(w*0.9), int(h*0.9) cv2.rectangle(mask, (x1, y1), (x2, y2), (255, 255, 255), -1) frame_roi = cv2.bitwise_and(frame, mask) frame_blur = cv2.GaussianBlur(frame_roi, (5, 5), 0) gray = cv2.cvtColor(frame_blur, cv2.COLOR_BGR2GRAY) binary = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 15, 3) kernel = np.ones((3, 3), np.uint8) binary = cv2.morphologyEx(binary, cv2.MORPH_OPEN, kernel) binary = cv2.morphologyEx(binary, cv2.MORPH_CLOSE, kernel) result = cv2.cvtColor(binary, cv2.COLOR_GRAY2BGR) return result, (x1, y1, x2, y2) # ===================== 加载模型与主逻辑 ===================== model = YOLO(MODEL_PATH) if __name__ == "__main__": cap = cv2.VideoCapture("rtsp://admin:123456@192.168.1.64:554/stream") cap.set(cv2.CAP_PROP_BUFFERSIZE, 1) while True: ret, frame = cap.read() if not ret: time.sleep(1) continue pre_frame, roi_pos = industrial_preprocess(frame) x1, y1, x2, y2 = roi_pos results = model.predict(pre_frame, imgsz=1280, conf=0.25, iou=0.4, verbose=False) warn_flag = False warn_class = "" for res in results: boxes = res.boxes for box in boxes: cls_id = int(box.cls[0]) cls_name = model.names[cls_id] if cls_name in ["no_hat", "no_suit", "bare_skin"]: warn_flag = True warn_class = cls_name # ========== 告警逻辑:语音 + 抓拍 + 弹窗文字 ========== if warn_flag and warn_class: msg = get_warn_text(warn_class) # 语音播报防抖 if need_broadcast(warn_class, 5): voice_broadcast(msg) # 保存截图日志 save_warn_image(draw_time_text(frame), warn_class) # 画面告警文字 draw_frame = res.plot() cv2.putText(draw_frame, msg, (180, 80), cv2.FONT_HERSHEY_SIMPLEX, 1.2, (0, 0, 255), 3) else: draw_frame = res.plot() # 绘制检测区域 + 时间戳 cv2.rectangle(draw_frame, (x1, y1), (x2, y2), (0, 0, 255), 2) draw_frame = draw_time_text(draw_frame) cv2.imshow("Industrial Detect System", draw_frame) if cv2.waitKey(1) & 0xFF == 27: break cap.release() cv2.destroyAllWindows()
八、EXE打包适配说明
pyttsx3 打包注意事项:
打包时无需额外配置,正常指令即可:
pyinstaller -F -w --add-data "best.onnx;." main.py
打包后完全支持离线语音播报,工控机无需联网、无需安装任何环境。
九、本篇总结
第10篇我们成功给工业视觉系统补齐了智能声光预警能力:
-
离线语音分类播报,不同违规不同提示
-
5秒智能防抖,杜绝噪音刷屏
-
画面红色高亮告警文字,监控室直观可见
-
完全兼容之前全套预处理、抓拍、日志、部署逻辑
至此,你的项目已经是市面上非常成熟、可商用、可验收、带交互预警的工业AI视觉系统。
十、下篇预告(最终进阶)
下一篇第11篇:多线程解耦 + 视频流稳流 + 推理加速
解决高延迟、画面卡顿、推理阻塞问题,实现毫秒级稳定实时检测,达到商业软件流畅度!