# -*- coding: utf-8 -*-
# 基于残差神经网络的人脸识别系统 - 现代界面版本
# @Time : 2023/12/25
# @Author : std-ie
# @Software: PyCharm
import csv
import glob
import os
import re
import shutil
import time
import warnings
from os import getcwd
import datetime
import cv2
import dlib
import numpy as np
import pandas as pd
from PIL import Image, ImageDraw, ImageFont
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtGui import QMovie
from PyQt5.QtWidgets import QFileDialog, QTableWidgetItem, QAbstractItemView, QStackedWidget
from PyQt5.QtCore import Qt, QTimer
from management_system import Ui_MainWindow
# 忽略警告
os.environ["TF_CPP_MIN_LOG_LEVEL"] = "3"
warnings.filterwarnings(action='ignore')
class ModernFaceMainWindow(Ui_MainWindow):
def __init__(self, MainWindow):
# 初始化路径和字体
self.path_face_dir = "../data/database_faces/"
self.fontC = ImageFont.truetype("./Font/platech.ttf", 14, 0)
self.cap_video = None # 视频流对象
self.path = getcwd()
self.video_path = getcwd()
self.timer_camera = QtCore.QTimer() # 定时器
self.timer_camera_load = QtCore.QTimer() # 载入相机定时器
self.timer_video = QtCore.QTimer() # 视频定时器
self.flag_timer = "" # 用于标记正在进行的功能项(视频/摄像)
self.CAM_NUM = 0 # 摄像头标号
# self.CAM_NUM1 = 0
self.cap = cv2.VideoCapture(self.CAM_NUM, cv2.CAP_DSHOW) # 屏幕画面对象
self.cap_video = None # 视频流对象
self.current_image = None # 当前的画面
self.current_face = None # 当前的人脸
self.setupUi(MainWindow) # 界面生成
self.init_ui() # 初始化界面
self.init_slots() # 初始化槽函数连接 # 槽函数
self.count = 0
self.count_face = 0
self.col_row = []
# Dlib 正向人脸检测器
self.detector = dlib.get_frontal_face_detector()
self.predictor = dlib.shape_predictor('../data/data_dlib/shape_predictor_68_face_landmarks.dat')
self.face_reco_model = dlib.face_recognition_model_v1("../data/data_dlib"
"/dlib_face_recognition_resnet_model_v1.dat")
self.face_feature_exist = [] # 用来存放所有录入人脸特征的数组
self.face_name_exist = [] # 存储录入人脸名字
# 用来存储上一帧和当前帧 ROI 的质心坐标
self.last_centroid = []
self.current_centroid = []
# 用来存储上一帧和当前帧检测出目标的名字
self.last_face_name = []
self.current_face_name = []
# 上一帧和当前帧中人脸数的计数器
self.last_face_cnt = 0
self.current_face_cnt = 0
# 存储当前摄像头中捕获到的所有人脸的坐标名字
self.current_face_position = []
# 存储当前摄像头中捕获到的人脸特征
self.current_face_feature = []
self.reclassify_cnt = 0
self.reclassify_interval = 20
# 前后帧的距离
self.last_current_distance = 0
# 用来存放识别的距离
self.current_face_distance = []
self.exist_flag = None
def init_ui(self):
"""初始化界面设置"""
# 设置初始页面为首页
self.stackedWidget.setCurrentIndex(0)
# 设置菜单按钮组
self.menu_buttons = [
self.btn_faceRecognition,
self.btn_faceRegistration,
self.btn_faceManagement
]
# 创建其他页面并添加到堆栈窗口
self.create_recognition_page()
self.create_face_input_page()
self.create_face_manage_page()
def init_slots(self):
"""初始化信号槽连接"""
# 菜单按钮点击事件
self.timer_video.timeout.connect(self.show_video)
self.timer_camera.timeout.connect(self.show_camera)
self.timer_camera_load.timeout.connect(self.show_camera_load)
self.btn_faceRecognition.clicked.connect(lambda: self.switch_page(0, "人脸识别"))
self.btn_faceRegistration.clicked.connect(lambda: self.switch_page(1, "人脸录入"))
self.btn_faceManagement.clicked.connect(lambda: self.switch_page(2, "人脸管理"))
# 定时器连接
def switch_page(self, index, title):
"""切换页面并更新标题"""
# 更新页面标题
# 切换到对应页面
self.stackedWidget.setCurrentIndex(index)
# 更新菜单按钮选中状态
for i, btn in enumerate(self.menu_buttons):
print(i)
btn.setChecked(i == index)
if index == 0:
self.button_open_camera_click()
self.run_rec()
def create_recognition_page(self):
"""创建人脸识别页面"""
# 创建人脸识别页面
self.page_faceRecognition = QtWidgets.QWidget()
self.page_faceRecognition.setObjectName("recognitionPage")
# 创建布局
layout = QtWidgets.QVBoxLayout(self.page_faceRecognition)
# 创建人脸识别容器
self.recognitionContainer = QtWidgets.QFrame(self.page_faceRecognition)
self.recognitionContainer.setObjectName("recognitionContainer")
self.recognitionContainer.setFrameShape(QtWidgets.QFrame.StyledPanel)
self.recognitionContainer.setFrameShadow(QtWidgets.QFrame.Raised)
# 创建人脸识别容器的布局
recLayout = QtWidgets.QVBoxLayout(self.recognitionContainer)
# 创建标题标签
titleLabel = QtWidgets.QLabel("人脸识别")
titleLabel.setObjectName("sectionTitle")
font = QtGui.QFont()
font.setPointSize(12)
font.setBold(True)
titleLabel.setFont(font)
recLayout.addWidget(titleLabel)
# 创建显示区域
displayContainer = QtWidgets.QWidget()
displayLayout = QtWidgets.QHBoxLayout(displayContainer)
# 视频显示区域
self.videoDisplay = QtWidgets.QLabel()
self.videoDisplay.setMinimumSize(QtCore.QSize(640, 480))
self.videoDisplay.setAlignment(QtCore.Qt.AlignCenter)
self.videoDisplay.setStyleSheet(" border: 1px solid #ddd;")
self.videoDisplay.setText("等待视频输入...")
# 结果显示区域
resultContainer = QtWidgets.QWidget()
resultLayout = QtWidgets.QVBoxLayout(resultContainer)
# 人脸图像显示
self.faceDisplay = QtWidgets.QLabel()
self.faceDisplay.setMinimumSize(QtCore.QSize(150, 150))
self.faceDisplay.setMaximumSize(QtCore.QSize(150, 150))
self.faceDisplay.setAlignment(QtCore.Qt.AlignCenter)
self.faceDisplay.setStyleSheet(" border: 1px solid #ddd;")
# 识别结果显示
self.resultNameLabel = QtWidgets.QLabel("姓名:未知")
self.resultConfidenceLabel = QtWidgets.QLabel("置信度:0%")
self.resultTimeLabel = QtWidgets.QLabel("识别时间:--")
resultLayout.addWidget(self.faceDisplay)
resultLayout.addWidget(self.resultNameLabel)
resultLayout.addWidget(self.resultConfidenceLabel)
resultLayout.addWidget(self.resultTimeLabel)
resultLayout.addStretch()
displayLayout.addWidget(self.videoDisplay, 4)
displayLayout.addWidget(resultContainer, 1)
recLayout.addWidget(displayContainer)
# 添加识别记录表格
self.recognitionTable = QtWidgets.QTableWidget()
self.recognitionTable.setAlternatingRowColors(True)
self.recognitionTable.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
self.recognitionTable.setColumnCount(5)
self.recognitionTable.setHorizontalHeaderLabels(["序号", "时间", "姓名", "置信度", "状态"])
self.recognitionTable.horizontalHeader().setStretchLastSection(True)
self.recognitionTable.setColumnWidth(0, 80)
self.recognitionTable.setColumnWidth(1, 150)
self.recognitionTable.setColumnWidth(2, 150)
self.recognitionTable.setColumnWidth(3, 100)
recLayout.addWidget(self.recognitionTable)
# 添加到主布局
layout.addWidget(self.recognitionContainer)
# 添加到堆栈窗口
self.stackedWidget.addWidget(self.page_faceRecognition)
# 连接按钮信号
def create_face_input_page(self):
"""创建人脸录入页面"""
# 创建人脸录入页面
self.page_faceRegistration = QtWidgets.QWidget()
self.page_faceRegistration.setObjectName("faceInputPage")
# 创建布局
layout = QtWidgets.QVBoxLayout(self.page_faceRegistration)
# 创建人脸录入容器
self.faceInputContainer = QtWidgets.QFrame(self.page_faceRegistration)
self.faceInputContainer.setObjectName("faceInputContainer")
self.faceInputContainer.setFrameShape(QtWidgets.QFrame.StyledPanel)
self.faceInputContainer.setFrameShadow(QtWidgets.QFrame.Raised)
# 创建人脸录入容器的布局
inputLayout = QtWidgets.QVBoxLayout(self.faceInputContainer)
# 创建标题标签
titleLabel = QtWidgets.QLabel("人脸录入")
titleLabel.setObjectName("sectionTitle")
font = QtGui.QFont()
font.setPointSize(12)
font.setBold(True)
titleLabel.setFont(font)
inputLayout.addWidget(titleLabel)
# 创建输入表单
formContainer = QtWidgets.QWidget()
formLayout = QtWidgets.QFormLayout(formContainer)
formLayout.setLabelAlignment(QtCore.Qt.AlignRight)
# 姓名输入
self.inputName = QtWidgets.QLineEdit()
self.inputName.setPlaceholderText("请输入姓名")
formLayout.addRow("姓名:", self.inputName)
# ID输入
self.inputID = QtWidgets.QLineEdit()
self.inputID.setPlaceholderText("请输入ID")
formLayout.addRow("ID:", self.inputID)
# 部门输入
self.inputDepartment = QtWidgets.QLineEdit()
self.inputDepartment.setPlaceholderText("请输入部门")
formLayout.addRow("部门:", self.inputDepartment)
inputLayout.addWidget(formContainer)
# 创建控制按钮容器
controlsContainer = QtWidgets.QWidget()
controlsLayout = QtWidgets.QHBoxLayout(controlsContainer)
# 添加控制按钮
self.btnInputCamera = QtWidgets.QPushButton("打开摄像头")
self.btnInputCamera.setIcon(QtGui.QIcon(":/newPrefix/images_test/camera.png"))
self.btnInputFile = QtWidgets.QPushButton("选择图片")
self.btnInputFile.setIcon(QtGui.QIcon(":/newPrefix/images_test/image.png"))
self.btnCapture = QtWidgets.QPushButton("拍摄照片")
self.btnCapture.setIcon(QtGui.QIcon(":/newPrefix/images_test/capture.png"))
self.btnCapture.setEnabled(False)
self.btnSaveFace = QtWidgets.QPushButton("保存人脸")
self.btnSaveFace.setIcon(QtGui.QIcon(":/newPrefix/images_test/save.png"))
self.btnSaveFace.setEnabled(False)
controlsLayout.addWidget(self.btnInputCamera)
controlsLayout.addWidget(self.btnInputFile)
controlsLayout.addWidget(self.btnCapture)
controlsLayout.addWidget(self.btnSaveFace)
inputLayout.addWidget(controlsContainer)
# 创建显示区域
displayContainer = QtWidgets.QWidget()
displayLayout = QtWidgets.QHBoxLayout(displayContainer)
# 视频显示区域
self.inputVideoDisplay = QtWidgets.QLabel()
self.inputVideoDisplay.setMinimumSize(QtCore.QSize(640, 480))
self.inputVideoDisplay.setAlignment(QtCore.Qt.AlignCenter)
self.inputVideoDisplay.setStyleSheet(" border: 1px solid #ddd;")
self.inputVideoDisplay.setText("等待视频输入...")
# 人脸显示区域
self.inputFaceDisplay = QtWidgets.QLabel()
self.inputFaceDisplay.setMinimumSize(QtCore.QSize(150, 150))
self.inputFaceDisplay.setMaximumSize(QtCore.QSize(150, 150))
self.inputFaceDisplay.setAlignment(QtCore.Qt.AlignCenter)
self.inputFaceDisplay.setStyleSheet(" border: 1px solid #ddd;")
self.inputFaceDisplay.setText("人脸预览")
displayLayout.addWidget(self.inputVideoDisplay, 4)
displayLayout.addWidget(self.inputFaceDisplay, 1)
inputLayout.addWidget(displayContainer)
# 添加到主布局
layout.addWidget(self.faceInputContainer)
# 添加到堆栈窗口
self.stackedWidget.addWidget(self.page_faceRegistration)
def create_face_manage_page(self):
"""创建人脸管理页面"""
# 创建人脸管理页面
self.page_faceManagement = QtWidgets.QWidget()
self.page_faceManagement.setObjectName("faceManagePage")
# 创建布局
layout = QtWidgets.QVBoxLayout(self.page_faceManagement)
# 创建人脸管理容器
self.faceManageContainer = QtWidgets.QFrame(self.page_faceManagement)
self.faceManageContainer.setObjectName("faceManageContainer")
self.faceManageContainer.setFrameShape(QtWidgets.QFrame.StyledPanel)
self.faceManageContainer.setFrameShadow(QtWidgets.QFrame.Raised)
# 创建人脸管理容器的布局
manageLayout = QtWidgets.QVBoxLayout(self.faceManageContainer)
# 创建标题标签
titleLabel = QtWidgets.QLabel("人脸管理")
titleLabel.setObjectName("sectionTitle")
font = QtGui.QFont()
font.setPointSize(12)
font.setBold(True)
titleLabel.setFont(font)
manageLayout.addWidget(titleLabel)
# 创建统计信息
statsContainer = QtWidgets.QWidget()
statsLayout = QtWidgets.QHBoxLayout(statsContainer)
self.faceCountLabel = QtWidgets.QLabel("已存人脸:0")
self.faceCountLabel.setStyleSheet("font-weight: bold; color: #0055ff;")
statsLayout.addWidget(self.faceCountLabel)
statsLayout.addStretch()
manageLayout.addWidget(statsContainer)
# 创建控制按钮容器
controlsContainer = QtWidgets.QWidget()
controlsLayout = QtWidgets.QHBoxLayout(controlsContainer)
# 添加控制按钮
self.btnRefreshFaces = QtWidgets.QPushButton("刷新列表")
self.btnRefreshFaces.setIcon(QtGui.QIcon(":/newPrefix/images_test/refresh.png"))
self.btnDeleteFace = QtWidgets.QPushButton("删除选中")
self.btnDeleteFace.setIcon(QtGui.QIcon(":/newPrefix/images_test/delete.png"))
self.btnExportFaces = QtWidgets.QPushButton("导出数据")
self.btnExportFaces.setIcon(QtGui.QIcon(":/newPrefix/images_test/export.png"))
controlsLayout.addWidget(self.btnRefreshFaces)
controlsLayout.addWidget(self.btnDeleteFace)
controlsLayout.addWidget(self.btnExportFaces)
controlsLayout.addStretch()
manageLayout.addWidget(controlsContainer)
# 创建显示区域
displayContainer = QtWidgets.QWidget()
displayLayout = QtWidgets.QHBoxLayout(displayContainer)
# 人脸列表表格
self.faceListTable = QtWidgets.QTableWidget()
self.faceListTable.setAlternatingRowColors(True)
self.faceListTable.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
self.faceListTable.setColumnCount(4)
self.faceListTable.setHorizontalHeaderLabels(["序号", "姓名", "ID", "部门"])
self.faceListTable.horizontalHeader().setStretchLastSection(True)
self.faceListTable.setColumnWidth(0, 80)
self.faceListTable.setColumnWidth(1, 150)
self.faceListTable.setColumnWidth(2, 150)
# 选中人脸显示
self.selectedFaceDisplay = QtWidgets.QLabel()
self.selectedFaceDisplay.setMinimumSize(QtCore.QSize(150, 150))
self.selectedFaceDisplay.setMaximumSize(QtCore.QSize(150, 150))
self.selectedFaceDisplay.setAlignment(QtCore.Qt.AlignCenter)
self.selectedFaceDisplay.setStyleSheet(" border: 1px solid #ddd;")
self.selectedFaceDisplay.setText("选中人脸")
displayLayout.addWidget(self.faceListTable, 4)
displayLayout.addWidget(self.selectedFaceDisplay, 1)
manageLayout.addWidget(displayContainer)
# 添加到主布局
layout.addWidget(self.faceManageContainer)
# 添加到堆栈窗口
self.stackedWidget.addWidget(self.page_faceManagement)
def ini_value(self):
self.face_feature_exist = [] # 用来存放所有录入人脸特征的数组
self.face_name_exist = [] # 存储录入人脸名字
# 用来存储上一帧和当前帧 ROI 的质心坐标
self.last_centroid = []
self.current_centroid = []
# 用来存储上一帧和当前帧检测出目标的名字
self.last_face_name = []
self.current_face_name = []
# 上一帧和当前帧中人脸数的计数器
self.last_face_cnt = 0
self.current_face_cnt = 0
# 存储当前摄像头中捕获到的所有人脸的坐标名字
self.current_face_position = []
# 存储当前摄像头中捕获到的人脸特征
self.current_face_feature = []
self.reclassify_cnt = 0
self.reclassify_interval = 20
# 前后帧的距离
self.last_current_distance = 0
# 用来存放识别的距离
self.current_face_distance = []
def button_open_camera_click(self):
# self.count = 0
# self.res_set = []
if self.timer_video.isActive():
self.timer_video.stop()
self.flag_timer = ""
if self.cap:
self.cap.release()
if self.cap_video:
self.cap_video.release() # 释放视频画面帧
self.ini_value()
if not self.timer_camera.isActive(): # 检查定时状态
flag = self.cap.open(self.CAM_NUM) # 检查相机状态
if not flag: # 相机打开失败提示
QtWidgets.QMessageBox.warning(self.centralwidget, u"Warning",
u"请检测相机与电脑是否连接正确! ",
buttons=QtWidgets.QMessageBox.Ok,
defaultButton=QtWidgets.QMessageBox.Ok)
self.flag_timer = ""
else:
print("相机已加载就绪")
# 准备运行识别程序
self.flag_timer = "camera"
# 清除文本框的显示内容
# self.label_display.setText('正在启动识别系统...\n\nleading')
QtWidgets.QApplication.processEvents()
# 清除UI上的label显示
# self.label_plate_result.setText("未知人脸")
# self.label_score_fps.setText("0")
# self.label_score_num.setText("0")
# self.label_score_dis.setText("0")
else:
print("定时器未开启")
# 定时器未开启,界面回复初始状态
def run_rec(self):
# 点击开始运行按钮执行函数
if self.flag_timer == "image":
# self.do_choose_file()
print("00")
elif self.flag_timer == "video":
print("001")
if not self.timer_video.isActive():
# self.count = 0
# self.tableWidget.clearContents()
# 打开定时器
# self.exist_flag = self.get_face_database()
self.timer_video.start(30)
else:
self.timer_video.stop()
elif self.flag_timer == "camera":
if not self.timer_camera.isActive():
# self.count = 0
# self.tableWidget.clearContents()
QtWidgets.QApplication.processEvents()
self.exist_flag = self.get_face_database() # 获取已存在人脸的特征
self.timer_camera.start(30)
else:
self.timer_camera.stop()
self.flag_timer = ""
if self.cap:
self.cap.release()
# self.textEdit_camera.setText("实时摄像已关闭")
# self.textEdit_camera.setStyleSheet("\n"
# "border-color: rgb(0, 170, 255);\n"
# "color: rgb(0, 170, 255);\n"
# "font: regular 12pt \"华为仿宋\";")
QtWidgets.QApplication.processEvents()
else:
print("003")
# self.textEdit_file.setText('图片文件未选中')
# self.textEdit_file.setStyleSheet("\n"
# "border-color: rgb(0, 170, 255);\n"
# "color: rgb(0, 170, 255);\n"
# "font: regular 12pt \"华为仿宋\";")
# self.textEdit_camera.setText("实时摄像已关闭")
# self.textEdit_camera.setStyleSheet("\n"
# "border-color: rgb(0, 170, 255);\n"
# "color: rgb(0, 170, 255);\n"
# "font: regular 12pt \"华为仿宋\";")
# # self.textEdit_model
# self.textEdit_video.setText('实时视频已关闭')
# self.textEdit_video.setStyleSheet("\n"
# "border-color: rgb(0, 170, 255);\n"
# "color: rgb(0, 170, 255);\n"
# "font: regular 12pt \"华为仿宋\";")
self.label_facePreview.clear()
# self.label_display.setStyleSheet("border-image: url(:/newPrefix/images_test/ini-image.png);")
# self.label_pic_newface.clear()
# self.count = 0
# self.tableWidget.clearContents()
# 清除UI上的label显示
# self.label_plate_result.setText("未知人脸")
# self.label_score_fps.setText("0")
# self.label_score_num.setText("0")
# self.label_score_dis.setText("0")
def get_face_database(self):
self.face_feature_exist = []
self.face_name_exist = []
if os.path.exists("../data/features.csv"):
path_features_known_csv = "../data/features.csv"
csv_rd = pd.read_csv(path_features_known_csv, header=None, encoding='gb2312')
for i in range(csv_rd.shape[0]):
features_someone_arr = []
for j in range(1, 129):
if csv_rd.iloc[i][j] == '':
features_someone_arr.append('0')
else:
features_someone_arr.append(csv_rd.iloc[i][j])
self.face_feature_exist.append(features_someone_arr)
if csv_rd.iloc[i][0] == '':
self.face_name_exist.append("未知人脸")
else:
self.face_name_exist.append(csv_rd.iloc[i][0])
return 1
else:
return 0
def show_video(self):
# 视频定时器槽函数,每隔一段时间执行该函数
start_time = time.time()
flag, img_rd = self.cap_video.read() # 获取画面
if flag:
# image = cv2.flip(image, 1) # 左右翻转
image = img_rd.copy()
# 2. 检测人脸 / Detect faces for frame X
faces = self.detector(img_rd, 0)
# self.label_score_num.setText(str(len(faces)))
# Update cnt for faces in frames
self.last_face_cnt = self.current_face_cnt
self.current_face_cnt = len(faces)
# Update the face name list in last frame
self.last_face_name = self.current_face_name[:]
# update frame centroid list
self.last_centroid = self.current_centroid
self.current_centroid = []
# 2.1. if cnt not changes
if (self.current_face_cnt == self.last_face_cnt) and (
self.reclassify_cnt != self.reclassify_interval):
self.disp_img(image)
self.current_face_position = []
if "未知人脸" in self.current_face_name:
self.reclassify_cnt += 1
if self.current_face_cnt != 0:
# 2.1.1 Get ROI positions
for k, d in enumerate(faces):
self.current_face_position.append(tuple(
[faces[k].left(), int(faces[k].bottom() + (faces[k].bottom() - faces[k].top()) / 4)]))
self.current_centroid.append(
[int(faces[k].left() + faces[k].right()) / 2,
int(faces[k].top() + faces[k].bottom()) / 2])
# 计算矩形框大小 / Compute the size of rectangle box
# height = (d.bottom() - d.top())
# width = (d.right() - d.left())
# hh = int(height / 2)
# ww = int(width / 2)
# y2 = d.right() + ww
# x2 = d.bottom() + hh
# y1 = d.left() - ww
# x1 = d.top() - hh
y2 = d.right()
x2 = d.bottom()
y1 = d.left()
x1 = d.top()
# 判断人脸区域是否超出画面范围
if y2 > img_rd.shape[1]:
y2 = img_rd.shape[1]
elif x2 > img_rd.shape[0]:
x2 = img_rd.shape[0]
elif y1 < 0:
y1 = 0
elif x1 < 0:
x1 = 0
# 剪切出人脸
crop_face = img_rd[x1: x2, y1: y2]
self.current_face = crop_face
self.disp_face(crop_face) # 在右侧label中显示检测出的人脸
rect = (d.left(), d.top(), d.right(), d.bottom())
name_lab = self.current_face_name[k] if self.current_face_name is not None else ""
image = self.drawRectBox(image, rect, name_lab)
# self.label_plate_result.setText(name_lab)
self.disp_img(image) # 在画面中显示图像
# Multi-faces in current frame, use centroid-tracker to track
if self.current_face_cnt != 1:
self.centroid_tracker()
# 2.2 If cnt of faces changes, 0->1 or 1->0 or ...
else:
self.current_face_position = []
self.current_face_distance = []
self.current_face_feature = []
self.reclassify_cnt = 0
# 2.2.1 Face cnt decreases: 1->0, 2->1, ...
if self.current_face_cnt == 0:
# clear list of names and features
self.current_face_name = []
# 2.2.2 Face cnt increase: 0->1, 0->2, ..., 1->2, ...
else:
self.current_face_name = []
for i in range(len(faces)):
shape = self.predictor(img_rd, faces[i])
self.current_face_feature.append(
self.face_reco_model.compute_face_descriptor(img_rd, shape))
self.current_face_name.append("未知人脸")
# 2.2.2.1 遍历捕获到的图像中所有的人脸 / Traversal all the faces in the database
for k in range(len(faces)):
self.current_centroid.append(
[int(faces[k].left() + faces[k].right()) / 2,
int(faces[k].top() + faces[k].bottom()) / 2])
self.current_face_distance = []
# 2.2.2.2 每个捕获人脸的名字坐标 / Positions of faces captured
self.current_face_position.append(tuple(
[faces[k].left(), int(faces[k].bottom() + (faces[k].bottom() - faces[k].top()) / 4)]))
# 2.2.2.3 对于某张人脸,遍历所有存储的人脸特征
# For every faces detected, compare the faces in the database
for i in range(len(self.face_feature_exist)):
# 如果 q 数据不为空
if str(self.face_feature_exist[i][0]) != '0.0':
e_distance_tmp = self.euclidean_distance(
self.current_face_feature[k],
self.face_feature_exist[i])
self.current_face_distance.append(e_distance_tmp)
else:
# 空数据 person_X
self.current_face_distance.append(999999999)
# 2.2.2.4 寻找出最小的欧式距离匹配 / Find the one with minimum e distance
min_dis = min(self.current_face_distance)
similar_person_num = self.current_face_distance.index(min_dis)
if min_dis < 0.4:
self.current_face_name[k] = self.face_name_exist[similar_person_num]
self.label_score_dis.setText(str(round(100/(1+min_dis), 2))+'%')
# 将识别记录到表格中
date_now = datetime.datetime.now().strftime('%m-%d_%H:%M:%S')
self.change_table(date_now + "_" + str(self.count), self.current_face_name[k], date_now,
1/(1+min_dis))
end_time = time.time()
if end_time - start_time == 0:
use_time = 1
else:
use_time = end_time - start_time
fps_rec = int(1.0 / round(use_time, 3))
self.label_score_fps.setText(str(fps_rec))
def show_camera(self):
# 定时器槽函数,每隔一段时间执行
start_time = time.time()
flag, img_rd = self.cap.read() # 获取画面
# left_img = img_rd[:, 640:1280, :]
if flag:
# image = cv2.flip(image, 1) # 左右翻转
image = img_rd.copy()
# 2. 检测人脸 / Detect faces for frame X
faces = self.detector(img_rd, 0)
# self.label_score_num.setText(str(len(faces)))
# Update cnt for faces in frames
self.last_face_cnt = self.current_face_cnt
self.current_face_cnt = len(faces)
# Update the face name list in last frame
self.last_face_name = self.current_face_name[:]
# update frame centroid list
self.last_centroid = self.current_centroid
self.current_centroid = []
# 2.1. if cnt not changes
if (self.current_face_cnt == self.last_face_cnt) and (
self.reclassify_cnt != self.reclassify_interval):
print("0")
# self.disp_img(image) # 在画面中显示图像
# self.label_facePreview.update() # 强制更新界面
self.current_face_position = []
if "未知人脸" in self.current_face_name:
self.reclassify_cnt += 1
if self.current_face_cnt != 0:
# 2.1.1 Get ROI positions
for k, d in enumerate(faces):
self.current_face_position.append(tuple(
[faces[k].left(), int(faces[k].bottom() + (faces[k].bottom() - faces[k].top()) / 4)]))
self.current_centroid.append(
[int(faces[k].left() + faces[k].right()) / 2,
int(faces[k].top() + faces[k].bottom()) / 2])
# 计算矩形框大小 / Compute the size of rectangle box
y2 = d.right()
x2 = d.bottom()
y1 = d.left()
x1 = d.top()
# 判断人脸区域是否超出画面范围
if y2 > img_rd.shape[1]:
y2 = img_rd.shape[1]
elif x2 > img_rd.shape[0]:
x2 = img_rd.shape[0]
elif y1 < 0:
y1 = 0
elif x1 < 0:
x1 = 0
# 剪切出人脸
crop_face = img_rd[x1: x2, y1: y2]
self.current_face = crop_face
self.disp_face(crop_face) # 在右侧label中显示检测出的人脸
rect = (d.left(), d.top(), d.right(), d.bottom())
name_lab = self.current_face_name[k] if self.current_face_name != [] else "位置人脸"
image = self.drawRectBox(image, rect, name_lab)
# self.label_recognitionResult.setText(name_lab)
#
self.disp_img(image)
#
# # Multi-faces in current frame, use centroid-tracker to track
if self.current_face_cnt != 1:
self.centroid_tracker()
# 2.2 If cnt of faces changes, 0->1 or 1->0 or ...
else:
print("10")
self.current_face_position = []
self.current_face_distance = []
self.current_face_feature = []
self.reclassify_cnt = 0
#
# # 2.2.1 Face cnt decreases: 1->0, 2->1, ...
if self.current_face_cnt == 0:
# clear list of names and features
self.current_face_name = []
# # 2.2.2 Face cnt increase: 0->1, 0->2, ..., 1->2, ...
else:
self.current_face_name = []
for i in range(len(faces)):
shape = self.predictor(img_rd, faces[i])
self.current_face_feature.append(
self.face_reco_model.compute_face_descriptor(img_rd, shape))
self.current_face_name.append("未知人脸")
# # 2.2.2.1 遍历捕获到的图像中所有的人脸 / Traversal all the faces in the database
for k in range(len(faces)):
self.current_centroid.append(
[int(faces[k].left() + faces[k].right()) / 2,
int(faces[k].top() + faces[k].bottom()) / 2])
self.current_face_distance = []
# 2.2.2.2 每个捕获人脸的名字坐标 / Positions of faces captured
self.current_face_position.append(tuple(
[faces[k].left(), int(faces[k].bottom() + (faces[k].bottom() - faces[k].top()) / 4)]))
#
# # 2.2.2.3 对于某张人脸,遍历所有存储的人脸特征
# # For every faces detected, compare the faces in the database
for i in range(len(self.face_feature_exist)):
# 如果 q 数据不为空
if str(self.face_feature_exist[i][0]) != '0.0':
print("8888888")
print(self.current_face_feature[k])
print(self.face_feature_exist[i])
e_distance_tmp = self.euclidean_distance(
self.current_face_feature[k],
self.face_feature_exist[i])
self.current_face_distance.append(e_distance_tmp)
# print(e_distance_tmp+"999999999999999999999")
else:
# print("8888888")
# 空数据 person_X
self.current_face_distance.append(99999999)
#
# # 2.2.2.4 寻找出最小的欧式距离匹配 / Find the one with minimum e distance
min_dis = min(self.current_face_distance)
similar_person_num = self.current_face_distance.index(min_dis)
if min_dis < 0.4:
self.current_face_name[k] = self.face_name_exist[similar_person_num]
# self.label_score_dis.setText(str(round(100/(1+min_dis), 2))+'%')
date_now = datetime.datetime.now().strftime('%m-%d_%H:%M:%S')
# self.change_table(date_now + "_" + str(self.count), self.current_face_name[k], date_now,
# 1/(1+min_dis))
end_time = time.time()
if end_time == start_time:
use_time = 1
else:
use_time = end_time - start_time
fps_rec = int(1.0 / round(use_time, 3))
# self.label_score_fps.setText(str(fps_rec))
def disp_face(self, image):
self.label_recognitionResult.clear()
if image.any():
image = cv2.resize(image, (200, 200)) # 设定图像尺寸为显示界面大小
show = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
showImage = QtGui.QImage(show.data, show.shape[1], show.shape[0], QtGui.QImage.Format_RGB888)
a = QtGui.QPixmap.fromImage(showImage)
self.label_recognitionResult.setPixmap(a)
self.label_recognitionResult.setScaledContents(True)
QtWidgets.QApplication.processEvents()
def disp_img(self, image):
# self.label_display.clear()
image = cv2.resize(image, (500, 500)) # 设定图像尺寸为显示界面大小
show = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
showImage = QtGui.QImage(show.data, show.shape[1], show.shape[0], QtGui.QImage.Format_RGB888)
a = QtGui.QPixmap.fromImage(showImage)
self.label_facePreview.setPixmap(a)
self.label_facePreview.setScaledContents(True)
QtWidgets.QApplication.processEvents()
def drawRectBox(self, image, rect, addText):
cv2.rectangle(image, (int(round(rect[0])), int(round(rect[1]))),
(int(round(rect[2])), int(round(rect[3]))),
(0, 0, 255), 2)
cv2.rectangle(image, (int(rect[0] - 1), int(rect[1]) - 16), (int(rect[0] + 75), int(rect[1])), (0, 0, 255), -1,
cv2.LINE_AA)
img = Image.fromarray(image)
draw = ImageDraw.Draw(img)
draw.text((int(rect[0] + 1), int(rect[1] - 16)), addText, (255, 255, 255), font=self.fontC)
imagex = np.array(img)
return imagex
def show_camera_load(self):
# 定时器槽函数,每隔一段时间执行
#self.cap = cv2.VideoCapture(self.CAM_NUM, cv2.CAP_DSHOW)
flag, img_rd = self.cap.read() # 获取画面
#left_img =img_rd[:, 640:1280, :]
if flag:
start_time = time.time() # 计时
self.current_image = img_rd.copy()
image = img_rd.copy()
face_name = self.lineEdit_face_name.text()
# 使用人脸检测器进行人脸检测
faces = self.detector(image, 0)
self.label_score_num.setText(str(len(faces)))
if len(faces) != 0:
# 矩形框 / Show the ROI of faces
for k, d in enumerate(faces):
# 计算矩形框大小 / Compute the size of rectangle box
height = (d.bottom() - d.top())
width = (d.right() - d.left())
hh = int(height / 2)
ww = int(width / 2)
rect = (d.left() - ww, d.top() - hh, d.right() + ww, d.bottom() + hh)
image = self.drawRectBox(image, rect, "正在录入")
y2 = d.right() + ww
x2 = d.bottom() + hh
y1 = d.left() - ww
x1 = d.top() - hh
# 判断人脸区域是否超出画面范围
if y2 > img_rd.shape[1]:
y2 = img_rd.shape[1]
elif x2 > img_rd.shape[0]:
x2 = img_rd.shape[0]
elif y1 < 0:
y1 = 0
elif x1 < 0:
x1 = 0
# 剪切出人脸
crop_face = img_rd[x1: x2, y1: y2]
self.current_face = crop_face
self.disp_face(crop_face)
if self.current_face.any() and face_name != "请在此输入人脸名" and face_name != "":
# self.label_loadface.setText("检测到人脸区域,可点击取图按钮以保存!")
self.toolButton_get_pic.setEnabled(True) # 存在人脸时可以取图
else:
self.toolButton_get_pic.setEnabled(False) # 不存在人脸时不可取图
self.disp_img(image) # 在画面中显示图像
end_time = time.time()
if end_time == start_time:
use_time = 1
else:
use_time = end_time - start_time
fps_rec = int(1.0 / round(use_time, 3))
self.label_score_fps.setText(str(fps_rec)) # 更新帧率
self.label_plate_result.setText("正在录入")
self.label_score_dis.setText("None")
def centroid_tracker(self):
for i in range(len(self.current_centroid)):
distance_current_person = []
# 计算不同对象间的距离
for j in range(len(self.last_centroid)):
self.last_current_distance = self.euclidean_distance(
self.current_centroid[i], self.last_centroid[j])
distance_current_person.append(
self.last_current_distance)
last_frame_num = distance_current_person.index(
min(distance_current_person))
self.current_face_name[i] = self.last_face_name[last_frame_num]
@staticmethod
def euclidean_distance(feature_1, feature_2):
# 计算两个128D向量间的欧式距离
feature_1 = np.array(feature_1)
feature_2 = np.array(feature_2)
dist = np.sqrt(np.sum(np.square(feature_1 - feature_2)))
return dist
关于qt页面的的控件问题,和其他的视频显示问题