TianZe 发表于 2024-11-19 15:53

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

本帖最后由 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())

TianZe 发表于 2024-11-20 11:13

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

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

TianZe 发表于 2024-11-19 18:15

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

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

bachelor66 发表于 2024-11-19 16:36

越玩越高级了都,厉害啊                                    

聪本 发表于 2024-11-19 16:48

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

zhongjun 发表于 2024-11-19 16:49

知乎上看过这个案例

guiziwen 发表于 2024-11-19 16:50

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

xiaofei263 发表于 2024-11-19 16:57

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

lcg888 发表于 2024-11-19 16:59

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

李亲顾 发表于 2024-11-19 17:05

高手高手高高手

aft705 发表于 2024-11-19 17:08

好像在哪里年到过相关教程,不过还是看不太懂。

lilang7 发表于 2024-11-19 17:20

正需要,试试效果
页: [1] 2 3 4 5 6 7
查看完整版本: 使用摄像头检测指定区域,当区域发生变化隐藏指定窗口