使用摄像头检测指定区域,当区域发生变化隐藏指定窗口

查看 107|回复 11
作者:TianZe   
先感谢大佬的帖子摸鱼时候使用摄像头辅助监控周围情况
我和大佬位置情况差不多,显示器正对着办公室入口,而且我的领导就在我后面
受到大佬启发,加上我也在学习pyqt和opencv,所以开发了这个小工具,自己设计了UI,可以手动设置检测区域,更易于使用
在使用之前需要 先使用Spy++ 提取到窗口类型和名字,输入到小工具里面


c83e78de5b1cdaf89e6006c312ce5ab.png (27.12 KB, 下载次数: 0)
下载附件
2024-11-19 15:41 上传



1732002188682.jpg (20.52 KB, 下载次数: 0)
下载附件
2024-11-19 15:42 上传

小工具使用方法:
1、输入窗口名字和类型
2、打开摄像头
3、点击检测位置,在图像范围内可以使用鼠标左键拖动画检测区域
4、点击关闭检测设置后,正式进入检测
5、不需要使用后 点击 清楚检测位置,关闭摄像头
小工具原理:设置好检测区域以后,当检测区域画面发生变化时,隐藏指定窗口
源代码和UI文件都上传到附件了,感兴趣可以下载使用
[Python] 纯文本查看 复制代码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  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, end_x, end_y])
                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[int(y1*ratio):int(y2*ratio),int(x1*ratio):int(x2*ratio)])
                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[roi_num], 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())

摄像头, 位置

TianZe
OP
  


bibubi 发表于 2024-11-20 10:05
能做成EXE么,我直接打开闪退。。另外源代码跟你帖子里面的源代码不一样呢。。

暂时没做成exe的计划,= = 感谢提醒,确实上传错附件了,附件是ui文件和ui的源代码,使用帖子的源代码,把附件里面的ui解压到 代码同一个文件夹内,或者修改程序第9行,指定ui位置也可以,需要提前配置python环境
TianZe
OP
  


reasuna 发表于 2024-11-19 17:38
那么有变化时后台录像是不是也可以呢

可以的,135-136行是 检测到区域变化以后程序进行的动作,这一段改成录像就可以
bachelor66   

越玩越高级了都,厉害啊                                    
聪本   

摄像头是自己工位的摄像头吗
zhongjun   

知乎上看过这个案例
guiziwen   

想法非常好。但有个缺陷:光线变化会使屏幕画面变化,很容易被误判,建议加个人脸识别(不受其他意外情况误判),检测到人立马关闭。
xiaofei263   

可以设置使用网络摄像头的视频流吗
lcg888   

我在想 这个被隐藏窗口隐藏的急不   被boss一眼就看到了窗口 随机就隐藏了 哈哈哈哈  
李亲顾   

高手高手高高手
您需要登录后才可以回帖 登录 | 立即注册

返回顶部