python 手动选取屏幕一块区域 实时比对是否变化

代码拿走就能跑

很乱 才开始学

import sys
import tkinter as tk
#创建图形用户界面(GUI)的标准库
import time
import cv2
#图片处理库
#import numpy as np
import pyautogui
#键鼠库
import pygame
#播放声音用,这个库有点大,但是我测试其他3个库 都不好使,只能用这个
from PIL import Image, ImageTk
#图像处理库
import threading
#线程库
from datetime import datetime
#时间库
start_x, start_y, end_x, end_y = None, None, None, None
#选取的区域坐标
from imagehash import average_hash
pinlv=2  #监控频率 第二版是把图片读取到内存操作 所以可以每秒一次
import io
should_exit = False
im0imagehas=0 #选区的hash值 用全局
isarm=False
i=0 
def print_to_text(*args):
    global i
    global isarm
    i=i+1
    if 8 < i :
        text_widget.delete(1.0, tk.END)#执行8次后清空一下txt,让txt一直滚动 方便进行监控
        i=0
    for arg in args:
        
        if not isarm:
            text_widget.tag_configure('red_text', foreground='blue')#正常字体
        if isarm :
            text_widget.tag_configure('red_text', foreground='red')#报警为红色
        text_widget.insert('end', str(arg), 'red_text' )
    text_widget.insert('end','\n')
    text_widget.yview_scroll(1, 'units')  # 向下滚动一格
# 将print的输出重定向到text_widget
print = print_to_text.__get__(None, print)
# 这将全局print函数绑定到text_widget

#按坐标获取切图
def qie_tu(img01=None):
    global start_x, start_y, end_x, end_y
    global disktoptu

    # 使用pyautogui进行屏幕截图
    screenshot = pyautogui.screenshot()
    #screenshot.save('temp.png', format='png')
    # 使用BytesIO将图像保持到内存中
    crop_bytes0 = io.BytesIO()
    screenshot.save(crop_bytes0, format='png')
    # 读取到内存中的图像数据
    crop_bytes0 = crop_bytes0.getvalue()
    # 打开图像
    img = Image.open(io.BytesIO(crop_bytes0))
    # 截取部分图像
    disktoptu=img
    crop = img.crop((start_x,start_y ,end_x, end_y))
    # 使用BytesIO将图像保持到内存中
    crop_bytes = io.BytesIO()
    crop.save(crop_bytes, format='png')
    # 读取到内存中的图像数据
    crop_bytes = crop_bytes.getvalue()
    # 对内存中的图像进行处理,例如调整大小
    # 这里使用的是PIL库的Image类,你可以根据需要进行其他操作
    im0 = Image.open(io.BytesIO(crop_bytes))
    # 如果需要,你可以在此处进行其他操作,例如旋转、裁剪等。
    # 在完成所有操作后,你可以使用下面的代码将图像保存到磁盘。

    imimagehash=average_hash(im0)#image hash
    img.save('desktop_screenshot.png', format='png')  # 将处理后的图像保存到磁盘
    if img01 != None:
        im0.save(img01, format='png')  # 将处理后的图像保存到磁盘
    return (str(imimagehash))

#鼠标选区并截取
def select_screen_region():
    load_alarm_sound("警报声.mp3")#放到这里防止错误提示终止运行
    text_widget.delete(1.0, tk.END)
    print('点击选区后,进入选区模式,'+'\n''最下面出现红色按钮才可以开始选区,'+'\n''选区后点击红色按钮退出选区模式')
    btn_xq.config(state=tk.DISABLED)#点击开始选区后 不可以重复点击 ,需要暂停后再次启动
    btn_start.config(state=tk.DISABLED)#开始按键停用
   
    global start_x, start_y, end_x, end_y
    global im0imagehas

    def on_press(event):
        global start_x, start_y
        start_x, start_y = event.x, event.y

    def on_move(event):
        global end_x, end_y
        end_x, end_y = event.x, event.y
        canvas.coords(rect, start_x, start_y, end_x, end_y)

    def on_release(event):
        global end_x, end_y
        end_x, end_y = event.x, event.y
        canvas.coords(rect, start_x, start_y, end_x, end_y)

    root1 = tk.Toplevel(root)
    root1.title("选择监控区域")
    root1.attributes('-fullscreen', True) #设置全屏模式
        
    screenshot = pyautogui.screenshot() #截屏
    screenshot.save('desktop_screenshot.png', format='png')

    canvas = tk.Canvas(root1, bg='white') #创建画布
    canvas.pack(fill=tk.BOTH, expand=True)#添加画布并填充

    desktop_image = ImageTk.PhotoImage(file='desktop_screenshot.png')#创建图片对象
    canvas.create_image(0, 0, anchor=tk.NW, image=desktop_image)#在画布上添加图片

    rect = canvas.create_rectangle(0, 0, 0, 0, outline='red')#创建矩形对象

    canvas.bind("<ButtonPress-1>", on_press)
    canvas.bind("<B1-Motion>", on_move)
    canvas.bind("<ButtonRelease-1>", on_release)
    
    def close_window():  # 新增的关闭窗口函数
        global im0imagehas
        if start_x== None:
            text_widget.delete(1.0, tk.END)
            print("请选定区域后再退出"+'\n'+'\n')
            print('点击选区后,进入选区模式,'+'\n''最下面出现红色按钮才可以开始选区,'+'\n''选区后点击红色按钮退出选区模式。')
        else:
            #im0imagehas = qie_tu('0.png') 在这里切图会再次抓屏 把那条红线抓进来
            img = Image.open('desktop_screenshot.png')
            crop = img.crop((start_x,start_y ,end_x, end_y))
            #crop.save('0.png', format='png')
            # 使用BytesIO将图像保持到内存中
            crop_bytes = io.BytesIO()
            crop.save(crop_bytes, format='png')
            im0imagehas=average_hash(crop)
            text_widget.delete(1.0, tk.END)
            print('成功抓取所选区域 可以开始监控')
            btn_start.config(state=tk.NORMAL)#成功抓取区域图片后,才可以开始监控
            root1.destroy()  # 使用Tkinter的destroy()方法关闭窗口
   
    button_close = tk.Button(root1, text=",选择需要监控的区域后,点击此关闭", fg="red", command=close_window)  # 创建关闭按钮
    button_close.pack()
    root1.mainloop()

# 初始化pygame库
pygame.init()
pygame.mixer.init()

# 全局变量,加载MP3文件
def load_alarm_sound(file_path):
    try:
        pygame.mixer.music.load(file_path)
    except pygame.error:
        print(f"无法加载音频文件:{file_path}")

# 封装一个播放MP3警报的函数
def play_alarm():
    try:
        # 播放MP3文件
        pygame.mixer.music.play()
    except pygame.error:
        print("播放警报音频失败")

def monitor(data_source):
    global pinlv
    global should_exit
    global isarm
    global im0imagehas

    while not should_exit:
            current_time = datetime.now()
            time_string = current_time.strftime("%H:%M:%S")
            #im1imagehas = qie_tu('1.png')
            im1imagehas = qie_tu()

            #print('im0imagehas:',str(im0imagehas))
            #print('im1imagehas:',str(im1imagehas))


            if str(im0imagehas) != str(im1imagehas) :
                print(time_string,'  相似度有变化,进行报警!')
                play_alarm()
                isarm=True
            else:
                print(time_string,'  相似度没有变化')
                isarm=False

            time.sleep(pinlv)  # 等待5秒后再获取下一帧
            
    if should_exit and suspend :
        print('暂停监控')
    else :
        cv2.destroyAllWindows()

def start_recognition():
    btn_start.config(state=tk.DISABLED)
    btn_suspend.config(state=tk.NORMAL)
    global should_exit
    global suspend
    suspend = False
    should_exit = False
    print("开始监控")
    th_monitor = threading.Thread(target=monitor, args=("screenshot",))
    th_monitor.daemon = True
    th_monitor.start()

def suspend_recognition():
    btn_xq.config(state=tk.NORMAL)
    btn_start.config(state=tk.NORMAL)
    btn_suspend.config(state=tk.DISABLED)
    global suspend
    global should_exit
    should_exit = True
    suspend=True


def end_program():
    global should_exit
    should_exit = True
    print("结束监控")
    sys.exit(1)
# 创建主窗口
root = tk.Tk()
root.title("监控报警")
root.wm_attributes('-topmost', True)
root.protocol("WM_DELETE_WINDOW",end_program)

#计算屏幕中央的位置
x = int((root.winfo_screenwidth() - root.winfo_reqwidth()) / 2)
y = int((root.winfo_screenheight() - root.winfo_reqheight()) / 2)
#将窗口居中显示
root.geometry("+{}+{}".format(x, y))

text_widget = tk.Text(root, width=55, height=10) # 设置文本框的最小宽度为40个字符,最小高度为10行
#text_widget.grid(column=0, row=0, width=10)  # 在grid中设置文本框的宽度为10个字符
text_widget.pack()

# 添加按钮
print('点击选区后,进入选区模式,'+'\n''最下面出现红色按钮才可以开始选区,'+'\n''选区后点击红色按钮退出选区模式。')
btn_xq = tk.Button(root, text="开始选区", command=select_screen_region)
btn_start = tk.Button(root, text="开始监控", command=start_recognition)
btn_suspend = tk.Button(root, text="暂停监控", command=suspend_recognition)
btn_end = tk.Button(root, text="结束监控", command=end_program)

#btn_start.config(state=tk.DISABLED)
# 使用pack布局并设置side参数为LEFT实现横向排列

btn_suspend.config(state=tk.DISABLED)#暂停按键停用
btn_start.config(state=tk.DISABLED)#开始按键停用

btn_xq.pack(side=tk.LEFT, padx=10, pady=10)
btn_start.pack(side=tk.LEFT, padx=10, pady=10)
btn_suspend.pack(side=tk.LEFT, padx=10, pady=10)
btn_end.pack(side=tk.LEFT, padx=10, pady=10)

# 创建一个下拉列表变量
root.var = tk.StringVar(root)
# 设置下拉列表的默认值
root.var.set("监控频率默认2秒次")
# 定义下拉列表的选项
options = ["1秒次", "5秒次", "10秒次", "20秒次", "30秒次"]
# 创建下拉列表
dropdown = tk.OptionMenu(root, root.var, *options)
# 将下拉列表放置到主窗口
dropdown.pack()

def option_selected(*args):
    global pinlv
    text_widget.delete(1.0, tk.END)
    print(f"选项 {root.var.get()} 被选择了!")
    if root.var.get() == "1秒次" :
        pinlv=1
    if root.var.get() == "5秒次" :
        pinlv=5
    if root.var.get() == "10秒次" :
        pinlv=10
    if root.var.get() == "20秒次" :
        pinlv=20
    if root.var.get() == "30秒次" :
        pinlv=30
root.var.trace("w", option_selected)
    
# 进入事件循环
root.mainloop()


 

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值