人脸识别系统之动态人脸识别

二.动态人脸识别

1.摄像头人脸识别

1.1.导入资源包

javascript 复制代码
import dlib
import cv2
import face_recognition
from PIL import Image, ImageTk
import tkinter as tk
import os

:这些导入语句允许您在代码中使用这些库和模块提供的功能,例如创建图形用户界面、处理文件、进行图像处理和人脸识别等。

Dlib:是一个开源的机器学习库,包含了许多常用的机器学习算法。它还包含了一个名为shape_predictor的模块,用于检测人脸的关键点。

1.2.初始化摄像头

javascript 复制代码
# 初始化摄像头
cap = cv2.VideoCapture(0)
#参数0指定要使用的摄像头设备。在大多数情况下,0表示默认摄像头。

:这行代码初始化了摄像头,并将其作为cap对象返回。cv2.VideoCapture(0)中的0参数通常表示默认摄像头。这行代码是用于从摄像头上捕获实时视频流。

1.3.创建主窗口

javascript 复制代码
root = tk.Tk()
root.title("人脸识别程序")
root.geometry('600x600')

:这段代码通常用于创建一个Tkinter窗口,并为其设置一个标题和一个初始大小。在后续的代码中,您可以添加更多的组件,如按钮、标签、图像等,来构建图形用户界面。

1.4.创建画布

javascript 复制代码
# 创建画布
canvas = tk.Canvas(root, width=600, height=600)
canvas.pack()

:这段代码首先导入了 Tkinter 模块,并创建了一个名为 root 的窗口。然后,它创建了一个画布(canvas),并设置了其宽度和高度。最后,它将画布添加到窗口中,并启动了 Tkinter 的主循环,这样窗口才会显示出来。

1.5.显示摄像头部分

javascript 复制代码
# 摄像头画面显示部分
camera_frame = tk.Label(root)
camera_frame.place(x=50, y=50, width=400, height=400)

:这段代码创建了一个 Label 对象,并将其放置在窗口(root)的坐标 (50, 50) 处,大小为 400x400。然而,由于 Label 控件本身不支持显示动态内容,如摄像头捕获的帧,您需要使用其他方法(如前面提到的 Canvas 控件和 PIL/Pillow 库)来显示摄像头画面。

1.6.显示文本

javascript 复制代码
# 文本显示部分
text_label = tk.Label(root, text="", font=('Helvetica', 12))
text_label.place(x=50, y=460, width=500, height=100)

:这段代码创建了一个 Label 对象,并将其放置在窗口(root)的坐标 (50, 460) 处,大小为 500x100。标签的初始文本内容为空,字体为 Helvetica 字体,字号为 12。

1.7.按钮的点击事件处理函数

javascript 复制代码
# 按钮部分
def capture_face():
    ret, frame = cap.read()
    if ret:
        # 将人脸图像转换为RGB
        rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)

        # 检测人脸位置
        face_locations = face_recognition.face_locations(rgb_frame)

        # 如果检测到人脸
        if face_locations:
            # 对检测到的人脸进行编码
            face_encoding = face_recognition.face_encodings(rgb_frame, face_locations)[0]

            # 加载已保存的人脸编码
            known_face_encodings = []
            known_face_names = []
            for file in os.listdir("facecomparison"):
                image = face_recognition.load_image_file(f"facecomparison/{file}")
                encoding = face_recognition.face_encodings(image)[0]
                known_face_encodings.append(encoding)
                known_face_names.append(file)

            # 比较当前人脸与已知人脸
            matches = face_recognition.compare_faces(known_face_encodings, face_encoding)
            if True in matches:
                text_label.config(text="该人脸已存在,请勿重复录入")
            else:
                # 裁剪人脸图像
                top, right, bottom, left = face_locations[0]
                face_image = frame[top:bottom, left:right]

                # 生成唯一的文件名
                unique_filename = f"facecomparison/face_{len(os.listdir('facecomparison')) + 1}.jpg"

                # 保存人脸到指定文件夹
                cv2.imwrite(unique_filename, face_image)
                text_label.config(text="人脸已录入")
        else:
            text_label.config(text="未检测到人脸")
    else:
        text_label.config(text="无法从摄像头读取帧")

:这段代码的作用是实现一个面部识别系统,该系统能够从摄像头捕获实时帧,检测帧中的人脸,并将新检测到的人脸与已保存的人脸编码进行比较。如果新检测到的人脸与已保存的人脸匹配,它会显示一个消息,告知用户该人脸已存在,不应该重复录入。如果新检测到的人脸与已保存的人脸不匹配,它会将新的人脸图像保存到指定的文件夹中,并显示一个消息,告知用户人脸已录入。如果无法从摄像头读取帧,或者没有检测到人脸,它会显示相应的错误消息。

1.8.识别摄像头捕获的人脸

javascript 复制代码
def recognize_face():
    # 识别摄像头捕获的人脸
    ret, frame = cap.read()
    if ret:
        frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
        rgb_frame = frame.copy()
        face_locations = face_recognition.face_locations(rgb_frame)
        face_encodings = face_recognition.face_encodings(rgb_frame, face_locations)

        # 加载已保存的人脸编码和文件名
        known_face_encodings = []
        known_face_names = []
        for file in os.listdir("facecomparison"):
            image = face_recognition.load_image_file(f"facecomparison/{file}")
            encoding = face_recognition.face_encodings(image)[0]
            known_face_encodings.append(encoding)
            known_face_names.append(file)

        # 标记人脸并显示信息
        for (top, right, bottom, left), face_encoding in zip(face_locations, face_encodings):
            matches = face_recognition.compare_faces(known_face_encodings, face_encoding)
            if True in matches:
                first_match_index = matches.index(True)
                text_label.config(text=f"识别到人脸,人脸属于:{known_face_names[first_match_index]}")
            else:
                cv2.rectangle(frame, (left, top), (right, bottom), (255, 0, 0), 2)  # 使用蓝色线条画框
                cv2.putText(frame, "新的人脸", (left + 10, top + 20), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 0, 0), 1)
                text_label.config(text="人脸不存在,请先录入人脸")

        # 更新画布
        image = Image.fromarray(frame)
        image = ImageTk.PhotoImage(image)
        camera_frame.configure(image=image)
        camera_frame.image = image
    else:
        text_label.config(text="无法从摄像头读取帧")

:这段代码是一个函数,当按钮被点击时,它会执行这个函数。这个函数的作用是识别摄像头捕获的实时帧中的人脸,并与已保存的人脸编码进行比较,以确定是否已存在。如果人脸存在,它会标记并显示该人脸的名称;如果人脸不存在,它会标记新的人脸并提示用户先录入人脸。

1.9.点击关闭程序的按钮

javascript 复制代码
def close_program():
#关闭 Tkinter 应用程序
    root.quit()
#释放摄像头(cap)资源
    cap.release()

:当用户点击关闭程序的按钮时,这两个操作会确保 Tkinter 应用程序和摄像头资源都能被正确地关闭和释放,从而避免资源泄漏和潜在的系统问题。

1.10.创建按钮

javascript 复制代码
button1 = tk.Button(root, text="录入人脸", command=capture_face, width=10, height=2)
button1.place(x=460, y=50, width=100, height=100)

button2 = tk.Button(root, text="识别人脸", command=recognize_face, width=10, height=2)
button2.place(x=460, y=200, width=100, height=100)

button3 = tk.Button(root, text="结束程序", command=close_program, width=10, height=2)
button3.place(x=460, y=350, width=100, height=100)

:这三行代码分别创建了三个按钮,并设置了它们的位置、大小和功能,当用户点击这些按钮时,会触发相应的函数执行。

1.11.更新摄像头的画面

javascript 复制代码
# 更新摄像头画面的函数
def update_image():
    ret, frame = cap.read()
    if ret:
        frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
        face_locations = face_recognition.face_locations(frame)
        for (top, right, bottom, left) in face_locations:
            cv2.rectangle(frame, (left, top), (right, bottom), (0, 255, 0), 2)  # 使用绿色线条画框
        image = Image.fromarray(frame)
        image = ImageTk.PhotoImage(image)
        camera_frame.configure(image=image)
        camera_frame.image = image
    root.after(10, update_image)

# 开始更新画面
update_image()

# 主循环
root.mainloop()

# 释放摄像头
cap.release()

:这段代码的作用是在 Tkinter 窗口(root)中创建一个循环,用于从摄像头捕获实时帧,并在窗口中显示这些帧。这个循环会在每次捕获新帧后立即更新显示的图像。
运行结果

2.视频流人脸识别

2.1.导入资源包

javascript 复制代码
import tkinter as tk
from tkinter import filedialog
from PIL import Image, ImageTk
import cv2
import os
import subprocess
from pathlib import Path

:导入了所需的模块,这些模块将用于创建一个图形用户界面 (GUI) 应用程序,该应用程序可以处理图像文件、使用摄像头、执行命令行操作等。

cv2:这是 OpenCV 模块,用于处理图像和视频,包括摄像头捕捉、图像处理、特征检测等。os:这是 Python 的标准库,用于操作文件和目录,例如创建目录、删除文件、获取文件路径等。

pathlib:这是 Python 的标准库,用于处理文件和目录路径,提供了一个面向对象的接口,可以更方便地处理路径。

2.2.创建界面窗口

javascript 复制代码
# 初始化窗口
win = tk.Tk()
win.title('视频流人脸识别')
win.geometry('600x600')
#创建了一个字体对象 title_font,用于设置标题的字体、大小和样式。title_font = ("Verdana", 20, 'italic')

:这段代码创建了一个名为 "视频流人脸识别" 的窗口,窗口的初始大小为 600x600 像素,并准备了一个斜体字体的对象,用于后续设置窗口标题的字体。

2.3.创建视频播放框架

javascript 复制代码
# 视频播放框架
video_frame = tk.Frame(win, width=300, height=300, bg='black')
video_frame.pack()
#将 video_frame 框架放置在窗口中

:这段代码创建了一个视频播放框架,并将其放置在窗口中,设置其大小为 300x300 像素,背景颜色为黑色。这个框架可以用来显示摄像头捕捉的实时帧或视频文件。

在视频播放框架 video_frame 中创建一个画布

javascript 复制代码
# 视频播放的Canvas
canvas = tk.Canvas(video_frame, width=900, height=900)
canvas.pack(side=tk.TOP, anchor=tk.CENTER)

:这段代码创建了一个画布,并将其放置在视频播放框架中,设置其大小为 900x900 像素。这个画布可以用来显示摄像头捕捉的实时帧或视频文件。

2.5. 加载人脸识别预训练的模型

javascript 复制代码
# 加载人脸识别的预训练模型
face_cascade=cv2.CascadeClassifier(cv2.data.haarcascades+'haarcascade_frontalface_default.xml')

:这段代码创建了一个名为 face_cascade 的级联分类器对象,用于检测图像或视频帧中的人脸。OpenCV 提供了许多预训练的级联分类器,包括正面人脸检测、眼睛检测等,这些分类器可以提高检测的准确性和效率。

2.6.人脸检测

javascript 复制代码
# 人脸检测函数
def detect_faces(frame):
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    faces = face_cascade.detectMultiScale(gray, 1.3, 5)
    for (x, y, w, h) in faces:
        cv2.rectangle(frame, (x, y), (x+w, y+h), (255, 0, 0), 2)
    return frame, faces

:这个函数通过级联分类器在输入图像中检测人脸,并在图像上标记出这些人脸,以便进一步的处理或显示。

1.3:是尺度缩放因子,用于调整检测窗口大小。

5:是邻域内像素的最低匹配数,用于确定检测到的候选框是否真正是人脸。

2.7.在循环外部创建全局的PhotoImage对象

javascript 复制代码
# 在循环外部创建全局的PhotoImage对象
imgtk = None

:在 Tkinter 中,PhotoImage 是一个用于在 Tkinter 控件中显示图像的类。当您创建一个 PhotoImage 对象时,它会占用一些内存来存储图像数据。如果您在循环中创建多个 PhotoImage 对象,并且循环会多次迭代,那么每次迭代都会创建一个新的对象,这将导致内存占用逐渐增加。为了避免这种情况,您可以创建一个全局的 PhotoImage 对象,并在循环中使用它。这样做的好处是,无论循环迭代多少次,都只会有一个 PhotoImage 对象在内存中。

2.8.定义播放视频的函数

javascript 复制代码
# 播放视频的函数
def play_video():
    global imgtk
    video_path = filedialog.askopenfilename(title='选择视频', filetypes=[('视频文件', '*.mp4')])
    if video_path:
        cap = cv2.VideoCapture(video_path)
        while cap.isOpened():
            ret, frame = cap.read()
            if ret:
                frame, faces = detect_faces(frame)
                display_frame(frame)
            else:
                break
        cap.release()
#在循环后释放视频文件资源

:这个函数允许用户选择一个视频文件,并播放该视频。在播放过程中,它将视频帧显示在窗口中,并使用人脸检测算法检测帧中的人脸。

2.9.在 Tkinter 窗口的画布上显示图像帧。

javascript 复制代码
#定义了一个函数 display_frame,它接受一个名为 frame 的参数,该参数是一个表示图像的 NumPy 数组。
def display_frame(frame):
    global imgtk
    if imgtk:
        canvas.delete(imgtk)
        imgtk = None
    frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
    img = Image.fromarray(frame)
    imgtk = ImageTk.PhotoImage(image=img)
#在画布上创建图像
    canvas.create_image(0, 0, anchor=tk.NW, image=imgtk)
#更新image属性
    canvas.image = imgtk
#更新窗口状态
    win.update_idletasks()
    win.update()

:这个函数负责将处理后的图像帧转换为 Tkinter 可以显示的格式,并在画布上显示这些帧。

2.10.让用户选择要查看的人脸图片,并在图像上显示这些图片

javascript 复制代码
def view_faces():
    directory = 'C:/Users/HUAWEI/Desktop/机器学习的人脸识别/机器学习的人脸识别/动态人脸识别/视频流人脸识别/保存图片'
    [os.path.join(directory, f) for f in os.listdir(directory) if f.endswith('.jpg')]
    face_paths = filedialog.askopenfilenames(title='查看人脸', initialdir=directory, filetypes=[('图片文件', '*.jpg')])
    if face_paths:
        for face_path in face_paths:
            img = cv2.imread(face_path)
            if img is not None:
                cv2.imshow('Face', img)
                cv2.waitKey(0)
                cv2.destroyAllWindows()
            else:
                print(f"无法加载图片: {face_path}")

:这行代码检查用户是否选择了图片文件。如果选择了,它将遍历用户选择的图片文件,并使用 cv2.imread() 函数尝试读取每个图片文件。如果成功读取,它将使用 cv2.imshow() 函数在窗口中显示图片,并使用 cv2.waitKey(0) 函数等待用户按键,然后使用 cv2.destroyAllWindows() 函数关闭所有打开的 OpenCV 窗口。如果无法加载图片,它会打印一个错误消息。

2.11.返回到主界面

javascript 复制代码
def return_to_system():
    subprocess.Popen(["python", "rlsb.py"])
    win.destroy()
#调用 win.destroy() 方法来关闭当前的 Tkinter 窗口。

:这个函数的作用是在当前 Tkinter 窗口中执行 rlsb.py 脚本,并在脚本执行完毕后关闭窗口。这通常用于将控制权返回到操作系统或另一个应用程序。

subprocess.Popen(["python", "rlsb.py"]):这行代码使用 subprocess.Popen() 函数启动一个新的进程,该进程将执行 rlsb.py 脚本。subprocess.Popen() 函数用于执行外部命令和程序,参数 ["python", "rlsb.py"] 指定使用 Python 解释器执行 rlsb.py 脚本。

2.12.创建按钮

javascript 复制代码
# 创建播放视频按钮,并放置在窗口的右侧
button1 = tk.Button(win, text="选择视频", command=play_video, width=10, height=2)
button1.place(x=150, y=500, width=100, height=50)


# 创建返回程序按钮,并放置在窗口的右侧
button2 = tk.Button(win, text="返回程序", command=return_to_system, width=10, height=2)
button2.place(x=400, y=500, width=100, height=50)

:这两行代码分别创建了两个按钮,并设置了它们的位置、大小和功能。当用户点击这些按钮时,会触发相应的函数执行。

2.13.更新窗口以确保按钮大小被计算

javascript 复制代码
# 更新窗口以确保按钮大小被计算
win.update_idletasks()

:这行代码的作用是更新 Tkinter 窗口,以确保按钮的大小被正确计算。在 Tkinter 中,按钮的大小是通过其 place 或 pack 方法设置的,但这些方法并不会立即更新按钮的实际大小。update_idletasks() 方法用于在布局管理器(如 pack 或 grid)计算所有控件的最终位置和大小后更新窗口。

2.14.事件循环

javascript 复制代码
# 进入Tkinter事件循环
win.mainloop()

:这行代码确保了 Tkinter 窗口和所有绑定的事件处理函数能够正常工作,并且用户可以与应用程序进行交互。它是 Tkinter 应用程序中不可或缺的一部分。
运行结果

相关推荐
幽络源小助理3 分钟前
Python使用requests_html库爬取掌阅书籍(附完整源码及使用说明)
python·html·python爬虫·爬虫教程·requests_html·爬取书籍·掌阅
取个名字真难呐4 分钟前
LossMaskMatrix损失函数掩码矩阵
python·深度学习·矩阵
南宫理的日知录6 分钟前
「Python数据科学」标量、向量、矩阵、张量与多维数组的辨析
python·numpy·数据科学
soulteary8 分钟前
使用 AI 辅助开发一个开源 IP 信息查询工具:一
人工智能·tcp/ip·开源·ip 查询
爱补鱼的猫猫13 分钟前
2、Bert论文笔记
论文阅读·人工智能·bert
GZ同学23 分钟前
Arcgis中python工具箱制造要点及统计要素图层字段信息工具分享
python·arcgis
Kenneth風车43 分钟前
【机器学习(九)】分类和回归任务-多层感知机(Multilayer Perceptron,MLP)算法-Sentosa_DSML社区版 (1)111
算法·机器学习·分类
盼小辉丶1 小时前
TensorFlow深度学习实战(2)——使用TensorFlow构建神经网络
深度学习·神经网络·tensorflow
起名字什么的好难1 小时前
conda虚拟环境安装pytorch gpu版
人工智能·pytorch·conda
18号房客1 小时前
计算机视觉-人工智能(AI)入门教程一
人工智能·深度学习·opencv·机器学习·计算机视觉·数据挖掘·语音识别