import sys import cv2 import numpy as np import pyttsx3 from pyzbar.pyzbar import decode from PyQt5.QtWidgets import ( QApplication, QLabel, QVBoxLayout, QWidget, QLineEdit, QPushButton, QListWidget, QHBoxLayout ) from PyQt5.QtGui import QImage, QPixmap from PyQt5.QtCore import QTimer, QTime, QDate, QDateTime, Qt from multiprocessing import Process, Manager, Lock import time import threading # 初始化语音引擎 engine = pyttsx3.init() engine.setProperty('voice', 'zh') engine.setProperty('rate', 200) engine.setProperty('voice', engine.getProperty('voices')[0].id) # 摄像头进程 def camera_process(share_data, lock): cap = cv2.VideoCapture(0) while share_data['running']: ret, rgb_image = cap.read() if ret: with lock: share_data['frame'] = rgb_image # 存储 RGB 图像 cap.release() # QR 码识别进程 def qr_code_process(share_data, lock): #previous_qr_data = "" # 记录上一个二维码数据,避免重复播报 while share_data['running']: with lock: frame = share_data.get('frame', None) if frame is not None: decoded_objects = decode(frame) for obj in decoded_objects: qr_data = obj.data.decode('utf-8') #if qr_data != previous_qr_data: # 如果内容有变化才播报 share_data['qr_data'] = qr_data text_to_speech(qr_data) #previous_qr_data = qr_data # 语音播报 def text_to_speech(text): engine.say(text) engine.runAndWait() print('二维码内容播报完毕') # NumPy 数组转 QImage def rgbimg_to_qimage(array): array = cv2.cvtColor(array, cv2.COLOR_BGR2RGB) height, width, channel = array.shape bytes_per_line = 3 * width q_image = QImage(array.data, width, height, bytes_per_line, QImage.Format_RGB888) pixmap = QPixmap.fromImage(q_image) return pixmap class MainWindow(QWidget): def __init__(self, share_data, lock): super().__init__() self.share_data = share_data self.lock = lock self.init_ui() self.start_timer() # 线程列表,用于管理每个预约任务的线程和事件 self.reminder_threads = [] self.reminder_events = [] def init_ui(self): self.setWindowTitle('QR Code Scanner & Task Scheduler') self.setGeometry(200, 200, 700, 600) # Video display self.video_label = QLabel(self) self.qr_label = QLabel('QR Code Content: ', self) # Time display self.time_label = QLabel(self) self.time_label.setAlignment(Qt.AlignCenter) # Input fields self.time_label_input = QLabel('预约时间:', self) self.time_input = QLineEdit(self) self.time_input.setPlaceholderText("Enter time (yyyy-MM-dd HH:mm:ss)") self.time_input.setText(QDateTime.currentDateTime().toString('yyyy-MM-dd HH:mm:ss')) self.content_label_input = QLabel('提示内容:', self) self.content_input = QLineEdit(self) self.content_input.setPlaceholderText("Enter reminder content") # Buttons self.add_reminder_button = QPushButton('添加预约任务', self) self.add_reminder_button.clicked.connect(self.set_reminder) self.delete_button = QPushButton('删除预约任务', self) self.delete_button.clicked.connect(self.delete_task) # List box self.task_list = QListWidget(self) # Layout setup layout = QVBoxLayout() layout.addWidget(self.video_label) layout.addWidget(self.qr_label) layout.addWidget(self.time_label) layout.addWidget(self.time_label_input) layout.addWidget(self.time_input) layout.addWidget(self.content_label_input) layout.addWidget(self.content_input) layout.addWidget(self.add_reminder_button) layout.addWidget(self.task_list) layout.addWidget(self.delete_button) self.setLayout(layout) def start_timer(self): self.timer = QTimer(self) self.timer.timeout.connect(self.update_frame) self.timer.start(50) # Time update timer self.time_update_timer = QTimer(self) self.time_update_timer.timeout.connect(self.update_time) self.time_update_timer.start(1000) def update_frame(self): with self.lock: frame = self.share_data.get('frame', None) if frame is not None: pixmap = rgbimg_to_qimage(frame) self.video_label.setPixmap(pixmap) qr_data = self.share_data.get('qr_data', '') if qr_data: self.qr_label.setText(f'QR Code Content: {qr_data}') def update_time(self): current_time = QDateTime.currentDateTime().toString('yyyy-MM-dd HH:mm:ss') self.time_label.setText(f'Current Time: {current_time}') def set_reminder(self): reminder_time = self.time_input.text() reminder_content = self.content_input.text() if reminder_time and reminder_content: reminder_item = f"At {reminder_time} - {reminder_content}" self.task_list.addItem(reminder_item) # Create an event to control the thread stop_event = threading.Event() # Create a new reminder thread reminder_thread = threading.Thread(target=self.trigger_reminder, args=(reminder_time, reminder_content, stop_event)) reminder_thread.daemon = True self.reminder_threads.append(reminder_thread) self.reminder_events.append(stop_event) reminder_thread.start() def trigger_reminder(self, reminder_time, reminder_content, stop_event): while self.share_data['running'] and not stop_event.is_set(): current_time = QDateTime.currentDateTime().toString('yyyy-MM-dd HH:mm:ss') if current_time == reminder_time: text_to_speech(reminder_content) print(f"Reminder triggered: {reminder_content}") break time.sleep(1) def delete_task(self): selected_item = self.task_list.currentRow() if selected_item >= 0: item_text = self.task_list.item(selected_item).text() # Remove from task list widget self.task_list.takeItem(selected_item) # Stop the corresponding reminder thread if 0 <= selected_item < len(self.reminder_threads): stop_event = self.reminder_events[selected_item] stop_event.set() # Stop the thread by setting the event # Optionally join the thread to ensure it has finished self.reminder_threads[selected_item].join() # Remove the thread and event from the list self.reminder_threads[selected_item] = None self.reminder_events[selected_item] = None def closeEvent(self, event): """ 关闭窗口时修改 share_data['running'] = False """ self.share_data['running'] = False event.accept() if __name__ == '__main__': manager = Manager() share_data = manager.dict() lock = manager.Lock() # 初始化共享数据 share_data['frame'] = None # 图像数据 share_data['qr_data'] = '' # 二维码识别结果 share_data['running'] = True # 线程运行标志位 # 启动摄像头进程 p1 = Process(target=camera_process, args=(share_data, lock)) p1.daemon = True p1.start() # 启动 QR 码识别进程 p2 = Process(target=qr_code_process, args=(share_data, lock)) p2.daemon = True p2.start() app = QApplication(sys.argv) window = MainWindow(share_data, lock) window.show() try: sys.exit(app.exec_()) finally: share_data['running'] = False p1.join() p2.join()