使用摄像头检测指定区域,当区域发生变化隐藏指定窗口
本帖最后由 TianZe 于 2024-11-19 15:55 编辑先感谢大佬的帖子摸鱼时候使用摄像头辅助监控周围情况
我和大佬位置情况差不多,显示器正对着办公室入口,而且我的领导就在我后面
受到大佬启发,加上我也在学习pyqt和opencv,所以开发了这个小工具,自己设计了UI,可以手动设置检测区域,更易于使用
在使用之前需要 先使用Spy++ 提取到窗口类型和名字,输入到小工具里面
小工具使用方法:
1、输入窗口名字和类型
2、打开摄像头
3、点击检测位置,在图像范围内可以使用鼠标左键拖动画检测区域
4、点击关闭检测设置后,正式进入检测
5、不需要使用后 点击 清楚检测位置,关闭摄像头
小工具原理:设置好检测区域以后,当检测区域画面发生变化时,隐藏指定窗口
源代码和UI文件都上传到附件了,感兴趣可以下载使用
import sys,cv2,copy,win32gui,win32con
from PyQt6.QtCore import QTimer,Qt
from PyQt6.QtGui import QPixmap, QImage
from PyQt6.QtWidgets import QApplication, QMainWindow, QMessageBox, QPushButton, QLineEdit
from PyQt6 import uic
import numpy as np
#加载UI文件
video_ui, _ = uic.loadUiType("摸鱼小程序.ui")
class Video_open(QMainWindow,video_ui):
#PYQT初始化
def __init__(self, parent=None):
super(Video_open, self).__init__(parent)
self.setupUi(self) #初始化UI
self.cap = cv2.VideoCapture(0) #打开摄像头0,如果有多个摄像头,可以在这里切换摄像头
self.timer = QTimer()
self.OpenCameraButton:QPushButton = self.pushButton #打开摄像头按键
self.DesignatedArea:QPushButton = self.pushButton_2 #设置检测位置按键
self.ClearDetectionPosition =self.pushButton_3 #清楚检测位置按键
self.background() #连接按键和槽函数
self.init_timer() #初始化计时器
self.roi_old_list = []#检测区域前一帧列表
self.roi_new_list = []#检测区域当前这一帧列表
self.window_text ="未输入内容" #隐藏窗口名字
self.num = 1 #通过计算次数,判断打开摄像头按键状态
self.DetectionArea_num = 1 #通过计算次数,判断设置检测按键状态
self.DesignatedArea_list = [] #检测区域位置列表
self.start_x, self.start_y = None, None #记录鼠标开始按下的位置
self.DetectionArea_Mark = None #检测位置标志,设置为TRUE就打开检测功能
self.window_type = None #窗口类型
#连接按键与函数
def background(self):
self.OpenCameraButton.clicked.connect(self.CameraMark)
self.DesignatedArea.clicked.connect(self.DetectionArea)
self.ClearDetectionPosition.clicked.connect(self.ClearFrame)
self.lineEdit.textChanged.connect(self.onTextChanged)
self.lineEdit_2.textChanged.connect(self.onTextChanged_2)
#输入窗口类型
def onTextChanged_2(self):
self.window_type = self.lineEdit_2.text()
#输入窗口名字
def onTextChanged(self):
self.window_text = self.lineEdit.text()
#清理检测位置
def ClearFrame(self):
self.DesignatedArea_list.clear()
self.roi_old_list.clear()
self.roi_new_list.clear()
#设置检测位置
def DetectionArea(self):
if self.DetectionArea_num % 2 == 0:
self.DesignatedArea.setText("设置检测")
self.DetectionArea_num += 1
self.DetectionArea_Mark = False
elif self.DetectionArea_num % 2 == 1:
QMessageBox.information(self, "检测区域", "使用鼠标左键拖动从左上往右下画框!")
self.DesignatedArea.setText("关闭设置检测")
self.DetectionArea_num += 1
self.DetectionArea_Mark = True
#记录鼠标左键按下位置
def mousePressEvent(self, event):
# -50 -50,为label相对窗口位置
if event.button() == Qt.MouseButton.LeftButton and self.DetectionArea_Mark:
self.start_x, self.start_y = event.pos().x()-50, event.pos().y()-50
#记录鼠标左键松开位置
def mouseReleaseEvent(self, event):
# -50 -50,为label相对窗口位置
if event.button() == Qt.MouseButton.LeftButton and self.DetectionArea_Mark:
end_x, end_y = event.pos().x()-50, event.pos().y()-50
#判断鼠标按下和释放位置是否在label区域内
if (0 < self.start_x < 640 and
0 < self.start_y < 360 and
640 > end_x > 0 and 360 > end_y > 0):
if self.start_x > end_x :
self.start_x,end_x = end_x,self.start_x
if self.start_y > end_y :
self.start_y,end_y = end_y,self.start_y
self.DesignatedArea_list.append()
self.start_x, self.start_y = None, None
#设置 打开摄像头 按键状态
def CameraMark(self):
if self.num == 1:
self.timer.start(30)
self.pushButton.setText("关闭摄像头")
self.num += 1
elif self.num % 2 == 0:
self.timer.blockSignals(True)
self.label.setPixmap(QPixmap())
self.pushButton.setText("打开摄像头")
self.num += 1
elif self.num % 2 == 1:
self.timer.blockSignals(False)
self.pushButton.setText("关闭摄像头")
self.num += 1
#初始化计时器
def init_timer(self):
self.timer.timeout.connect(self.show_pic)
#处理主程序,计时器30ms激活一次
def show_pic(self):
roi_num = 0 #roi数量
change_threshold = 100 #检测阈值(0-255),当像素点变化大于该值时,表示该区域发生变化
ret,img = self.cap.read()
if ret:
#加载并翻转摄像头图像
frame = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
frame = cv2.flip(frame,1)
#获取图片大小,和缩放比例
height, width, _ = frame.shape
ratio = max(width / self.label.width(), height / self.label.height())
#检测roi这一帧和上一帧是否相同
if self.DesignatedArea_list is not None :
for x1,y1,x2,y2 in self.DesignatedArea_list:
frame = cv2.rectangle(frame, (int(x1*ratio),int(y1*ratio)),
(int(x2*ratio),int(y2*ratio)), (0, 255, 0), 2)
self.roi_new_list.append(frame)
if self.roi_old_list is not None and not self.DetectionArea_Mark \
and len(self.roi_old_list) == len(self.roi_new_list):
for roi in self.roi_old_list:
old_roi_gray = cv2.cvtColor(roi, cv2.COLOR_BGR2GRAY)
new_roi_gray = cv2.cvtColor(self.roi_new_list, cv2.COLOR_BGR2GRAY)
diff = cv2.absdiff(old_roi_gray, new_roi_gray)
#如果roi区域发生变化,进入以下程序
if np.any(diff > change_threshold ):
hwnd = win32gui.FindWindow(f'{self.window_type}', f'{self.window_text}')
win32gui.ShowWindow(hwnd, win32con.SW_HIDE)
roi_num += 1
#将opencv提取到的图片转换成pyqt的格式
pixmap = QImage(frame,width,height,QImage.Format.Format_RGB888)
pixmap = QPixmap.fromImage(pixmap)
pixmap.setDevicePixelRatio(ratio)
#label显示图片
self.label.setPixmap(pixmap)
self.roi_old_list = copy.deepcopy(self.roi_new_list)
self.roi_new_list.clear()
if __name__ == '__main__':
app = QApplication(sys.argv)
window = Video_open()
window.show()
sys.exit(app.exec()) bibubi 发表于 2024-11-20 10:05
能做成EXE么,我直接打开闪退。。另外源代码跟你帖子里面的源代码不一样呢。。
暂时没做成exe的计划,= = 感谢提醒,确实上传错附件了,附件是ui文件和ui的源代码,使用帖子的源代码,把附件里面的ui解压到 代码同一个文件夹内,或者修改程序第9行,指定ui位置也可以,需要提前配置python环境 reasuna 发表于 2024-11-19 17:38
那么有变化时后台录像是不是也可以呢
可以的,135-136行是 检测到区域变化以后程序进行的动作,这一段改成录像就可以 越玩越高级了都,厉害啊 摄像头是自己工位的摄像头吗 知乎上看过这个案例 想法非常好。但有个缺陷:光线变化会使屏幕画面变化,很容易被误判,建议加个人脸识别(不受其他意外情况误判),检测到人立马关闭。 可以设置使用网络摄像头的视频流吗 我在想 这个被隐藏窗口隐藏的急不 被boss一眼就看到了窗口 随机就隐藏了 哈哈哈哈 高手高手高高手 好像在哪里年到过相关教程,不过还是看不太懂。 正需要,试试效果