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

目录

抽烟检测的运用

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.rhkb.cn/news/33862.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

大数据学习(66)- CDH管理平台

&#x1f34b;&#x1f34b;大数据学习&#x1f34b;&#x1f34b; &#x1f525;系列专栏&#xff1a; &#x1f451;哲学语录: 用力所能及&#xff0c;改变世界。 &#x1f496;如果觉得博主的文章还不错的话&#xff0c;请点赞&#x1f44d;收藏⭐️留言&#x1f4dd;支持一…

Python字符串高效优化策略:特定编码 -> Unicode码点 -> UTF-8(可自定义)

Python利用唯一uni-pot中介打理&#xff0c;任意制式输出&#xff08;首选uyf-8&#xff09;。 笔记模板由python脚本于2025-03-14 23:37:04创建&#xff0c;本篇笔记适合喜欢探究字符串编码细节的coder翻阅。 【学习的细节是欢悦的历程】 博客的核心价值&#xff1a;在于输出思…

Linux自动化构建工具—make/makeflie

目录 1、为什么我们需要make和makefile 2、makefile文件的基本语法 makefile文件的语法和make指令的用法 定义变量 3、PHONY关键字 .PHONY 的语法 为什么需要.PHONY&#xff1f; 1、为什么我们需要make和makefile make 和 Makefile 是软件开发中用于自动化构建和管理代…

使用DeepSeek完成一个简单嵌入式开发

开启DeepSeek对话 请帮我使用Altium Designer设计原理图、PCB&#xff0c;使用keil完成代码编写&#xff1b;要求&#xff1a;使用stm32F103RCT6为主控芯片&#xff0c;控制3个流水灯的原理图 这里需要注意&#xff0c;每次DeepSeek的回答都不太一样。 DeepSeek回答 以下是使…

OSPF-2 邻接建立关系

上一期我们说了OSPF的邻居建立关系以及OSPF邻居关系建立中建立失败的因素以及相关实验案例 这一期我们来说说OSPF的邻接关系建立时需要交互哪些报文以及失败因素及原因和相关实验案例 一、概述 在运行了OSPF的网络当中为了交互链路状态信息和路由信息,互相之间需要建立邻接关…

app.config.globalProperties

目录 一:基础使用 1、简介 2、使用 3、打印结果: 二:封装 1、创建一个.ts文件(utils/msg.ts) 2、在main.ts中全局注册 3、在页面中使用 4、打印结果 一:基础使用 1、简介 app.config.globalProperties 是 Vue 3 应用实例&#xff08;app&#xff09;的一个配置属性&…

初探大模型开发:使用 LangChain 和 DeepSeek 构建简单 Demo

最近&#xff0c;我开始接触大模型开发&#xff0c;并尝试使用 LangChain 和 DeepSeek 构建了一个简单的 Demo。通过这个 Demo&#xff0c;我不仅加深了对大模型的理解&#xff0c;还体验到了 LangChain 和 DeepSeek 的强大功能。下面&#xff0c;我将分享我的开发过程以及一些…

基于RWA 与 AI-Agent 协同的企业数字化生态构建

在当前数字经济高速发展的背景下&#xff0c;企业数字化转型已成为提升竞争力和创新能力的必由之路。以实体零售与文旅行业为代表的传统产业&#xff0c;正通过现实世界资产&#xff08;RWA&#xff09;数字化与人工智能代理&#xff08;AI-Agent&#xff09;的协同应用&#x…

专题地图的立体表达-基于QGIS和PPT的“千层饼”视图制作实践

目录 前言 一、QGIS准备基础数据 1、QGIS 相关插件 2、图层标绘操作 二、PPT中制作 1、调整图片的规格 2、设置旋转 3、添加文字 三、总结 前言 在信息爆炸的时代&#xff0c;数据的可视化呈现变得愈发关键&#xff0c;而专题地图作为传递地理空间信息的有力工具&#…

3D文物线上展览如何实现?

3D文物线上展览的实现主要依赖于一系列先进的数字技术和创新手段&#xff0c;以下是实现3D文物线上展览的关键步骤和技术要点&#xff1a; 一、文物数字化采集与建模 高精度扫描&#xff1a; 使用专业的3D扫描仪对文物进行高精度扫描&#xff0c;获取文物的三维数据。积木易…

SpringCloud 学习笔记1(Spring概述、工程搭建、注册中心、负载均衡、 SpringCloud LoadBalancer)

文章目录 SpringCloudSpringCloud 概述集群和分布式集群和分布式的区别和联系 微服务什么是微服务&#xff1f;分布式架构和微服务架构的区别微服务的优缺点&#xff1f;拆分微服务原则 什么是 SpringCloud &#xff1f;核心功能与组件 工程搭建父项目的 pom 文件 注册中心Rest…

1140:验证子串--next.data()、KMP和find

1140&#xff1a;验证子串--KMP 题目 解析next.data()KMP代码Find代码 题目 解析 对于字符串的匹配常见的KMP算法【面试常考】 KMP中需要注意的是&#xff1a;应该从下标1开始遍历&#xff0c;因为下标0前面无值&#xff0c;不能匹配next 固在循环外应初始next[0]0;//易忘点 …

Python 实现大文件的高并发下载

项目背景 基于一个 scrapy-redis 搭建的分布式系统&#xff0c;所有item都通过重写 pipeline 存储到 redis 的 list 中。这里我通过代码演示如何基于线程池 协程实现对 item 的中文件下载。 Item 结构 目的是为了下载 item 中 attachments 保存的附件内容。 {"crawl_tim…

ubuntu中用docker下载opengauss

1.安装docker sudo apt install docker.io2.拉取opengauss镜像 sudo docker pull enmotech/opengauss3.创建容器 sudo docker run --name opengauss --privilegedtrue -d -e GS_PASSWORDEnmo123 enmotech/opengauss:latest3.5.如果容器停止运行&#xff08;比如关机了&#…

从零基础到能独立设计单片机产品,一般需要经历哪些学习阶段?

相信很多人&#xff0c;内心都有“钢铁侠”的幻想&#xff0c;成为能写程序&#xff0c;能设计硬件&#xff0c;能设计结构&#xff0c;能焊接的全能型人才。 上次徐工问我&#xff0c;如果你财富自由了&#xff0c;想去做啥&#xff1f; 我说出来&#xff0c;可能大家都不信&a…

cursor中git提交记录出现 签出(已分离)

我当时在cursor中的git记录右键点击 签出(已分离) 就导致最左边的记录图标的颜色由蓝色变为了橙色 后面提交的记录都不在显示本地分支和远程分支 创建新分支&#xff1a;在您当前的分离HEAD状态下&#xff0c;创建一个新的分支来保存这些提交。 git checkout -b new-branch-nam…

软件测试之测试用例

1. 什么是测试用例 测试用例&#xff08;TestCase)是为了实施测试而向被测试的系统提供的一组集合&#xff0c;这组集合包含&#xff1a;测试环境、操作步骤、测试数据、预期结果等要素。 设计测试⽤例原则⼀&#xff1a; 测试⽤例中⼀个必需部分是对预期输出或结果进⾏定义 使…

Unity2D 井字棋

Unity版本2022.3 场景布置 其中可以通过给Board对象添加Grid Layout Group&#xff0c;然后设置每个子物体所占宽高快速排整齐。用完删掉。每个落子的方格ChessBox都是一个Button。 根据Board的宽高除以三即可。 然后隐藏按钮&#xff0c;通过设置alpha值实现。 将ChessBox的…

专题三搜索插入位置

1.题目 题目分析&#xff1a; 给一个目标值&#xff0c;然后要在排序的整数数组中&#xff0c;找到跟目标值一样的&#xff0c;如果没有就把这个值插入进去&#xff0c;然后返回插入后的下标。 2.算法原理 根据题目的时间复杂度可以知道要用二分&#xff0c;开始划分区域&…

正式进入linux 1.0

切记&#xff1a;在Linux中空格很重要 回车键也很重要&#xff0c;不要按两次回车键 ls是显示当前所有文件夹 具体解释&#xff1a; 前面的东西是用户名 后面的是设备名&#xff08;计算机名&#xff09; 这是因为linux允许不同用户在终端下进行操作&#xff0c;这么做可以…