Because the tasks I have to do next are complex, I spent two weeks finishing this task.

In this task, I have to combine the face recognition system I did last semester with my WebUI. It is hard for me because it requires communication with Python and HTML and some multithreaded programming techniques. After some thinking, I came up with the idea that I could let the Python program write down the information it needs to tell HTML language in a JSON file, and HTML can read this file automatically.

Here is my code👇

faceRecognition.html
<!DOCTYPE html>
<html lang="zh">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>人脸识别</title>
  <style>
    body {
      background: #ffffff;
      font-family: 'Arial', sans-serif;
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      min-height: 100vh;
      margin: 0;
      color: #2d572c;
      text-align: center;
    }

    p {
      font-size: 2rem;
      font-weight: bold;
      margin-bottom: 20px;
      border-bottom: 3px solid #2d572c;
      display: inline-block;
      padding-bottom: 5px;
      animation: fadeIn 1.5s ease-out;
    }

    .image-container {
      background: #ffffff;
      padding: 15px;
      border-radius: 15px;
      border: 3px solid #2d572c;
      box-shadow: 0 5px 15px rgba(45, 87, 44, 0.2);
      transition: transform 0.3s ease-in-out;
    }

    .image-container:hover {
      transform: scale(1.02);
    }

    #faceImage {
      border-radius: 10px;
      width: 100%;
      max-width: 500px;
      height: auto;
      box-shadow: 0 8px 15px rgba(45, 87, 44, 0.2);
      transition: opacity 0.5s ease-in-out;
      opacity: 0;
    }

    #faceImage.loaded {
      opacity: 1;
    }

    @keyframes fadeIn {
      0% {
        opacity: 0;
        transform: translateY(-20px);
      }

      100% {
        opacity: 1;
        transform: translateY(0);
      }
    }
  </style>
</head>

<body>
  <p id="title">第一步:人脸识别</p>
  <div class="image-container">
    <img id="faceImage" src="../static/image/temp.jpeg?timestamp=0" alt="人脸识别">
  </div>

  <script>
    let lastSuccessfulSrc = "../static/image/temp.jpeg?timestamp=0";

    function updateImage() {
      const imgElement = document.getElementById('faceImage');
      const timestamp = Date.now();
      const newSrc = `../static/image/temp.jpeg?timestamp=${timestamp}`;

      fetch(newSrc, { method: 'HEAD' })
        .then(response => {
          if (response.ok) {
            imgElement.src = newSrc;
            imgElement.classList.add('loaded');
            lastSuccessfulSrc = newSrc;
          }
        })
        .catch(() => {
          console.error("图片加载失败,保留上一帧");
          imgElement.src = lastSuccessfulSrc;
        });
    }

    const urlParams = new URLSearchParams(window.location.search);
    const lang = urlParams.get('lang') || 'zh';
    let isChinese = lang === 'zh';

    function switchLanguage() {
      document.getElementById("title").textContent = isChinese ? "第一步:人脸识别" : "Step 1: Face recognition";
      setInterval(checkJsonData, 1000); // **每 1 秒检查 JSON**
    }

    function checkJsonData() {
      fetch('/static/data.json')
        .then(response => response.json())
        .then(data => {
          if ((Array.isArray(data.name) && data.name.length > 0) ||
            (typeof data.name === "string" && data.name !== "0")) {
            // name 是数组且非空,或 name 是字符串且不为 "0",则跳转
            const url = lang === 'en' ? "/helloPeopel?lang=en" : "/helloPeopel?lang=zh";
            window.location.href = url;
          }
        })
        .catch(error => console.error('Error fetching JSON:', error));
    }

    window.onload = function () {
      switchLanguage();
      setTimeout(() => document.getElementById('faceImage').classList.add('loaded'), 100);
    };

    setInterval(updateImage, 1000);
  </script>
</body>

</html>
helloPeople.html
<!DOCTYPE html>
<html lang="zh">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>关于此项目</title>
  <link rel="stylesheet" href="../static/home.css">
</head>

<body>
  <div class="container">
    <h1 id="title">关于此项目</h1>
    <p id="description">本系统由宁波赫德KAINGMING班的Jackson搭建</p>
    <p id="moreInfo">该项目使用计算机视觉算法,来帮助我们的用户进行大规模的视力筛查</p>
    <button class="btn" id="backButton" onclick="goBack()">返回首页</button>
  </div>

  <script>
    // 获取 URL 中的语言参数
    const urlParams = new URLSearchParams(window.location.search);
    const lang = urlParams.get('lang');

    // 切换语言
    function switchLanguage(name) {
      const title = document.getElementById("title");
      const description = document.getElementById("description");
      const moreInfo = document.getElementById("moreInfo");
      const backButton = document.getElementById("backButton");

      if (lang === 'en') {
        title.textContent = "Hi, " + name; // 英文模式
        description.textContent = "This system was built by Jackson from HDNB KAINGMING class";
        moreInfo.textContent = "This project uses computer vision algorithms to help our users conduct large-scale vision screening";
        backButton.textContent = "Back to Home";
      } else {
        title.textContent = "你好, " + name; // 中文模式
        description.textContent = "本系统由宁波赫德KAINGMING班的Jackson搭建";
        moreInfo.textContent = "该项目使用计算机视觉算法,来帮助我们的用户进行大规模的视力筛查";
        backButton.textContent = "返回首页";
      }
    }

    // 页面加载时切换语言并读取JSON文件
    window.onload = function () {
      fetch('data.json')
        .then(response => response.json())
        .then(data => {
          const name = data.name;
          switchLanguage(name);
        })
        .catch(error => console.error('Error loading JSON:', error));
    };

    // 返回首页函数
    function goBack() {
      const url = lang === 'en' ? "/?lang=en" : "/?lang=zh";
      window.location.href = url;
    }
  </script>
</body>

</html>
MyFaceRecognation.py
from sklearn.neighbors import NearestNeighbors
import face_recognition
import os
import json
import numpy as np

def save_to_json(encodings, names, json_file):
    """保存人脸特征和名字到 JSON 文件"""
    # 将 numpy.ndarray 转换为列表
    data = [{"name": name, "encoding": encoding.tolist()} for name, encoding in zip(names, encodings)]
    with open(json_file, "w", encoding="utf-8") as f:
        json.dump(data, f, ensure_ascii=False, indent=4)

def load_from_json(json_file):
    """从 JSON 文件加载人脸特征和名字"""
    if not os.path.exists(json_file):
        return [], []

    with open(json_file, "r", encoding="utf-8") as f:
        data = json.load(f)
    encodings = [np.array(item["encoding"]) for item in data]  # 转回 numpy.ndarray
    names = [item["name"] for item in data]
    return encodings, names

def load_known_faces_with_knn(known_faces_dir, data_file="../data/faces.json"):
    """加载已知人脸,构建 KD-Tree,支持增量更新和同步删除"""
    print("Loading known faces...")
    os.makedirs(os.path.dirname(data_file), exist_ok=True)

    # 加载已保存的特征和名称
    known_encodings, known_names = load_from_json(data_file)

    # 获取目录中的实际文件名(去掉扩展名)
    current_files = {os.path.splitext(filename)[0] for filename in os.listdir(known_faces_dir) if filename.endswith((".jpg", ".jpeg", ".png"))}

    # 找到需要移除的文件
    removed_files = set(known_names) - current_files
    if removed_files:
        print(f"Removing deleted files from cache: {removed_files}")
        indices_to_keep = [i for i, name in enumerate(known_names) if name not in removed_files]
        known_encodings = [known_encodings[i] for i in indices_to_keep]
        known_names = [known_names[i] for i in indices_to_keep]

    # 处理新文件
    for filename in current_files - set(known_names):
        print(f"Processing {filename}...")
        image_path = os.path.join(known_faces_dir, filename + ".jpg")  # 默认扩展名为 .jpg
        if not os.path.exists(image_path):  # 检查其他扩展名
            image_path = os.path.join(known_faces_dir, filename + ".jpeg")
        if not os.path.exists(image_path):  # 检查其他扩展名
            image_path = os.path.join(known_faces_dir, filename + ".png")

        if os.path.exists(image_path):
            image = face_recognition.load_image_file(image_path)
            encodings = face_recognition.face_encodings(image)
            if encodings:  # 确保图片中有检测到人脸
                known_encodings.append(encodings[0])
                known_names.append(filename)

    # 保存更新后的特征和名称
    save_to_json(known_encodings, known_names, data_file)

    knn = NearestNeighbors(n_neighbors=1, algorithm="ball_tree").fit(known_encodings)
    return knn, np.array(known_encodings), known_names

def recognize_faces_with_knn(input_image_path, knn, known_names, tolerance=0.6):
    """使用 KD-Tree 识别人脸"""
    print("Recognizing faces in image...")
    input_image = face_recognition.load_image_file(input_image_path)
    face_encodings = face_recognition.face_encodings(input_image)
    recognized_names = []

    for face_encoding in face_encodings:
        distances, indices = knn.kneighbors([face_encoding])
        if distances[0][0] < tolerance:
            recognized_names.append(known_names[indices[0][0]])
        else:
            recognized_names.append("Unknown")
    return recognized_names

    
print("Starting...")

known_faces_dir = "../data/faces"  # 存放已知人脸图片的目录
input_image_path = "./static/image/output.jpeg"  # 要识别的图片路径

knn, known_encodings, known_names = load_known_faces_with_knn(known_faces_dir)
print("Known names (without extensions):", known_names)
recognized_names = recognize_faces_with_knn(input_image_path, knn, known_names)
print("**********************")
print("Recognized names:", recognized_names)
print("**********************")
 # 创建一个字典变量
data = {
    "name":recognized_names
}

# 将字典写入 JSON 文件
with open("./static/data.json", "w") as json_file:
    json.dump(data, json_file)

webUI.py
from flask import Flask, render_template, request, redirect, url_for
import threading
import time
import Track_Display
import os
import json

app = Flask(__name__)
isStart = False

# 首页路由
@app.route('/')
def home():
    lang = request.args.get('lang', 'zh')  # 获取URL中的语言参数,默认为中文
    return render_template('home.html', lang=lang)

# 关于页面路由
@app.route('/about')
def about():
    lang = request.args.get('lang', 'zh')  # 获取URL中的语言参数,默认为中文
    return render_template('about.html', lang=lang)

@app.route('/introduction')
def introduction():
    lang = request.args.get('lang', 'zh')  # 获取URL中的语言参数,默认为中文
    return render_template('introduction.html', lang=lang)

@app.route('/face')
def face():
    global isStart
    lang = request.args.get('lang', 'zh')
    if isStart == False:
        tread = threading.Thread(target=Track_Display.track_display)
        tread.start()
        isStart = True

    return render_template('faceRecognition.html', lang=lang)

@app.route('/helloPeopel')
def helloPeople():
    lang = request.args.get('lang', 'zh')
    return render_template('helloPeople.html',lang = lang)

@app.route('/data.json')
def serve_data():
    return app.send_static_file('data.json')

if __name__ == '__main__':
    print("cleaning json file...")
    init = {
    "name":0
    }
    with open("./static/data.json", "w") as json_file:
        json.dump(init, json_file)
    # 启动Flask服务并监听所有可用的IP地址,这样在局域网中其他设备可以访问
    app.run(host='0.0.0.0', port=5000, debug=True)

At the beginning of the program, the value in data.json will be cleared to zero. When the MyFaceRecognition.py program detects and recognizes a face, it will record the person's name in the json file. Finally, when faceRecognition.html detects that the data in json is not 0, it will jump to helloPeople.html, and helloPeople.html will print the person's name.

Here is the result👇

https://www.youtube.com/watch?v=3y7Xq2DUjN8