摸鱼时候使用摄像头辅助监控周围情况

查看 125|回复 11
作者:windindind   
背景介绍:
楼主的座位很尴尬,显示器正对办公室入口,对摸鱼很不友好
受到Boss Sensor项目的启发,决定采用一个桌面摄像头辅助监控背后是否有人进入
于是在ai的帮助下,有了下面的代码
原本Boss Sensor项目是识别画面中的人脸是否为老板
但是楼主这个办公环境……等程序识别出来,可以收拾东西滚蛋了
所以只能退而求其次,“宁可错杀,绝不放过”
通过对比连续的两帧画面,只要差异值超出警戒值就直接触发后续动作,可以是隐藏窗口、自动按老板键等
注释比较详细了
代码的核心功能就是对比画面、触发特定动作(代码中是隐藏记事本,且最后一次预警10秒后恢复记事本窗口)
其他的功能都是辅助性的,比如监控窗口置顶、顶部滑动条调整监控窗口的透明度、(因为隐藏了窗体标题栏)可以在窗体内部任意位置拖动移动窗体位置、窗体内按ESC键退出
关于监控画面和预警值的说明:
楼主使用的是桌面摄像头,没有固定装置,所以需要一个预览窗口检查是否对准重点关注区域
裁剪画面,一方面是为了提高处理效率(以现在的PC性能,应该可以忽略不计了),另一方面是为了减少环境噪点对后面差异值的影响
预警值需要根据各自环境、裁剪画面大小等进行调整,多观察吧
原本计划取启动后10秒内的平均值(或者最大值)作为预警值,但是实际效果不太好,所以最后还是采用固定值了
因为是自用,所以没有考虑配置参数文件化,也就不方便直接生成成品EXE了
有需要的,就自己动手吧
[Python] 纯文本查看 复制代码import sys
import cv2
import win32gui
import win32con
import numpy as np
from datetime import datetime
from PyQt5.QtGui import QImage, QPixmap
from PyQt5.QtCore import QTimer, Qt, QPoint
from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QVBoxLayout, QHBoxLayout, QSlider
class VideoPlayer(QWidget):
    def __init__(self):
        super().__init__()
        # 打开摄像头
        self.cap = cv2.VideoCapture(0)
        if not self.cap.isOpened():
            exit("摄像头未能成功打开")
        self.hide_windows = False
        self.hwnd = -1
        # 设置窗口初始信息
        self.setGeometry(100, 100, 200, 320)  # 自行修改窗口尺寸,适配下面的画面展示
        self.setWindowTitle('Video Player')
        self.label = QLabel(self)
        self.slider = QSlider(Qt.Horizontal)
        self.slider.setMinimum(10)
        self.slider.setMaximum(99)
        self.slider.setTickInterval(5)
        self.slider.setTickPosition(QSlider.TicksBelow)
        self.slider.setValue(40)
        self.set_opacity(self.slider.value())
        self.slider.valueChanged.connect(self.set_opacity_and_update_label)
        self.opacity_label = QLabel(str(self.slider.value()), self)
        opacity_layout = QHBoxLayout()
        opacity_layout.addWidget(self.slider)
        opacity_layout.addWidget(self.opacity_label)
        layout = QVBoxLayout()
        layout.addLayout(opacity_layout)
        layout.addWidget(self.label)
        self.setLayout(layout)
        self.setWindowFlag(Qt.FramelessWindowHint)
        self.setWindowFlag(Qt.WindowStaysOnTopHint)
        self.drag_position = QPoint()
        # 用于存储上一帧的ROI,进行对比
        self.previous_roi = None
        self.show()
        # 创建定时器
        self.change_detected_timer = QTimer(self)
        self.change_detected_timer.timeout.connect(self.reset_hide_window)
        self.change_detected_timer.setSingleShot(True)
    # 按下 ESC 键,关闭应用
    def keyPressEvent(self, event):
        if event.key() == Qt.Key_Escape:
            self.close()
    # 设置窗体透明度
    def set_opacity_and_update_label(self, value):
        self.set_opacity(value)
        self.opacity_label.setText(str(value))
    # 将滑动条的值映射到0.1-1.0的范围
    def set_opacity(self, value):
        opacity = value / 100.0
        self.setWindowOpacity(opacity)
    # 鼠标可以拖动窗体
    def mousePressEvent(self, event):
        if event.button() == Qt.LeftButton:
            self.drag_position = event.globalPos() - self.frameGeometry().topLeft()
            event.accept()
    def mouseMoveEvent(self, event):
        if event.buttons() == Qt.LeftButton:
            self.move(event.globalPos() - self.drag_position)
            event.accept()
    # 从摄像头获取画面
    def show_frame(self):
        ret, frame = self.cap.read()
        if ret:
            # 获取指定区域的画面
            # 这是楼主环境下需要监控的区域大小,请自行调整
            x, y, w, h = 100, 100, 200, 320
            roi = frame[y:y + h, x:x + w]
            # 在这里对ROI进行翻转、镜像等处理
            # roi = cv2.flip(roi, 1)  # 1表示水平翻转
            roi = cv2.rotate(roi, cv2.ROTATE_180)  # 旋转180度
            # 变化检测
            if self.previous_roi is not None:
                # 计算两帧之间的差异
                diff = cv2.absdiff(self.previous_roi, roi)
                gray_diff = cv2.cvtColor(diff, cv2.COLOR_BGR2GRAY)
                _, thresh = cv2.threshold(gray_diff, 30, 255, cv2.THRESH_BINARY)
                change_detected = np.sum(thresh) > 30000  # 预警值
                if change_detected:
                    # 触发特定动作
                    self.on_change_detected(np.sum(thresh))
                # 叠加差异图像到原始视频帧上
                diff_image = cv2.cvtColor(thresh, cv2.COLOR_GRAY2BGR)
                overlay = cv2.addWeighted(roi, 0.7, diff_image, 0.3, 0)
                # 获取当前时间并添加到图像上
                cv2.putText(overlay, f"{datetime.now()}", (4, 10), cv2.FONT_HERSHEY_SIMPLEX, 0.37, (255, 255, 255), 1)
                # 添加 np.sum(thresh) 和 self.hide_windows 的值
                hide_windows_status = f'{"Hidden" if self.hide_windows else "Visible"} thresh: {np.sum(thresh)}'
                text_color = (0, 0, 255) if change_detected else (255, 255, 255)
                cv2.putText(overlay, f'{hide_windows_status}', (4, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.4, text_color, 1)
                # 使用叠加后的图像
                display_image = overlay
            else:
                display_image = roi
            # 更新上一帧
            self.previous_roi = roi
            rgb_image = cv2.cvtColor(display_image, cv2.COLOR_BGR2RGB)  # 转换颜色通道
            h, w, ch = rgb_image.shape
            bytes_per_line = ch * w
            q_image = QImage(rgb_image.data, w, h, bytes_per_line, QImage.Format_RGB888)
            pixmap = QPixmap.fromImage(q_image)
            self.label.setPixmap(pixmap)
    # 这里可以执行你想要的特定动作
    def on_change_detected(self, change_detected):
        print(f"{datetime.now()}  检测到变化!{change_detected}")
        if not self.hide_windows:
            self.hide_windows = True
            print(f'{datetime.now()}  hide_windows:{"隐藏" if self.hide_windows else "可见"}')
            self.hide_other_window()  # 隐藏指定窗口
        self.change_detected_timer.start(10000)  # 启动10秒定时器
        self.setWindowTitle(
            f'{datetime.now().strftime("%H:%M:%S")}-{"隐藏" if self.hide_windows else "可见"}-Video Player')
    # 替换为您要隐藏的窗口的信息
    def hide_other_window(self):
        window_class = None
        window_title = "无标题 - 记事本"
        # 查找窗口句柄
        self.hwnd = win32gui.FindWindow(window_class, window_title)
        if self.hwnd:
            # 隐藏窗口
            win32gui.ShowWindow(self.hwnd, win32con.SW_HIDE)
    def reset_hide_window(self):
        self.hide_windows = False
        print(f'{datetime.now()}  hide_windows:{"隐藏" if self.hide_windows else "可见"}')
        self.setWindowTitle(f'Video Player-可见')
        # 恢复窗口
        if self.hwnd:
            win32gui.ShowWindow(self.hwnd, win32con.SW_SHOW)
    # 退出程序
    def closeEvent(self, event):
        self.cap.release()
        super().closeEvent(event)
if __name__ == '__main__':
    app = QApplication(sys.argv)
    player = VideoPlayer()
    def update_frame():
        player.show_frame()
        # 递归调用自身,实现无限循环
        QTimer.singleShot(30, update_frame)
    update_frame()  # 第一次调用
    sys.exit(app.exec_())


微信截图_20241105102124.png (68.16 KB, 下载次数: 0)
下载附件
2024-11-5 10:25 上传



微信截图_20241105102232.png (68.64 KB, 下载次数: 0)
下载附件
2024-11-5 10:25 上传

窗口, 窗体

windindind
OP
  


yjhyjh0258 发表于 2024-11-5 12:23
可以出一个连接海康摄像头的吗。台式电脑没有自带摄像头,但公司的摄像头我有账号密码,能登录查看

我也是台式电脑,自己买个小摄像头就几十块钱,摸鱼被抓住也不止罚这点,还是划算的
当然如果有网络摄像头更方便
把“self.cap = cv2.VideoCapture(0)”使用网络摄像头的 URL 替代 0(这表示本地摄像头)
例如[Python] 纯文本查看 复制代码camera_url = 'rtsp://username:password@ip_address:port/stream'  # RTSP 示例
self.cap = cv2.VideoCapture(camera_url)
windindind
OP
  


Designlazy 发表于 2024-11-5 13:52
我没其他意思,别误会了。只是想的是让你看看有没有参考的地方
具体地址我记不太清了,这是我之前保存的 ...

我的意思就是去帖子里看看他的思路,偷师学艺
度盘这个我下载回来,不知道什么原因,无法运行(闪退)
百度查到一个叫“异量摸鱼精灵”的,可能就是你提到的这个软件
看了介绍,比我的代码完美多了
我这算是又造了一个轮子吧
Xiaosesi   

感谢分享,摸鱼不怕抓了
a976606645   

这个真的可以有
Blacksuns   

劳动人民的智慧是无穷无尽的
fbifbi   

厉害了,弄下来试试看
SVIP008   

这摸出了新高度,至少有三层楼那么高
tyy474   

需求才是创造的根本
axinabcd   

这个能够看到多远的位置?
您需要登录后才可以回帖 登录 | 立即注册

返回顶部