使用OpenCV和MediaPipe库——抽烟检测(姿态监控)

embedded/2025/3/18 10:23:06/

目录

抽烟检测的运用

1. 安全监控

(1) 公共场所禁烟监管

(2) 工业安全

2. 智能城市与执法

(1) 城市违章吸烟检测

(2) 无人值守管理

3. 健康管理与医疗

(1) 吸烟习惯分析

(2) 远程监护

4. AI 监控与商业分析

(1) 保险行业

(2) 商场营销

5. 技术实现

(1) 计算机视觉

(2) 传感器检测

(3) 结合物联网(IoT)

6. 挑战与优化

(1) 误报问题

(2) 夜间检测难度

(3) 隐私问题

代码实现思路

实现思路

1. 初始化检测模型

2. 读取视频流

3. 手部检测

4. 香烟检测

5. 嘴部检测

6. 抽烟行为判断

7. 可视化输出

8. 运行主循环

完整代码

效果展示



抽烟检测的运用

1. 安全监控

(1) 公共场所禁烟监管

  • 应用场景:机场、火车站、地铁站、医院、商场、学校等禁烟区域。
  • 作用:利用摄像头自动检测吸烟行为,触发警报或通知管理人员干预,减少人工巡逻成本。

(2) 工业安全

  • 应用场景:化工厂、加油站、煤矿、仓库等易燃易爆场所。
  • 作用:实时监测抽烟行为,防止安全事故,提高生产安全管理。

2. 智能城市与执法

(1) 城市违章吸烟检测

  • 应用场景:公交站、公共厕所、电梯、餐厅等区域。
  • 作用:结合智能监控系统,对违规吸烟行为进行抓拍、存证,甚至自动处罚。

(2) 无人值守管理

  • 应用场景:智能楼宇、写字楼、电影院等无人巡逻区域。
  • 作用:通过 AI 检测+语音提醒,劝阻违规吸烟者。

3. 健康管理与医疗

(1) 吸烟习惯分析

  • 应用场景:医院、戒烟中心、健康管理 APP。
  • 作用:记录个人抽烟次数、时间、环境等数据,帮助戒烟计划制定。

(2) 远程监护

  • 应用场景:养老院、精神病院等特殊场所。
  • 作用:监测老年人或患者是否有吸烟行为,防止健康风险。

4. AI 监控与商业分析

(1) 保险行业

  • 应用场景:人寿保险、健康保险公司。
  • 作用:检测投保人是否吸烟,调整保费或健康建议。

(2) 商场营销

  • 应用场景:便利店、烟草店。
  • 作用:分析吸烟人群的特征,优化营销策略。

5. 技术实现

(1) 计算机视觉

  • 算法:基于 YOLO、Faster R-CNN 等目标检测模型。
  • 数据:训练数据包含吸烟者的手部、嘴部、烟雾等特征。

(2) 传感器检测

  • 红外摄像头:检测烟头的温度特征。
  • 空气质量传感器:监测 PM2.5、尼古丁气味等。

(3) 结合物联网(IoT)

  • 智能监控摄像头:内置 AI 识别系统,边缘计算本地处理数据。
  • 云平台:接收数据并发出警报。

6. 挑战与优化

(1) 误报问题

  • 误将吸烟动作与喝水、拿笔等动作混淆。
  • 解决方案:使用时间序列分析、骨骼检测等方法提高准确率。

(2) 夜间检测难度

  • 夜间光照条件差,普通摄像头难以检测烟雾。
  • 解决方案:采用 红外摄像头 结合 AI 算法提高夜间识别率。

(3) 隐私问题

  • 监控摄像头涉及个人隐私,可能引发争议。
  • 解决方案:使用 边缘计算,仅上传检测结果,不存储人脸信息。



代码实现思路

实现思路

1. 初始化检测模型

  • MediaPipe Hands:用于检测 手部位置,得到手的边界框(bounding box)。
  • dlib 人脸关键点检测:用于检测 嘴部关键点,确定嘴巴的位置。
  • YOLOv3:用于检测 香烟,需要加载权重(yolov3.weights)、配置文件(yolov3.cfg)和类别标签(coco.names)。

2. 读取视频流

  • 通过 cv2.VideoCapture(0) 打开摄像头,逐帧读取视频。

3. 手部检测

  • MediaPipe Hands 处理帧图像,返回检测到的手部 关键点
  • 计算手部的 边界框x_min, y_min, x_max, y_max)。
  • 使用 cv2.rectangle() 画出手部边界框。

4. 香烟检测

  • 通过 YOLOv3 目标检测 识别图像中的物体(包括香烟)。
  • 过滤出 类别为 "cigarette" 的目标,并记录香烟的边界框信息(cigarette_bboxes)。
  • 使用 cv2.rectangle() 画出香烟的位置。

5. 嘴部检测

  • 通过 dlib 人脸检测器 定位人脸,并使用 68个面部关键点 识别嘴部(第48-67号点)。
  • 计算 嘴部中心位置
  • cv2.polylines() 画出嘴部区域。

6. 抽烟行为判断

  • 遍历每只 手的边界框
    1. 判断是否持有香烟(手与香烟的 IOU 交并比 是否超过阈值 0.3)。
    2. 计算手部到嘴部的距离
      • 获取手部中心 (hand_center_x, hand_center_y)
      • 计算与 最近的嘴部中心 的欧几里得距离 distance
    3. 综合判断抽烟行为
      • 手持香烟 且 距离嘴部<100像素,则判定 正在抽烟
      • 手部靠近嘴部<50像素,但未持有香烟,则 可能在抽烟(警告)。

7. 可视化输出

  • 如果检测到 正在抽烟
    • 在屏幕上显示 "WARNING: Active Smoking Detected!"(红色警告)。
  • 如果 疑似抽烟(手靠近嘴但未持烟):
    • 显示 "Potential Smoking!"(黄色提示)。
  • 画出所有检测到的 手部、香烟、嘴部

8. 运行主循环

  • 不断读取摄像头画面,并调用 detect_smoking(frame) 进行检测。
  • 按下 ESC 退出程序。



完整代码

import cv2
import numpy as np
import dlib
import mediapipe as mp# 初始化MediaPipe手部检测
mp_hands = mp.solutions.hands
hands = mp_hands.Hands(max_num_hands=2,min_detection_confidence=0.7,min_tracking_confidence=0.5
)# 初始化dlib人脸检测
detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat")# 加载YOLOv3模型(需包含自定义训练的香烟类别)
net = cv2.dnn.readNet("yolov3.weights", "yolov3.cfg")
layer_names = net.getLayerNames()
output_layers = [layer_names[i - 1] for i in net.getUnconnectedOutLayers().flatten()]with open("coco.names", "r") as f:classes = [line.strip() for line in f.readlines()]def is_holding_cigarette(hand_bbox, cigarette_bboxes, iou_threshold=0.3):"""判断手部是否持有香烟(基于IOU)"""for cig_bbox in cigarette_bboxes:# 计算IOUx1 = max(hand_bbox[0], cig_bbox[0])y1 = max(hand_bbox[1], cig_bbox[1])x2 = min(hand_bbox[2], cig_bbox[2])y2 = min(hand_bbox[3], cig_bbox[3])intersection = max(0, x2 - x1) * max(0, y2 - y1)area_hand = (hand_bbox[2] - hand_bbox[0]) * (hand_bbox[3] - hand_bbox[1])area_cig = (cig_bbox[2] - cig_bbox[0]) * (cig_bbox[3] - cig_bbox[1])iou = intersection / (area_hand + area_cig - intersection)if iou > iou_threshold:return Truereturn Falsedef detect_smoking(frame):# 转换为RGB格式(MediaPipe需要)rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)# 手部检测hand_bboxes = []results = hands.process(rgb_frame)if results.multi_hand_landmarks:for landmarks in results.multi_hand_landmarks:# 获取手部边界框x_coords = [lm.x * frame.shape[1] for lm in landmarks.landmark]y_coords = [lm.y * frame.shape[0] for lm in landmarks.landmark]x_min, x_max = min(x_coords), max(x_coords)y_min, y_max = min(y_coords), max(y_coords)hand_bboxes.append((x_min, y_min, x_max, y_max))cv2.rectangle(frame, (int(x_min), int(y_min)),(int(x_max), int(y_max)), (255, 0, 0), 2)# YOLOv3香烟检测cigarette_bboxes = []blob = cv2.dnn.blobFromImage(frame, 0.00392, (320, 320), swapRB=True)net.setInput(blob)outs = net.forward(output_layers)for out in outs:for detection in out:scores = detection[5:]class_id = np.argmax(scores)confidence = scores[class_id]if confidence > 0.5 and classes[class_id] == "cigarette":center_x = int(detection[0] * frame.shape[1])center_y = int(detection[1] * frame.shape[0])w = int(detection[2] * frame.shape[1])h = int(detection[3] * frame.shape[0])x = center_x - w // 2y = center_y - h // 2cigarette_bboxes.append((x, y, x + w, y + h))cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2)# 人脸关键点检测mouth_positions = []faces = detector(frame)for face in faces:landmarks = predictor(frame, face)mouth_points = [(landmarks.part(i).x, landmarks.part(i).y)for i in range(48, 68)]mouth_center = np.mean(mouth_points, axis=0)mouth_positions.append(mouth_center)# 绘制嘴巴区域cv2.polylines(frame, [np.array(mouth_points, dtype=np.int32)],True, (0, 0, 255), 2)# 综合判断逻辑warning = Falsefor hand in hand_bboxes:# 判断是否持烟holding = is_holding_cigarette(hand, cigarette_bboxes)# 计算手部中心点hand_center = ((hand[0] + hand[2]) / 2, (hand[1] + hand[3]) / 2)# 找最近的人脸min_distance = float('inf')for mouth in mouth_positions:distance = np.sqrt((hand_center[0] - mouth[0]) ** 2 +(hand_center[1] - mouth[1]) ** 2)min_distance = min(min_distance, distance)# 判断条件if holding and min_distance < 100:  # 持烟且距离<100像素warning = Trueelif min_distance < 50:  # 未持烟但手部靠近嘴部cv2.putText(frame, "Potential Smoking!",(int(hand[0]), int(hand[1]) - 10),cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 255), 2)if warning:cv2.putText(frame, "WARNING: Active Smoking Detected!",(20, 50), cv2.FONT_HERSHEY_SIMPLEX,1, (0, 0, 255), 3, cv2.LINE_AA)return frame# 视频处理主循环
cap = cv2.VideoCapture(0)
while cap.isOpened():ret, frame = cap.read()if not ret:breakframe = cv2.flip(frame, 1)  # 镜像翻转result = detect_smoking(frame)cv2.imshow('Smoking Detection', result)if cv2.waitKey(1) == 27:breakcap.release()
cv2.destroyAllWindows()

效果展示


http://www.ppmy.cn/embedded/173566.html

相关文章

微服务即时通信系统---(八)用户管理子服务

本章节,主要对项目中用户管理子服务模块进行分析、开发与测试。 功能设计 用户管理子服务,主要用于管理用户的数据,以及关于用户信息的各项操作,因此,在本模块中,用户管理子服务需要提供以下的功能性接口 用户注册用户输入 用户名(昵称) + 用户密码 进行注册。用户登录…

docker学习

基本结构 镜像(image)&#xff1a; docker镜像可以当作一个模板&#xff0c;通过这个模板可以创建多个容器。 例如一个tomcat镜像>运行>容器(提供服务) 容器(container)&#xff1a; docker利用容器技术&#xff0c;可以独立运行一个或一组应用(容器间相互隔离) docker…

C语言:编程设计猜数游戏

先由计算机想一个数给用户猜&#xff0c;如果猜对了&#xff0c;提示“right&#xff01;”&#xff0c;猜错了&#xff0c;提示“wrong&#xff01;及大小” 思路&#xff1a;用随机函数rand&#xff08;&#xff09;取到计算机想的数 代码&#xff1a; #include <stdio.…

JVM、MySQL常见面试题(尽力局)

JVM篇 一.谈一谈JDK、JRE、JVM分别是什么&#xff0c;有什么联系&#xff1f; 1.JDK是Java工具包&#xff0c;里面包含了JRE、Javac编译器等。 2.JRE是java运行环境&#xff0c;里面包含了JVM、JavaSE标准库类等。 3.JVM是Java虚拟机&#xff0c;运行编译后的.class的文件&am…

C/C++中应用程序调用其他dll模块,想要使用vs调试这个dll里的代码,附加进程的方式无法命中断点,但通过调试启动的方式却可以,是什么原因?

文章目录 1. 符号文件&#xff08;PDB&#xff09;未正确加载2. DLL 版本与调试代码不一致3. DLL 加载时机错过调试器附加4. 调试器类型不匹配5. 编译优化导致断点偏移6. 断点位置未被执行7. 配置属性设置错误快速诊断流程&#xff1a;终极方案&#xff1a;直接调试启动 在 Vis…

机器学习中说的正向传递和反向传递是什么意思

在机器学习&#xff0c;尤其是深度学习领域&#xff0c;​正向传递&#xff08;Forward Pass&#xff09;​和反向传递&#xff08;Backward Pass&#xff09;​是神经网络训练过程中的两个核心步骤。它们共同构成了训练神经网络的基础框架&#xff0c;通常与梯度下降算法结合使…

提高开发效率:公共字段自动化填充方案

目录 问题描述 解决方案 Mybatis-Plus AOP注解 方案比较 MyBatis-Plus 自动填充功能 AOP 注解 问题描述 当我们在开发过程中&#xff0c;处理像创建时间、创建人等这样的公共字段会显得比较繁琐&#xff0c;尤其是在每个实体都需要这些信息的情况下。就比如&#xff0c…

centos Supported Java versions are: [17, 21]

在 CentOS 系统中&#xff0c;支持的 Java 版本取决于你使用的 CentOS 版本以及你所使用的 Oracle JDK 或 OpenJDK 的版本。截至我所知的信息&#xff0c;截至2023年&#xff0c;CentOS 7 和 CentOS 8 都已经停止官方支持&#xff0c;并被各自的替代版本取代&#xff0c;即 Cen…