捕捉人脸,同步语音播报(成功获得CSDN 短信通知的永久使用Chattts API)工作时间---


import cv2
import os
import sys
import threading
import time
import pyttsx3
from PyQt5.QtCore import Qt, QTimer, QThread, pyqtSignal
from PyQt5.QtGui import QImage, QPixmap
from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel, QVBoxLayout, QWidget, QLineEdit, QPushButton
from datetime import datetime

# 保存路径
SAVE_PATH = r"D:\Pic"
LOG_FILE = os.path.join(SAVE_PATH, "log.txt")

# 创建目录
if not os.path.exists(SAVE_PATH):
    os.makedirs(SAVE_PATH)

# 初始化语音引擎
engine = pyttsx3.init()

# 新增线程类用于播报运行时间
class TimeAnnouncerThread(QThread):
    def __init__(self, main_window):
        super().__init__()
        self.main_window = main_window
        self.running = False
        self.start_time = None

    def run(self):
        self.running = True
        self.start_time = datetime.now()
        while self.running:
            current_time = datetime.now()
            elapsed_time = current_time - self.start_time
            #elapsed_time_2=elapsed_time.strftime('%Y-%m-%d %H:%M:%S')
            #message = f"{self.person_name},目前已经刷牙: 0.0612"
            #message = f"{self.person_name},捕捉OK. 时间是 {now.strftime('%Y-%m-%d %H:%M:%S')}"  file.write(f"{datetime.now().strftime('%Y-%m-%d %H:%M:%S')} - {text}\n")
            message = f"目前已经运行: 0.0612"
            if self.main_window.person_name:
                self.main_window.speak(message)
            else:
                self.main_window.speak("请输入人名")
            
            time.sleep(10)

    def stop(self):
        self.running = False
        self.wait()

class VideoThread(QThread):
    change_pixmap_signal = pyqtSignal(QImage)
    face_detected_signal = pyqtSignal()  # 新增信号用于触发面部检测事件

    def __init__(self):
        super().__init__()
        self._run_flag = True
        self.frame = None

    def run(self):
        cap = cv2.VideoCapture(0)
        if not cap.isOpened():
            print("Cannot open camera")
            return

        while self._run_flag:
            ret, frame = cap.read()
            if ret:
                # 面部检测
                gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
                faces = face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30))
                for (x, y, w, h) in faces:
                    cv2.rectangle(frame, (x, y), (x+w, y+h), (255, 0, 0), 2)
                    self.face_detected_signal.emit()  # 触发面部检测信号

                rgb_image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
                h, w, ch = rgb_image.shape
                bytes_per_line = ch * w
                convert_to_Qt_format = QImage(rgb_image.data, w, h, bytes_per_line, QImage.Format_RGB888)
                p = convert_to_Qt_format.scaled(640, 480, Qt.KeepAspectRatio)
                self.change_pixmap_signal.emit(p)
                self.frame = frame  # 保存当前帧以便后续使用

            time.sleep(1/30)  # 限制帧率

        cap.release()

    def stop(self):
        self._run_flag = False
        self.wait()

class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle('Face Detection App')
        self.setGeometry(100, 100, 900, 700)

        self.label = QLabel(self)
        self.label.resize(640, 480)
        self.setCentralWidget(self.label)

        self.thread = VideoThread()
        self.thread.change_pixmap_signal.connect(self.update_image)
        self.thread.face_detected_signal.connect(self.on_face_detected)  # 连接面部检测信号
        self.thread.start()

        # 添加输入框和按钮
        self.name_input = QLineEdit(self)
        self.name_input.move(20, 600)
        self.name_input.resize(200, 30)
        self.name_input.returnPressed.connect(self.start_capture)

        self.capture_button = QPushButton('Start Capture', self)
        self.capture_button.move(20, 640)
        self.capture_button.resize(200, 30)
        self.capture_button.clicked.connect(self.start_capture)

        # 保存人名
        self.person_name = ""
        self.capture_active = False
        self.face_detected_count = 0
        self.time_announcer_thread = TimeAnnouncerThread(self)  # 实例化时间播报线程

    def start_capture(self):
        # 获取输入的人名并开始捕获
        self.person_name = self.name_input.text()
        self.capture_active = True
        self.name_input.setEnabled(False)
        self.capture_button.setEnabled(False)

    def update_image(self, image):
        self.label.setPixmap(QPixmap.fromImage(image))

    def speak(self, text):
        engine.say(text)
        engine.runAndWait()

    def log_event(self, text):
        with open(LOG_FILE, 'a') as file:
            file.write(f"{datetime.now().strftime('%Y-%m-%d %H:%M:%S')} - {text}\n")

    def on_face_detected(self):
        now = datetime.now()
        timestamp = now.strftime("%Y%m%d_%H%M%S")
        image_path = os.path.join(SAVE_PATH, f"face_{timestamp}.jpg")
        # 检查 frame 是否为空
        if self.thread.frame is not None and self.capture_active:
            cv2.imwrite(image_path, self.thread.frame)
            self.log_event(f"Face detected and saved to {image_path}")

            # 播报捕捉OK信息
            if self.face_detected_count < 2:
                message = f"{self.person_name},捕捉OK. 时间是 {now.strftime('%Y-%m-%d %H:%M:%S')}"
                self.speak(message)
                self.face_detected_count += 1

            # 如果已经播报过两次捕捉OK,则启动时间播报线程
            if self.face_detected_count == 2 and not self.time_announcer_thread.isRunning():
                self.time_announcer_thread.start()

        else:
            print("Warning: Frame is empty or None when trying to save.")

    def closeEvent(self, event):
        self.thread.stop()
        self.time_announcer_thread.stop()  # 停止时间播报线程
        event.accept()

if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = MainWindow()

    # 在窗口显示之前提示用户输入人名
    window.name_input.setFocus()
    window.name_input.selectAll()

    # 加载级联分类器
    face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')

    window.show()

    sys.exit(app.exec_())

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值