自己动手编写一个熊孩子监视器(U型遥控器,Python 3,多线程,多客户端)

本篇所展示的脚本均无加密处理,请在安全的网络环境下使用。本篇所展示内容均开源开放,但其使用务必遵循当地法律法规!

熊孩子在家上网课偷偷玩电脑?是时候处理一下了!

借此机会展示一下图传和多线程同时收发的脚本,脚本不是很完善但是希望能做到抛砖引玉。

目标

1.捕捉熊孩子的电脑桌面并且发送到USwitch;

2.通过摄像头观察熊孩子是否在认真听课;

3.点点手机就可以弹出窗口警告熊孩子认真学习;

4.合理的资源占用,随时停止发送图像,随时启用/停用摄像头;

5.多线程,多客户端,简单配对,可以做到父母亲友同时监督 :)

下面是一些效果图:

同时启用摄像头和屏幕捕捉
弹出窗口警告
弹出窗口警告

准备工作

要有网,有网很重要 (手机和熊孩子的电脑连接同一个路由器,或者你有自己的服务器...)

0.Windows平台的脚本已经打包好可以直接下载使用,因此你可以直接跳过后边所有的步骤,直接跳到“USwitch端的配置”学习如何使用。(备用下载地址,提取码:5yam)

1.安装必备的库(windows 在 cmd 执行,linux 在终端执行):

pip install opencv-python
pip install pillow
pip install numpy 

2.在手机上安装U型遥控器

脚本和注释

脚本的后缀由.py修改为.pyw可以在windows平台上实现无弹窗运行,可以手动设置为开机启动项。(运行后仍可在任务管理器中找到)

from socket import *
from threading import Thread
from PIL import ImageGrab
from io import BytesIO
from numpy import array
from sys import platform
from math import ceil
import  cv2

#弹窗警告功能暂时只针对win平台
if platform == "win32" or platform == "win64":
    ISWIN = True
    import ctypes

Use_WebCam=False
WebCam_starting=False


#接收端ip列表,当接收端地址从其中移除将不再向其发送
#支持多端接收
Running=[]
#发送图像的分辨率
Res_x=690
Res_y=360

#配置UDP
r_host = ''
r_port = 127  #电脑的接收端口
s_port = 9921 #手机的接收端,使用4位数的端口(受部分安卓系统限制)
bufsize = 1024 
r_addr = (r_host,r_port)
r_udpServer = socket(AF_INET,SOCK_DGRAM) 
r_udpServer.bind(r_addr)

#接收线程
class Rec_Thread(Thread):
    def __init__(self, server: socket):
        super().__init__()
        self.server = server
    def run(self):
        global Running
        global Use_WebCam
        while 1:
            data,addr = self.server.recvfrom(bufsize)
            data=data.decode()
            if data=="exit":
                Running=[]
                if Use_WebCam:
                    Use_WebCam=False
                    try:
                        cap.release()
                    except:
                        pass
                exit(0)
            if data=="start" and not addr[0] in Running:
                Running.append(addr[0]) #将发来start命令的ip地址添加到列表
                stream_thread = Send_Thread(addr[0]) #创建发送线程
                stream_thread.start()
            elif data=="stop" and addr[0] in Running:
                Running.remove(addr[0])
            elif data=="warning":
                Msg_Box_thread = Msg_Box(0)
                Msg_Box_thread.start()
            elif data=="camera" and not WebCam_starting: #摄像头启动有延迟请耐心
                if Use_WebCam:
                    Use_WebCam=False
                    try:
                        cap.release()
                    except:
                        pass
                else:
                    Use_WebCam=True
            else:
                Msg_Box_thread = Msg_Box(1,addr[0],data)
                Msg_Box_thread.start()

                
#发送线程
class  Send_Thread(Thread):
    def __init__(self,host):
        super().__init__()
        self.host = host
        self.addr = (host,s_port)
        self.udpClient = socket(AF_INET,SOCK_DGRAM)
    def run(self):
        while self.host in Running: 
            captureImage = ImageGrab.grab() #捕获屏幕截图
            captureImage = captureImage.resize((Res_x,Res_y))
            #转变为cv格式以便编码发送
            captureImage = cv2.cvtColor(array(captureImage), cv2.COLOR_RGB2BGR)
            #如果启用摄像头将进行图片叠加
            if Use_WebCam:
                try:
                    get, image_np = cap.read()
                    if get :
                        rows, cols = image_np.shape[:2]
                        captureImage[:rows, :cols]=image_np
                    elif not WebCam_starting:
                        Cam_thread = Set_Webcam()
                        Cam_thread.start()
                except:
                    if not WebCam_starting:
                        Cam_thread = Set_Webcam()
                        Cam_thread.start()

            #captureImage.resize((690,360))
            data=cv2.imencode(".jpg",captureImage,[cv2.IMWRITE_JPEG_QUALITY, 30])[1].tobytes()
            cut=int(ceil(len(data)/(bufsize)))#计算切片数
            strr="size;"+str(cut)# 通知手机开始接收切片
            self.udpClient.sendto(strr.encode(),self.addr)
            for i in range(cut):
              self.udpClient.sendto(data[i*int(bufsize):(i+1)*int(bufsize)],self.addr)#切片并且发送
            self.udpClient.sendto(("end").encode(),self.addr)#通知手机显示图片
        self.udpClient.sendto(("clear").encode(),self.addr)#结束,清理手机上显示的图片,V1.2.7以后版本可用


#弹窗警告功能
class  Msg_Box(Thread):
    def __init__(self,Type,addr="",Text=""):
        super().__init__()
        self.Type=Type
        self.addr=addr
        self.Text=Text
    def run(self):
        if ISWIN:
            if self.Type == 0: #警告
                ctypes.windll.user32.MessageBoxW(0,  "专心学习!", "不专心警告:",16+4096)
            if self.Type == 1: #其他消息
                ctypes.windll.user32.MessageBoxW(0,  self.Text, "来自:"+self.addr,1+4096)
        
#异步摄像头启动
class  Set_Webcam(Thread):
    def run(self):
        global WebCam_starting
        global cap
        WebCam_starting=True
        cap = cv2.VideoCapture(0)
        cap.set(3,int(Res_x/3.0))
        cap.set(4,int(Res_y/3.0))
        WebCam_starting=False
        
# 获取本机ip
def get_host_ip():
    ip='127.0.0.1'
    try:
        s=socket(AF_INET,SOCK_DGRAM)
        s.connect(('8.8.8.8',80))
        ip=s.getsockname()[0]
    finally:
        s.close()
    return ip

        
    


server_thread = Rec_Thread(r_udpServer)
server_thread.start()
#提示本机ip便于接收
Msg_Box_thread = Msg_Box(1,"熊孩子监视器","本机IP:"+get_host_ip()+"\n接收端口:"+str(r_port))
Msg_Box_thread.start()



理论上,上面的脚本可运行在任何平台,但是弹窗提醒只支持Windows平台,截屏函数只支持Windows和MacOS,其他平台有需要的,可以自行替换对应内容。

USwitch端的配置

1.和熊孩子电脑连接同一个路由器

2.进入编辑模式,点击左上角的“地球”,设置一个全局IP(电脑端脚本运行时会显示那个IP)

设置全局IP

3.创建按钮,脚本可以接受"start","stop","warning","camera"等命令,你可以选择性的将它们创建成按钮,由于我们已经设置了全局IP,所以这里每个按钮的的IP将不再重要,相比之下我们更关心端口(127),和发送的消息("start","stop","warning","camera"等)。

创建按钮g

4.设置图传,现版本图传在FPSView中,同样这里最重要的是开启图传,把接收端口设置为9921(如脚本),注意接收端口可以更改,
但是不可以小于四位数,不可以是已经被占用的端口(检查你的会话界面)

图传设置

5.去试一下吧!

同样你可以设置一个会话界面,生成各种自定义的弹窗,这里就不一一介绍了。

本教程到此就结束:)

APP下载

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,457评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,837评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,696评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,183评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,057评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,105评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,520评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,211评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,482评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,574评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,353评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,897评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,489评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,683评论 2 335

推荐阅读更多精彩内容