今日简题(18)

题目:

获取鼠标的位置,并打印

输入格式:

【无】

输出格式:

【(鼠标x,鼠标y)】

# -*- coding import tkinter as tk from tkinter import ttk, messagebox from PIL import Image, ImageTk, ImageDraw, ImageFont import vlc import os import cv2 import json import time import threading import queue import random import subprocess OUT_DIR = "./output" class EmployeeClockSystem: def __init__(self, root): self.root = root self.root.title("员工工牌识别打卡系统") self.root.geometry("1200x700") self.root.configure(bg="#f0f0f0") # 设置输出目录 self.OUT_DIR = "./output" os.makedirs(self.OUT_DIR, exist_ok=True) # 创建样式 self.style = ttk.Style() self.style.configure("Title.TLabel", font=("微软雅黑", 18, "bold"), foreground="#2c3e50") self.style.configure("Subtitle.TLabel", font=("微软雅黑", 14), foreground="#34495e") self.style.configure("Info.TLabel", font=("微软雅黑", 12), foreground="#2c3e50") self.style.configure("Card.TFrame", background="#ffffff", borderwidth=1, relief="raised", padding=10) self.style.configure("Control.TFrame", background="#e0e0e0", borderwidth=1, relief="sunken", padding=10) # 主布局框架 - 使用PanedWindow实现可调整的分割 main_paned = tk.PanedWindow(root, orient=tk.HORIZONTAL, sashrelief=tk.RAISED, sashwidth=4) main_paned.pack(fill=tk.BOTH, expand=True, padx=10, pady=10) # 左侧视频区域 (50%) left_frame = ttk.Frame(main_paned) main_paned.add(left_frame, stretch="always") # 右侧员工信息区域 (50%) right_frame = ttk.Frame(main_paned) main_paned.add(right_frame, stretch="always") # 视频流标 ttk.Label(left_frame, text="实时视频监控", style="Title.TLabel").pack(pady=(0, 10), anchor=tk.W, padx=10) # 视频显示区域 video_card = ttk.Frame(left_frame, style="Card.TFrame") video_card.pack(fill=tk.BOTH, expand=True, padx=10, pady=(0, 10)) self.video_container = ttk.Frame(video_card) self.video_container.pack(fill=tk.BOTH, expand=True) # 视频控制面板 control_frame = ttk.Frame(left_frame, style="Control.TFrame") control_frame.pack(fill=tk.X, padx=10, pady=(0, 10)) # URL输入框 ttk.Label(control_frame, text="RTSP地址:").pack(side=tk.LEFT, padx=(0, 5)) self.url_entry = ttk.Entry(control_frame, width=40) self.url_entry.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=(0, 10)) self.url_entry.insert(0, "rtsp://tapocxy:123456@192.168.137.100/stream1") # 连接按钮 self.connect_button = ttk.Button(control_frame, text="启动监控", command=self.toggle_stream, width=12) self.connect_button.pack(side=tk.LEFT, padx=(0, 5)) # 截图按钮 self.snapshot_button = ttk.Button(control_frame, text="抓拍", command=self.take_snapshot, width=8, state=tk.DISABLED) self.snapshot_button.pack(side=tk.LEFT) # 员工信息标 ttk.Label(right_frame, text="员工信息识别", style="Title.TLabel").pack(pady=(0, 10), anchor=tk.W, padx=10) # 员工信息卡片 info_card = ttk.Frame(right_frame, style="Card.TFrame") info_card.pack(fill=tk.BOTH, expand=True, padx=10, pady=(0, 10)) # 员工照片和基本信息 info_frame = ttk.Frame(info_card) info_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10) # 左侧员工照片区域 avatar_frame = ttk.Frame(info_frame, width=180, height=200) avatar_frame.pack(side=tk.LEFT, padx=(0, 20), fill=tk.Y) self.avatar_label = ttk.Label(avatar_frame) self.avatar_label.pack(fill=tk.BOTH, expand=True) # 默认头像 self.show_default_avatar() # 右侧员工详细信息 detail_frame = ttk.Frame(info_frame) detail_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True) ttk.Label(detail_frame, text="员工基本信息", style="Subtitle.TLabel").pack(anchor=tk.W, pady=(0, 10)) # 信息标签 - 使用Grid布局更精确控制 label_frame = ttk.Frame(detail_frame) label_frame.pack(fill=tk.X, pady=5) ttk.Label(label_frame, text="姓名:", width=8, anchor=tk.E, style="Info.TLabel").grid(row=0, column=0, sticky="e", padx=5, pady=5) self.name_value = ttk.Label(label_frame, text="", width=20, anchor=tk.W, style="Info.TLabel") self.name_value.grid(row=0, column=1, sticky="w", padx=5, pady=5) ttk.Label(label_frame, text="工号:", width=8, anchor=tk.E, style="Info.TLabel").grid(row=1, column=0, sticky="e", padx=5, pady=5) self.id_value = ttk.Label(label_frame, text="", width=20, anchor=tk.W, style="Info.TLabel") self.id_value.grid(row=1, column=1, sticky="w", padx=5, pady=5) ttk.Label(label_frame, text="部门:", width=8, anchor=tk.E, style="Info.TLabel").grid(row=2, column=0, sticky="e", padx=5, pady=5) self.dept_value = ttk.Label(label_frame, text="", width=20, anchor=tk.W, style="Info.TLabel") self.dept_value.grid(row=2, column=1, sticky="w", padx=5, pady=5) ttk.Label(label_frame, text="职位:", width=8, anchor=tk.E, style="Info.TLabel").grid(row=3, column=0, sticky="e", padx=5, pady=5) self.position_value = ttk.Label(label_frame, text="", width=20, anchor=tk.W, style="Info.TLabel") self.position_value.grid(row=3, column=1, sticky="w", padx=5, pady=5) ttk.Label(label_frame, text="打卡状态:", width=8, anchor=tk.E, style="Info.TLabel").grid(row=4, column=0, sticky="e", padx=5, pady=5) self.status_value = ttk.Label(label_frame, text="未识别", width=20, anchor=tk.W, style="Info.TLabel") self.status_value.grid(row=4, column=1, sticky="w", padx=5, pady=5) # 打卡按钮 button_frame = ttk.Frame(detail_frame) button_frame.pack(fill=tk.X, pady=10) self.clock_button = ttk.Button(button_frame, text="打卡", command=self.clock_in, width=15, state=tk.DISABLED) self.clock_button.pack(side=tk.RIGHT, padx=(0, 10)) # 考勤记录标 ttk.Label(right_frame, text="今日考勤记录", style="Title.TLabel").pack(pady=(10, 10), anchor=tk.W, padx=10) # 考勤记录表格 record_card = ttk.Frame(right_frame, style="Card.TFrame") record_card.pack(fill=tk.BOTH, expand=True, padx=10, pady=(0, 10)) # 创建表格 columns = ("time", "id", "name", "dept", "status") self.record_tree = ttk.Treeview(record_card, columns=columns, show="headings", height=8) # 设置列标 self.record_tree.heading("time", text="时间", anchor=tk.W) self.record_tree.heading("id", text="工号", anchor=tk.W) self.record_tree.heading("name", text="姓名", anchor=tk.W) self.record_tree.heading("dept", text="部门", anchor=tk.W) self.record_tree.heading("status", text="状态", anchor=tk.W) # 设置列宽 self.record_tree.column("time", width=150, anchor=tk.W) self.record_tree.column("id", width=100, anchor=tk.W) self.record_tree.column("name", width=100, anchor=tk.W) self.record_tree.column("dept", width=120, anchor=tk.W) self.record_tree.column("status", width=80, anchor=tk.W) # 添加滚动条 scrollbar = ttk.Scrollbar(record_card, orient="vertical", command=self.record_tree.yview) self.record_tree.configure(yscrollcommand=scrollbar.set) # 布局 self.record_tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=10, pady=10) scrollbar.pack(side=tk.RIGHT, fill=tk.Y) # 状态栏 self.status_var = tk.StringVar(value="系统就绪") status_bar = ttk.Label(root, textvariable=self.status_var, relief=tk.SUNKEN, anchor=tk.W) status_bar.pack(side=tk.BOTTOM, fill=tk.X) # 初始化变量 self.stream_active = False self.instance = vlc.Instance("--no-xlib") self.player = self.instance.media_player_new() # 模拟员工数据库 self.employees = { "1001": {"name": "张明", "dept": "技术部", "position": "高级工程师", "avatar": "avatar1.jpg"}, "1002": {"name": "李华", "dept": "市场部", "position": "市场经理", "avatar": "avatar2.jpg"}, "1003": {"name": "王芳", "dept": "财务部", "position": "会计", "avatar": "avatar3.jpg"}, "1004": {"name": "赵刚", "dept": "人力资源", "position": "招聘主管", "avatar": "avatar4.jpg"}, "1005": {"name": "陈晓", "dept": "产品部", "position": "产品经理", "avatar": "avatar5.jpg"}, } # 考勤记录 self.attendance_records = [] # 添加示例记录 self.add_sample_records() # 初始化线程队列 self.gui_queue = queue.Queue() self.root.after(100, self.process_queue) def process_queue(self): """处理队列中的GUI更新任务""" while not self.gui_queue.empty(): try: task = self.gui_queue.get_nowait() if task["type"] == "update_employee_info": self.name_value.config(text=task["name"]) self.id_value.config(text=task["id"]) self.dept_value.config(text=task["dept"]) self.position_value.config(text=task["position"]) self.status_value.config(text=task["status"]) self.show_employee_avatar(task["avatar"]) self.clock_button.config(state=tk.NORMAL) elif task["type"] == "update_status": self.status_var.set(task["message"]) elif task["type"] == "clock_in": self.clock_in_task(task["emp_id"], task["emp_name"], task["emp_dept"]) except queue.Empty: pass self.root.after(100, self.process_queue) def show_default_avatar(self): """显示默认头像""" default_img = Image.new('RGB', (180, 200), color='#3498db') draw = ImageDraw.Draw(default_img) try: font = ImageFont.truetype("arial.ttf", 24) except: font = ImageFont.load_default() draw.text((40, 85), "无数据", fill="white", font=font) default_photo = ImageTk.PhotoImage(default_img) self.avatar_label.config(image=default_photo) self.avatar_label.image = default_photo def add_sample_records(self): """添加示例考勤记录""" records = [ ("08:45:22", "1001", "张明", "技术部", "正常"), ("09:01:35", "1002", "李华", "市场部", "迟到"), ("09:05:47", "1003", "王芳", "财务部", "正常"), ("12:01:15", "1001", "张明", "技术部", "外出"), ("13:30:08", "1004", "赵刚", "人力资源", "正常"), ] for record in records: self.attendance_records.append(record) self.record_tree.insert("", tk.END, values=record) def toggle_stream(self): """切换视频流状态""" if self.stream_active: self.stop_stream() else: self.start_stream() def start_stream(self): """启动视频流""" url = self.url_entry.get().strip() if not url: messagebox.showerror("错误", "请输入有效的视频流URL") return try: media = self.instance.media_new(url) self.player.set_media(media) win_id = self.video_container.winfo_id() if os.name == 'nt': win_id = int(win_id) self.player.set_hwnd(win_id) else: self.player.set_xwindow(win_id) self.player.play() self.stream_active = True self.connect_button.config(text="停止监控") self.snapshot_button.config(state=tk.NORMAL) self.status_var.set(f"正在播放: {url}") # 启动视频流线程 threading.Thread(target=self.video_thread, daemon=True).start() # 启动识别线程 threading.Thread(target=self.recognition_thread, daemon=True).start() except Exception as e: messagebox.showerror("连接错误", f"无法连接到视频流: {str(e)}") self.status_var.set("连接失败") def video_thread(self): """视频流播放线程""" pass # 视频流由VLC内部处理,无需额外操作 def recognition_thread(self, out_dir: str = OUT_DIR): """使用实际工牌识别代码进行识别的线程""" cap = cv2.VideoCapture(self.url_entry.get().strip()) if not cap.isOpened(): print("[错误] 无法打开视频流") return while self.stream_active: ret, frame = cap.read() if not ret: print("[调试信息] 无法读取视频帧") continue # 保存当前帧为临时文件供main函数处理 temp_image_path = "temp_frame.jpg" OUT_DIR = "output" cv2.imwrite(OUT_DIR, frame) cv2.imwrite(temp_image_path, frame) print(f"[调试信息] 图像已保存至 {temp_image_path}") # 调用main.py 进行图像识别 try: print(f"[调试信息] 正在调用 main.py 处理 {temp_image_path}") subprocess.run(["python", "main.py", temp_image_path], check=True) print("[调试信息] main.py 执行完成") except subprocess.CalledProcessError as e: print(f"[错误信息] main.py 执行失败: {e}") # 读取main.py 输出的JSON文件 stem = os.path.splitext(os.path.basename(temp_image_path))[0] final_json = os.path.join(OUT_DIR, f"{stem}_face_result.json") if os.path.exists(final_json): print(f"[调试信息] JSON文件已找到: {final_json}") with open(final_json, "r", encoding="utf-8") as f: result = json.load(f) ocr_info = result.get("ocr", {}) emp_id = ocr_info.get("id") emp_name = ocr_info.get("name") emp_dept = ocr_info.get("department") # 打印识别结果 print(f"[调试信息] 识别结果: ID={emp_id}, 姓名={emp_name}, 部门={emp_dept}") # 将识别结果发送到GUI队列 task = { "type": "update_employee_info", "name": emp_name, "id": emp_id, "dept": emp_dept, "position": "未知", "avatar": os.path.join(OUT_DIR, f"{stem}_face.jpg") } self.gui_queue.put(task) time.sleep(1) # 控制识别频率 cap.release() def stop_stream(self): """停止视频流""" if self.player: self.player.stop() self.stream_active = False self.connect_button.config(text="启动监控") self.snapshot_button.config(state=tk.DISABLED) self.clock_button.config(state=tk.DISABLED) self.status_var.set("已停止视频流") # 清空员工信息 self.name_value.config(text="") self.id_value.config(text="") self.dept_value.config(text="") self.position_value.config(text="") self.status_value.config(text="未识别") self.show_default_avatar() def take_snapshot(self): """抓拍当前帧""" if self.stream_active: timestamp = time.strftime("%Y%m%d_%H%M%S") filename = f"snapshot_{timestamp}.png" self.player.video_take_snapshot(0, filename, 0, 0) messagebox.showinfo("抓拍成功", f"已保存截图: {filename}") self.status_var.set(f"截图已保存: {filename}") def show_employee_avatar(self, avatar_path): """显示员工头像""" try: colors = ["#3498db", "#2ecc71", "#e74c3c", "#f39c12", "#9b59b6"] color = random.choice(colors) img = Image.new('RGB', (180, 200), color=color) draw = ImageDraw.Draw(img) try: font = ImageFont.truetype("arial.ttf", 20) except: font = ImageFont.load_default() draw.text((40, 85), "员工照片", fill="white", font=font) photo = ImageTk.PhotoImage(img) self.avatar_label.config(image=photo) self.avatar_label.image = photo except Exception as e: print(f"头像加载错误: {e}") def clock_in(self): """员工打卡""" emp_id = self.id_value.cget("text") emp_name = self.name_value.cget("text") emp_dept = self.dept_value.cget("text") task = {"type": "clock_in", "emp_id": emp_id, "emp_name": emp_name, "emp_dept": emp_dept} self.gui_queue.put(task) def clock_in_task(self, emp_id, emp_name, emp_dept): """执行打卡逻辑""" current_time = time.strftime("%H:%M:%S") hour = int(time.strftime("%H")) minute = int(time.strftime("%M")) status = "迟到" if (hour > 9 or (hour == 9 and minute > 0)) else "正常" record = (current_time, emp_id, emp_name, emp_dept, status) self.attendance_records.append(record) self.record_tree.insert("", tk.END, values=record) self.status_value.config(text=f"已打卡 ({status})") self.status_var.set(f"{emp_name} 打卡成功! 时间: {current_time}") self.clock_button.config(state=tk.DISABLED) self.record_tree.see(self.record_tree.get_children()[-1]) if __name__ == "__main__": root = tk.Tk() app = EmployeeClockSystem(root) root.mainloop() 再这个代码基础上使用ttkboostrap主包,使得界面更好看
08-23
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值