团队项目-将py界面嵌入到vue中

通过将原有的py代码进行修改,删除了tkinter界面化工具,改用视频流的形式,将视频流通过端口传输到前端,虽然会导致有延迟卡顿,但相比于白花花的界面更加美观。

import os
import dlib
import numpy as np
import cv2
import logging
import time
import pandas as pd

# Dlib 初始化
detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor('data/data_dlib/shape_predictor_68_face_landmarks.dat')
face_reco_model = dlib.face_recognition_model_v1("data/data_dlib/dlib_face_recognition_resnet_model_v1.dat")

class Face_Recognizer:
    def __init__(self):
        self.font = cv2.FONT_ITALIC
        self.frame_time = 0
        self.frame_start_time = 0
        self.fps = 0
        self.fps_show = 0
        self.start_time = time.time()
        self.frame_cnt = 0

        # 人脸数据库相关
        self.face_features_known_list = []
        self.face_name_known_list = []
        self.signed_in_names = []  # 仅保留内存中的签到名单
        self.all_names = []

        # 视频流相关
        self.cap = cv2.VideoCapture(0)
        self.get_face_database()
        logging.info("Face Recognizer initialized without GUI")

    def get_face_database(self):
        path_features_known_csv = r"D:\github\facecsv\features_all.csv"
        if os.path.exists(path_features_known_csv):
            csv_rd = pd.read_csv(path_features_known_csv, header=None)
            for i in range(csv_rd.shape[0]):
                features_someone_arr = []
                name = csv_rd.iloc[i][0]
                self.face_name_known_list.append(name)
                self.all_names.append(name)
                for j in range(1, 129):
                    features_someone_arr.append(float(csv_rd.iloc[i][j]))
                self.face_features_known_list.append(features_someone_arr)
            logging.info(f"Loaded {len(self.face_features_known_list)} faces from database")
        else:
            logging.error("'features_all.csv' not found!")

    def sign_in(self, name):
        # 直接标记为已签到(不再检查重复)
        if name not in self.signed_in_names:
            self.signed_in_names.append(name)
            logging.info(f"{name} signed in")
            return True
        return False

    @staticmethod
    def return_euclidean_distance(feature_1, feature_2):
        feature_1 = np.array(feature_1)
        feature_2 = np.array(feature_2)
        return np.sqrt(np.sum(np.square(feature_1 - feature_2)))

    def process_frame(self, img_rd):
        self.frame_cnt += 1
        faces = detector(img_rd, 0)

        if len(faces) > 0:
            for i, face in enumerate(faces):
                shape = predictor(img_rd, face)
                face_descriptor = face_reco_model.compute_face_descriptor(img_rd, shape)
                face_feature = [float(x) for x in face_descriptor]

                distances = []
                for known_feature in self.face_features_known_list:
                    distance = self.return_euclidean_distance(face_feature, known_feature)
                    distances.append(distance)
                min_distance = min(distances)
                min_index = distances.index(min_distance)

                if min_distance < 0.4:
                    name = self.face_name_known_list[min_index]
                    self.sign_in(name)  # 仅更新内存中的签到状态
                    cv2.putText(img_rd, name, (face.left(), face.top() - 10),
                                self.font, 0.8, (0, 255, 0), 2)
                else:
                    cv2.putText(img_rd, "Unknown", (face.left(), face.top() - 10),
                                self.font, 0.8, (0, 0, 255), 2)
                cv2.rectangle(img_rd, (face.left(), face.top()),
                              (face.right(), face.bottom()), (0, 255, 0), 2)

        self.update_fps()
        cv2.putText(img_rd, f"FPS: {self.fps_show:.2f}", (10, 30),
                    self.font, 0.8, (0, 255, 0), 2)
        return img_rd

    def update_fps(self):
        now = time.time()
        if int(now) != int(self.start_time):
            self.fps_show = self.fps
        self.frame_time = now - self.frame_start_time
        self.fps = 1.0 / self.frame_time
        self.frame_start_time = now

    def generate_frames(self):
        try:
            while self.cap.isOpened():
                ret, frame = self.cap.read()
                if not ret:
                    break
                processed_frame = self.process_frame(frame)
                ret, buffer = cv2.imencode('.jpg', processed_frame)
                frame = buffer.tobytes()
                yield (b'--frame\r\n'
                       b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')
        except Exception as e:
            logging.error(f"Video stream error: {e}")
        finally:
            self.__del__()

    def __del__(self):
        if self.cap.isOpened():
            self.cap.release()
            cv2.destroyAllWindows()  # 新增窗口资源释放
            logging.info("Camera resource released")

from flask import Flask, jsonify, Response
from flask_cors import CORS
import threading
import subprocess
import pandas as pd
from datetime import datetime
from face_reco_from_camera_ot import Face_Recognizer
from threading import Lock

app = Flask(__name__)
CORS(app, resources={r"/*": {"origins": "*"}})  # 启用跨域支持

# 全局变量和锁
face_recognizer = None
current_csv = ""
camera_lock = Lock()  # 防止摄像头资源冲突

# -------------------- 签到功能路由 --------------------
@app.route('/start-recognition', methods=['POST'])
def start_recognition():
    global face_recognizer, current_csv
    try:
        with camera_lock:
            # 释放已有摄像头资源
            if face_recognizer is not None:
                face_recognizer.__del__()
            # 初始化新实例
            face_recognizer = Face_Recognizer()
            current_csv = ""  # 移除了对不存在属性的引用
            return jsonify({
                "status": "started",
                "message": "人脸识别已启动"
            })
    except Exception as e:
        return jsonify({
            "status": "error",
            "message": str(e)
        }), 500

@app.route('/video_feed')
def video_feed():
    global face_recognizer
    if face_recognizer is None:
        return Response("人脸识别未初始化", status=503)
    return Response(
        face_recognizer.generate_frames(),
        mimetype='multipart/x-mixed-replace; boundary=frame'
    )

@app.route('/sign-in-status', methods=['GET'])
def get_sign_in_status():
    global face_recognizer
    try:
        if face_recognizer is not None:
            return jsonify({"signed": face_recognizer.signed_in_names})
        else:
            return jsonify({"signed": []})
    except Exception as e:
        return jsonify({"signed": [], "error": str(e)}), 500

# -------------------- 人脸注册功能路由 --------------------
def run_face_register():
    subprocess.Popen(['python', 'get_faces_from_camera_tkinter.py'])

@app.route('/start-face-registration', methods=['POST'])
def start_face_registration():
    thread = threading.Thread(target=run_face_register)
    thread.start()
    return jsonify({
        'status': 'started',
        'message': '人脸录入窗口已启动'
    })

# -------------------- 特征提取路由 --------------------
def run_face_reco_standalone():
    subprocess.Popen(['python', 'features_extraction_to_csv.py'])

@app.route('/start-face-recognition', methods=['POST'])
def start_face_recognition():
    thread = threading.Thread(target=run_face_reco_standalone)
    thread.start()
    return jsonify({
        'status': 'started',
        'message': '人脸特征正在导入数据库'
    })

if __name__ == '__main__':
    app.run(port=5000, debug=True, threaded=True)
posted @ 2025-05-19 09:58  sword_kong  阅读(9)  评论(0)    收藏  举报