OpenCV工业视觉实战10|违规语音播报+弹窗告警+重复告警过滤,打造智能声光预警系统(项目加分必备)

前言

前面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篇:多线程解耦 + 视频流稳流 + 推理加速

解决高延迟、画面卡顿、推理阻塞问题,实现毫秒级稳定实时检测,达到商业软件流畅度!

相关推荐
AI人工智能+8 小时前
银行回单识别技术通过AI驱动的智能文档理解方案,实现财务处理的革命性升级
深度学习·计算机视觉·自然语言处理·ocr·银行回单识别
湘美书院--湘美谈教育8 小时前
湘美书院主理人:AI世代武侠小说的基本特征与蕴意
大数据·人工智能·深度学习·机器学习·生活
FriendshipT8 小时前
Ultralytics:解读CBLinear模块
人工智能·pytorch·python·深度学习·目标检测
光锥智能8 小时前
AI应用WAIC“抢跑”:热闹是真,但差异化是假
大数据·人工智能
某林2128 小时前
履带小车底盘stm32F103RCT6开发
人工智能·stm32·单片机·嵌入式硬件·架构·人机交互·ros2
逸模8 小时前
多业态连锁,如何同步铺开各类门店
大数据·人工智能·笔记·工程·公装·连锁店
音视频牛哥8 小时前
AI浪潮下,实时音视频SDK正在经历怎样的价值重构?
人工智能·音视频·实时音视频·rtmp推流·低延迟rtsp播放器·低延迟rtmp播放器·rtsp转rtmp推流
ShallWeL8 小时前
Orin 上用 Docker 跑通目标检测功能
人工智能·目标检测·docker·容器
xd1855785558 小时前
家电选购参谋 —— 鸿蒙AI智能助手开发全流程解析
人工智能·华为·harmonyos·鸿蒙