1.增加人脸识别模块
2.人脸识别整定优化,分离串口配置 3.改为使用原有uart_group_config.py文件实现配置连接,保持原有断线重连
This commit is contained in:
@ -1,281 +1,31 @@
|
||||
# import sys
|
||||
# import cv2
|
||||
# import os
|
||||
# import time
|
||||
# from PyQt5.QtCore import QThread, pyqtSignal, QObject
|
||||
# import face_recognition
|
||||
|
||||
# current_dir = os.path.dirname(__file__)
|
||||
# share_code_dir = os.path.abspath(os.path.join(current_dir, '..', '..'))
|
||||
# sys.path.append(share_code_dir)
|
||||
|
||||
# from print_color import *
|
||||
|
||||
# DEFAULT_VIDEO_SLEEP_MS = 20
|
||||
|
||||
# # 图像处理线程
|
||||
# class ImageProcessingThread(QThread):
|
||||
# processed_image_signal = pyqtSignal(object)
|
||||
|
||||
# def __init__(self):
|
||||
# super().__init__()
|
||||
|
||||
# def run(self):
|
||||
# while True:
|
||||
# # 在这里添加图像处理代码
|
||||
# # 这里暂时只是将图像传递给下一个线程
|
||||
# time.sleep(0.01)
|
||||
# self.processed_image_signal.emit(None)
|
||||
|
||||
# # 摄像头采集线程
|
||||
# class CameraThread(QThread):
|
||||
# image_signal = pyqtSignal(object)
|
||||
|
||||
# def __init__(self, camera_url, circuit_id: int = 0):
|
||||
# super().__init__()
|
||||
|
||||
# self.camera_url = camera_url # 摄像头url地址, 整数 或者 字符串
|
||||
# self.face_detection: bool = False
|
||||
|
||||
# if isinstance(camera_url, int):
|
||||
# self.camera_url_str = str(camera_url)
|
||||
# else:
|
||||
# self.camera_url_str = camera_url
|
||||
|
||||
# self.cap: cv2.VideoCapture = None
|
||||
# self.running: bool = True
|
||||
|
||||
# self.fps = 0
|
||||
|
||||
# self.cycle_limit = DEFAULT_VIDEO_SLEEP_MS
|
||||
# self.cycle_ms = 0
|
||||
# self.circuit_id = circuit_id # 摄像头对应的回路, 组合开关每一个回路都有对应的摄像头
|
||||
# self.is_signal_connect = False
|
||||
# self.is_emit = False
|
||||
|
||||
# self.set_video_cycle_ms(2000)
|
||||
|
||||
# def signal_connect(self, slot_func):
|
||||
# self.image_signal.connect(slot_func)
|
||||
# self.is_signal_connect = True
|
||||
|
||||
# def signal_disconnect(self):
|
||||
# # 判断信号是否已连接
|
||||
# if self.is_signal_connect:
|
||||
# self.image_signal.disconnect()
|
||||
# self.is_signal_connect = False
|
||||
|
||||
# def set_video_cycle_ms(self, cycle_ms: int = 10):
|
||||
# if self.cycle_limit != cycle_ms:
|
||||
# if cycle_ms <= DEFAULT_VIDEO_SLEEP_MS:
|
||||
# self.cycle_limit = DEFAULT_VIDEO_SLEEP_MS
|
||||
# else:
|
||||
# self.cycle_limit = cycle_ms
|
||||
|
||||
# # 新建函数,改变函数延时方法
|
||||
# def change_camera_url(self, camera_url: str):
|
||||
# if self.circuit_id == camera_url:
|
||||
# self.set_video_cycle_ms(DEFAULT_VIDEO_SLEEP_MS)
|
||||
# else:
|
||||
# self.set_video_cycle_ms(1000)
|
||||
|
||||
# def close(self):
|
||||
# if self.cap == None: # 初始化一直未完成
|
||||
# self.terminate()
|
||||
# self.running = False
|
||||
|
||||
# def run(self):
|
||||
# process_count = 0
|
||||
# fps_time = 0
|
||||
|
||||
# while self.running == True:
|
||||
# inform_msg = "cameral init start, url = " + self.camera_url_str
|
||||
# print_inform_msg(inform_msg)
|
||||
|
||||
# try:
|
||||
# if isinstance(self.camera_url, int):
|
||||
# # 在 Windows 平台下,使用默认的 cv2.VideoCapture 接口
|
||||
# self.cap = cv2.VideoCapture(self.camera_url, cv2.CAP_DSHOW)
|
||||
# else:
|
||||
# # 在 Linux 平台下,使用默认的 cv2.VideoCapture 接口
|
||||
# self.cap = cv2.VideoCapture(self.camera_url)
|
||||
|
||||
# if self.cap != None:
|
||||
# inform_msg = "cameral Init Success, url = " + self.camera_url_str
|
||||
# self.is_emit = True
|
||||
# print_inform_msg(inform_msg)
|
||||
# else:
|
||||
# inform_msg = "cameral connection timeout, url = " + self.camera_url_str
|
||||
# print_inform_msg(inform_msg)
|
||||
|
||||
# except Exception as e:
|
||||
# self.cap = None
|
||||
# inform_msg = "cameral camera Init Fail, url = " + self.camera_url_str
|
||||
# print_error_msg(inform_msg)
|
||||
|
||||
# base_time = time.time()
|
||||
|
||||
# while self.running and self.cap != None:
|
||||
# # 延时20ms
|
||||
# time.sleep(DEFAULT_VIDEO_SLEEP_MS / 1000)
|
||||
# if self.cycle_ms + DEFAULT_VIDEO_SLEEP_MS < self.cycle_limit:
|
||||
# self.cycle_ms += DEFAULT_VIDEO_SLEEP_MS
|
||||
# self.cap.grab() # 抛弃多余的帧,保持最新帧
|
||||
# continue
|
||||
# else:
|
||||
# self.cycle_ms = 0
|
||||
|
||||
# try:
|
||||
# ret, frame = self.cap.read()
|
||||
# cur_time = time.time()
|
||||
|
||||
# execution_time = cur_time - base_time
|
||||
# base_time = cur_time
|
||||
# process_count += 1
|
||||
|
||||
# fps_time += execution_time
|
||||
|
||||
# if fps_time >= 1:
|
||||
# self.fps = process_count
|
||||
# process_count = 0
|
||||
# fps_time = 0
|
||||
|
||||
# if execution_time < 5:
|
||||
# image_object: QObject = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
|
||||
# self.image_signal.emit(image_object)
|
||||
# else: # 时间差大于5秒, 表示网络可能中断过, 退出并重新连接
|
||||
# err_message = "cameral read timeout, url = " + self.camera_url_str
|
||||
# print_error_msg(err_message)
|
||||
# break
|
||||
# except Exception as e:
|
||||
# err_message = "cameral read timeout, url = " + self.camera_url_str
|
||||
# self.is_emit = False
|
||||
# print_error_msg(err_message)
|
||||
# if self.running == True:
|
||||
# time.sleep(2)
|
||||
# break
|
||||
|
||||
# print_inform_msg("cameral connection End")
|
||||
# time.sleep(0.01)
|
||||
|
||||
# if self.cap != None:
|
||||
# self.cap.release()
|
||||
# self.cap = None
|
||||
# - * - coding:utf - 8 - * -
|
||||
import sys
|
||||
import cv2
|
||||
import os
|
||||
import time
|
||||
import subprocess
|
||||
import face_recognition
|
||||
import numpy as np
|
||||
from PIL import Image, ImageDraw, ImageFont
|
||||
from PyQt5.QtCore import QThread, pyqtSignal, QObject
|
||||
from print_color import *
|
||||
import face_recognition
|
||||
|
||||
current_dir = os.path.dirname(__file__)
|
||||
share_code_dir = os.path.abspath(os.path.join(current_dir, '..', '..'))
|
||||
sys.path.append(share_code_dir)
|
||||
|
||||
from print_color import *
|
||||
|
||||
DEFAULT_VIDEO_SLEEP_MS = 20
|
||||
|
||||
# 定义路径常量
|
||||
npy_file_path = os.path.abspath(os.path.join(os.path.dirname(__file__), 'face_data/face_data.npy'))
|
||||
image_folder_path = os.path.abspath(os.path.join(os.path.dirname(__file__), 'face_data'))
|
||||
font_path = os.path.abspath(os.path.join(os.path.dirname(__file__), 'font/hanzi.ttc'))
|
||||
def load_face_data():
|
||||
face_data = {}
|
||||
try:
|
||||
face_data = np.load(npy_file_path, allow_pickle=True).item()
|
||||
print_debug_msg(f"Loaded {len(face_data)} face encodings from {npy_file_path}.")
|
||||
except Exception as e:
|
||||
print_error_msg(f"Error loading face encodings: {e}")
|
||||
|
||||
current_images = [f for f in os.listdir(image_folder_path) if f.endswith('.jpg')]
|
||||
current_image_set = set(os.path.splitext(f)[0] for f in current_images)
|
||||
known_image_set = set(face_data.keys())
|
||||
|
||||
added_images = current_image_set - known_image_set
|
||||
removed_images = known_image_set - current_image_set
|
||||
|
||||
for image_name in added_images:
|
||||
image_path = os.path.join(image_folder_path, f"{image_name}.jpg")
|
||||
try:
|
||||
image = face_recognition.load_image_file(image_path)
|
||||
face_encodings = face_recognition.face_encodings(image)
|
||||
if face_encodings:
|
||||
face_data[image_name] = face_encodings[0].tolist()
|
||||
print_debug_msg(f"Added encoding for {image_name}.")
|
||||
else:
|
||||
print_warning_msg(f"[WARNING] No face detected in {image_name}.jpg.")
|
||||
except Exception as e:
|
||||
print_error_msg(f"[ERROR] Error processing {image_name}.jpg: {e}")
|
||||
|
||||
for removed_image in removed_images:
|
||||
del face_data[removed_image]
|
||||
print_debug_msg(f"Removed encoding for {removed_image}.")
|
||||
|
||||
np.save(npy_file_path, face_data)
|
||||
print_debug_msg(f"Updated face data saved with {len(face_data)} entries.")
|
||||
return face_data
|
||||
|
||||
# 图像处理线程
|
||||
class ImageProcessingThread(QThread):
|
||||
processed_image_signal = pyqtSignal(object)
|
||||
|
||||
def __init__(self, frame=None):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.frame = frame # 添加 frame 参数
|
||||
self.face_encodings = []
|
||||
self.face_names = []
|
||||
self.face_locations = []
|
||||
self.face_data = load_face_data()
|
||||
self.total_image_name = list(self.face_data.keys())
|
||||
self.total_face_encoding = [np.array(self.face_data[name]) for name in self.total_image_name]
|
||||
|
||||
def process_frame(self, frame):
|
||||
"""实时处理帧,匹配已知人脸"""
|
||||
self.face_locations = face_recognition.face_locations(frame)
|
||||
face_encodings = face_recognition.face_encodings(frame, self.face_locations)
|
||||
names = []
|
||||
for face_encoding in face_encodings:
|
||||
name = "Unknown"
|
||||
face_distances = face_recognition.face_distance(self.total_face_encoding, face_encoding)
|
||||
|
||||
if face_distances.size > 0:
|
||||
min_distance = np.min(face_distances)
|
||||
best_match_index = np.argmin(face_distances)
|
||||
|
||||
if min_distance < self.dynamic_tolerance(): # 使用动态容忍度
|
||||
name = self.total_image_name[best_match_index]
|
||||
|
||||
names.append(name)
|
||||
|
||||
self.face_names = names
|
||||
return frame
|
||||
|
||||
def dynamic_tolerance(self):
|
||||
# 动态调整容忍度,可以基于一些规则来调整,如帧内错误率、识别准确率等
|
||||
error_rate = self.calculate_error_rate()
|
||||
if error_rate > 0.1:
|
||||
return 0.5 # 高容忍度以减少错误
|
||||
else:
|
||||
return 0.4 # 适中容忍度
|
||||
|
||||
def calculate_error_rate(self):
|
||||
# 计算识别错误率,作为动态调整容忍度的依据
|
||||
total_faces = len(self.total_face_encoding)
|
||||
unmatched_faces = sum(1 for name in self.face_names if name == "Unknown")
|
||||
return unmatched_faces / total_faces if total_faces > 0 else 0
|
||||
|
||||
def set_frame(self, frame):
|
||||
self.frame = frame
|
||||
|
||||
def run(self):
|
||||
while True:
|
||||
if self.frame is not None:
|
||||
self.process_frame(self.frame)
|
||||
self.processed_image_signal.emit(self.frame)
|
||||
time.sleep(0.01) # 控制帧率
|
||||
|
||||
# 在这里添加图像处理代码
|
||||
# 这里暂时只是将图像传递给下一个线程
|
||||
time.sleep(0.01)
|
||||
self.processed_image_signal.emit(None)
|
||||
|
||||
# 摄像头采集线程
|
||||
class CameraThread(QThread):
|
||||
@ -283,8 +33,9 @@ class CameraThread(QThread):
|
||||
|
||||
def __init__(self, camera_url, circuit_id: int = 0):
|
||||
super().__init__()
|
||||
self.camera_url = camera_url
|
||||
self.face_detection: bool = True
|
||||
|
||||
self.camera_url = camera_url # 摄像头url地址, 整数 或者 字符串
|
||||
self.face_detection: bool = False
|
||||
|
||||
if isinstance(camera_url, int):
|
||||
self.camera_url_str = str(camera_url)
|
||||
@ -295,12 +46,10 @@ class CameraThread(QThread):
|
||||
self.running: bool = True
|
||||
|
||||
self.fps = 0
|
||||
self.frame_count = 0
|
||||
self.fps_time = 0
|
||||
|
||||
self.cycle_limit = DEFAULT_VIDEO_SLEEP_MS
|
||||
self.cycle_ms = 0
|
||||
self.circuit_id = circuit_id
|
||||
self.circuit_id = circuit_id # 摄像头对应的回路, 组合开关每一个回路都有对应的摄像头
|
||||
self.is_signal_connect = False
|
||||
self.is_emit = False
|
||||
|
||||
@ -311,6 +60,7 @@ class CameraThread(QThread):
|
||||
self.is_signal_connect = True
|
||||
|
||||
def signal_disconnect(self):
|
||||
# 判断信号是否已连接
|
||||
if self.is_signal_connect:
|
||||
self.image_signal.disconnect()
|
||||
self.is_signal_connect = False
|
||||
@ -322,6 +72,7 @@ class CameraThread(QThread):
|
||||
else:
|
||||
self.cycle_limit = cycle_ms
|
||||
|
||||
# 新建函数,改变函数延时方法
|
||||
def change_camera_url(self, camera_url: str):
|
||||
if self.circuit_id == camera_url:
|
||||
self.set_video_cycle_ms(DEFAULT_VIDEO_SLEEP_MS)
|
||||
@ -329,115 +80,364 @@ class CameraThread(QThread):
|
||||
self.set_video_cycle_ms(1000)
|
||||
|
||||
def close(self):
|
||||
if self.cap is None:
|
||||
if self.cap == None: # 初始化一直未完成
|
||||
self.terminate()
|
||||
self.running = False
|
||||
|
||||
def run(self):
|
||||
process_count = 0
|
||||
fps_time = 0
|
||||
face_thread = ImageProcessingThread()
|
||||
face_thread.start()
|
||||
|
||||
self.match_count = 0 # 初始化匹配帧数计数器
|
||||
|
||||
while self.running:
|
||||
inform_msg = "Camera init start, URL = " + self.camera_url_str
|
||||
while self.running == True:
|
||||
inform_msg = "cameral init start, url = " + self.camera_url_str
|
||||
print_inform_msg(inform_msg)
|
||||
|
||||
try:
|
||||
self.cap = cv2.VideoCapture(self.camera_url) # 强制使用 BGR 格式
|
||||
if self.cap.isOpened():
|
||||
inform_msg = "Camera Init Success, URL = " + self.camera_url_str
|
||||
if isinstance(self.camera_url, int):
|
||||
# 在 Windows 平台下,使用默认的 cv2.VideoCapture 接口
|
||||
self.cap = cv2.VideoCapture(self.camera_url, cv2.CAP_DSHOW)
|
||||
else:
|
||||
# 在 Linux 平台下,使用默认的 cv2.VideoCapture 接口
|
||||
self.cap = cv2.VideoCapture(self.camera_url)
|
||||
|
||||
if self.cap != None:
|
||||
inform_msg = "cameral Init Success, url = " + self.camera_url_str
|
||||
self.is_emit = True
|
||||
print_inform_msg(inform_msg)
|
||||
else:
|
||||
inform_msg = "Camera connection timeout, URL = " + self.camera_url_str
|
||||
print_error_msg(inform_msg)
|
||||
inform_msg = "cameral connection timeout, url = " + self.camera_url_str
|
||||
print_inform_msg(inform_msg)
|
||||
|
||||
except Exception as e:
|
||||
self.cap = None
|
||||
inform_msg = "Camera Init Fail, URL = " + self.camera_url_str
|
||||
inform_msg = "cameral camera Init Fail, url = " + self.camera_url_str
|
||||
print_error_msg(inform_msg)
|
||||
|
||||
base_time = time.time()
|
||||
|
||||
while self.running and self.cap:
|
||||
while self.running and self.cap != None:
|
||||
# 延时20ms
|
||||
time.sleep(DEFAULT_VIDEO_SLEEP_MS / 1000)
|
||||
|
||||
if self.cycle_ms + DEFAULT_VIDEO_SLEEP_MS < self.cycle_limit:
|
||||
self.cycle_ms += DEFAULT_VIDEO_SLEEP_MS
|
||||
self.cap.grab()
|
||||
self.cap.grab() # 抛弃多余的帧,保持最新帧
|
||||
continue
|
||||
else:
|
||||
self.cycle_ms = 0
|
||||
|
||||
try:
|
||||
ret, frame = self.cap.read()
|
||||
if not ret:
|
||||
break
|
||||
|
||||
face_thread.set_frame(frame)
|
||||
|
||||
cur_time = time.time()
|
||||
|
||||
execution_time = cur_time - base_time
|
||||
base_time = cur_time
|
||||
process_count += 1
|
||||
|
||||
fps_time += execution_time
|
||||
if fps_time >= 1: # 每隔1秒重新计算 FPS
|
||||
|
||||
if fps_time >= 1:
|
||||
self.fps = process_count
|
||||
process_count = 0
|
||||
fps_time = 0
|
||||
|
||||
if execution_time < 5:
|
||||
frame: QObject = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
|
||||
for (top, right, bottom, left), name in zip(face_thread.face_locations, face_thread.face_names):
|
||||
if name != "Unknown": # 只绘制已匹配的结果
|
||||
self.match_count += 1 # 计数成功匹配的帧
|
||||
# cv2.rectangle(frame, (left, top), (right, bottom), (0, 255, 0), 2)
|
||||
# cv2.putText(frame, name, (left + 6, bottom - 6), cv2.FONT_HERSHEY_DUPLEX, 1.0, (255, 255, 255), 1)
|
||||
|
||||
# 将OpenCV图像转换为PIL图像格式(注意要转换色彩空间,OpenCV是BGR,PIL是RGB)
|
||||
pil_image = Image.fromarray(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
|
||||
draw = ImageDraw.Draw(pil_image)
|
||||
# 这里选择合适的中文字体文件路径,比如系统自带的宋体(不同系统路径可能有差异),并设置字体大小
|
||||
font = ImageFont.truetype(font_path, 15)
|
||||
# 在指定位置绘制中文
|
||||
draw.text((left + 12, bottom + 12), name, font=font, fill=(255, 255, 255))
|
||||
# 再将PIL图像转换回OpenCV图像格式
|
||||
frame = cv2.cvtColor(np.array(pil_image), cv2.COLOR_RGB2BGR)
|
||||
cv2.rectangle(frame, (left, top), (right, bottom), (0, 255, 0), 2)
|
||||
else:
|
||||
name = "未在人脸库中,无操作权限"
|
||||
pil_image = Image.fromarray(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
|
||||
draw = ImageDraw.Draw(pil_image)
|
||||
#设置字体大小
|
||||
font = ImageFont.truetype(font_path, 15)
|
||||
# 在指定位置绘制中文
|
||||
draw.text((left + 12, bottom + 12), name, font=font, fill=(255, 255, 255))
|
||||
# 再将PIL图像转换回OpenCV图像格式
|
||||
frame = cv2.cvtColor(np.array(pil_image), cv2.COLOR_RGB2BGR)
|
||||
cv2.rectangle(frame, (left, top), (right, bottom), (255, 0, 0), 2)
|
||||
self.image_signal.emit(frame)
|
||||
else:
|
||||
err_message = "Camera read timeout, URL = " + self.camera_url_str
|
||||
image_object: QObject = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
|
||||
self.image_signal.emit(image_object)
|
||||
else: # 时间差大于5秒, 表示网络可能中断过, 退出并重新连接
|
||||
err_message = "cameral read timeout, url = " + self.camera_url_str
|
||||
print_error_msg(err_message)
|
||||
break
|
||||
|
||||
except Exception as e:
|
||||
err_message = "Camera read exception, URL = " + self.camera_url_str
|
||||
err_message = "cameral read timeout, url = " + self.camera_url_str
|
||||
self.is_emit = False
|
||||
print_error_msg(err_message)
|
||||
if self.running:
|
||||
if self.running == True:
|
||||
time.sleep(2)
|
||||
break
|
||||
|
||||
if self.cap:
|
||||
self.cap.release()
|
||||
self.cap = None
|
||||
|
||||
print_inform_msg("Camera connection ended")
|
||||
print_inform_msg("cameral connection End")
|
||||
time.sleep(0.01)
|
||||
|
||||
if self.cap != None:
|
||||
self.cap.release()
|
||||
self.cap = None
|
||||
# - * - coding:utf - 8 - * -
|
||||
# import sys
|
||||
# import cv2
|
||||
# import os
|
||||
# import time
|
||||
# import subprocess
|
||||
# import face_recognition
|
||||
# import numpy as np
|
||||
# from PIL import Image, ImageDraw, ImageFont
|
||||
# from PyQt5.QtCore import QThread, pyqtSignal, QObject
|
||||
# from print_color import *
|
||||
# current_dir = os.path.dirname(__file__)
|
||||
# share_code_dir = os.path.abspath(os.path.join(current_dir, '..', '..'))
|
||||
# sys.path.append(share_code_dir)
|
||||
|
||||
# DEFAULT_VIDEO_SLEEP_MS = 20
|
||||
|
||||
# # 定义路径常量
|
||||
# npy_file_path = os.path.abspath(os.path.join(os.path.dirname(__file__), 'face_data/face_data.npy'))
|
||||
# image_folder_path = os.path.abspath(os.path.join(os.path.dirname(__file__), 'face_data'))
|
||||
# font_path = os.path.abspath(os.path.join(os.path.dirname(__file__), 'font/hanzi.ttc'))
|
||||
# def load_face_data():
|
||||
# face_data = {}
|
||||
# try:
|
||||
# face_data = np.load(npy_file_path, allow_pickle=True).item()
|
||||
# print_debug_msg(f"Loaded {len(face_data)} face encodings from {npy_file_path}.")
|
||||
# except Exception as e:
|
||||
# print_error_msg(f"Error loading face encodings: {e}")
|
||||
|
||||
# current_images = [f for f in os.listdir(image_folder_path) if f.endswith('.jpg')]
|
||||
# current_image_set = set(os.path.splitext(f)[0] for f in current_images)
|
||||
# known_image_set = set(face_data.keys())
|
||||
|
||||
# added_images = current_image_set - known_image_set
|
||||
# removed_images = known_image_set - current_image_set
|
||||
|
||||
# for image_name in added_images:
|
||||
# image_path = os.path.join(image_folder_path, f"{image_name}.jpg")
|
||||
# try:
|
||||
# image = face_recognition.load_image_file(image_path)
|
||||
# face_encodings = face_recognition.face_encodings(image)
|
||||
# if face_encodings:
|
||||
# face_data[image_name] = face_encodings[0].tolist()
|
||||
# print_debug_msg(f"Added encoding for {image_name}.")
|
||||
# else:
|
||||
# print_warning_msg(f"[WARNING] No face detected in {image_name}.jpg.")
|
||||
# except Exception as e:
|
||||
# print_error_msg(f"[ERROR] Error processing {image_name}.jpg: {e}")
|
||||
|
||||
# for removed_image in removed_images:
|
||||
# del face_data[removed_image]
|
||||
# print_debug_msg(f"Removed encoding for {removed_image}.")
|
||||
|
||||
# np.save(npy_file_path, face_data)
|
||||
# print_debug_msg(f"Updated face data saved with {len(face_data)} entries.")
|
||||
# return face_data
|
||||
|
||||
# class ImageProcessingThread(QThread):
|
||||
# processed_image_signal = pyqtSignal(object)
|
||||
|
||||
# def __init__(self, frame=None):
|
||||
# super().__init__()
|
||||
# self.frame = frame # 添加 frame 参数
|
||||
# self.face_encodings = []
|
||||
# self.face_names = []
|
||||
# self.face_locations = []
|
||||
# self.face_data = load_face_data()
|
||||
# self.total_image_name = list(self.face_data.keys())
|
||||
# self.total_face_encoding = [np.array(self.face_data[name]) for name in self.total_image_name]
|
||||
|
||||
# def process_frame(self, frame):
|
||||
# """实时处理帧,匹配已知人脸"""
|
||||
# self.face_locations = face_recognition.face_locations(frame)
|
||||
# face_encodings = face_recognition.face_encodings(frame, self.face_locations)
|
||||
# names = []
|
||||
# for face_encoding in face_encodings:
|
||||
# name = "Unknown"
|
||||
# face_distances = face_recognition.face_distance(self.total_face_encoding, face_encoding)
|
||||
|
||||
# if face_distances.size > 0:
|
||||
# min_distance = np.min(face_distances)
|
||||
# best_match_index = np.argmin(face_distances)
|
||||
|
||||
# if min_distance < self.dynamic_tolerance(): # 使用动态容忍度
|
||||
# name = self.total_image_name[best_match_index]
|
||||
|
||||
# names.append(name)
|
||||
|
||||
# self.face_names = names
|
||||
# return frame
|
||||
|
||||
# def dynamic_tolerance(self):
|
||||
# # 动态调整容忍度,可以基于一些规则来调整,如帧内错误率、识别准确率等
|
||||
# error_rate = self.calculate_error_rate()
|
||||
# if error_rate > 0.1:
|
||||
# return 0.5 # 高容忍度以减少错误
|
||||
# else:
|
||||
# return 0.4 # 适中容忍度
|
||||
|
||||
# def calculate_error_rate(self):
|
||||
# # 计算识别错误率,作为动态调整容忍度的依据
|
||||
# total_faces = len(self.total_face_encoding)
|
||||
# unmatched_faces = sum(1 for name in self.face_names if name == "Unknown")
|
||||
# return unmatched_faces / total_faces if total_faces > 0 else 0
|
||||
|
||||
# def set_frame(self, frame):
|
||||
# self.frame = frame
|
||||
|
||||
# def run(self):
|
||||
# while True:
|
||||
# if self.frame is not None:
|
||||
# self.process_frame(self.frame)
|
||||
# self.processed_image_signal.emit(self.frame)
|
||||
# time.sleep(0.01) # 控制帧率
|
||||
|
||||
|
||||
# # 摄像头采集线程
|
||||
# class CameraThread(QThread):
|
||||
# image_signal = pyqtSignal(object)
|
||||
|
||||
# def __init__(self, camera_url, circuit_id: int = 0):
|
||||
# super().__init__()
|
||||
# self.camera_url = camera_url
|
||||
# self.face_detection: bool = True
|
||||
|
||||
# if isinstance(camera_url, int):
|
||||
# self.camera_url_str = str(camera_url)
|
||||
# else:
|
||||
# self.camera_url_str = camera_url
|
||||
|
||||
# self.cap: cv2.VideoCapture = None
|
||||
# self.running: bool = True
|
||||
|
||||
# self.fps = 0
|
||||
# self.frame_count = 0
|
||||
# self.fps_time = 0
|
||||
|
||||
# self.cycle_limit = DEFAULT_VIDEO_SLEEP_MS
|
||||
# self.cycle_ms = 0
|
||||
# self.circuit_id = circuit_id
|
||||
# self.is_signal_connect = False
|
||||
# self.is_emit = False
|
||||
|
||||
# self.set_video_cycle_ms(2000)
|
||||
|
||||
# def signal_connect(self, slot_func):
|
||||
# self.image_signal.connect(slot_func)
|
||||
# self.is_signal_connect = True
|
||||
|
||||
# def signal_disconnect(self):
|
||||
# if self.is_signal_connect:
|
||||
# self.image_signal.disconnect()
|
||||
# self.is_signal_connect = False
|
||||
|
||||
# def set_video_cycle_ms(self, cycle_ms: int = 10):
|
||||
# if self.cycle_limit != cycle_ms:
|
||||
# if cycle_ms <= DEFAULT_VIDEO_SLEEP_MS:
|
||||
# self.cycle_limit = DEFAULT_VIDEO_SLEEP_MS
|
||||
# else:
|
||||
# self.cycle_limit = cycle_ms
|
||||
|
||||
# def change_camera_url(self, camera_url: str):
|
||||
# if self.circuit_id == camera_url:
|
||||
# self.set_video_cycle_ms(DEFAULT_VIDEO_SLEEP_MS)
|
||||
# else:
|
||||
# self.set_video_cycle_ms(1000)
|
||||
|
||||
# def close(self):
|
||||
# if self.cap is None:
|
||||
# self.terminate()
|
||||
# self.running = False
|
||||
|
||||
# def run(self):
|
||||
# process_count = 0
|
||||
# fps_time = 0
|
||||
# face_thread = ImageProcessingThread()
|
||||
# face_thread.start()
|
||||
|
||||
# self.match_count = 0 # 初始化匹配帧数计数器
|
||||
|
||||
# while self.running:
|
||||
# inform_msg = "Camera init start, URL = " + self.camera_url_str
|
||||
# print_inform_msg(inform_msg)
|
||||
|
||||
# try:
|
||||
# self.cap = cv2.VideoCapture(self.camera_url) # 强制使用 BGR 格式
|
||||
# if self.cap.isOpened():
|
||||
# inform_msg = "Camera Init Success, URL = " + self.camera_url_str
|
||||
# self.is_emit = True
|
||||
# print_inform_msg(inform_msg)
|
||||
# else:
|
||||
# inform_msg = "Camera connection timeout, URL = " + self.camera_url_str
|
||||
# print_error_msg(inform_msg)
|
||||
|
||||
# except Exception as e:
|
||||
# self.cap = None
|
||||
# inform_msg = "Camera Init Fail, URL = " + self.camera_url_str
|
||||
# print_error_msg(inform_msg)
|
||||
|
||||
# base_time = time.time()
|
||||
|
||||
# while self.running and self.cap:
|
||||
# time.sleep(DEFAULT_VIDEO_SLEEP_MS / 1000)
|
||||
|
||||
# if self.cycle_ms + DEFAULT_VIDEO_SLEEP_MS < self.cycle_limit:
|
||||
# self.cycle_ms += DEFAULT_VIDEO_SLEEP_MS
|
||||
# self.cap.grab()
|
||||
# continue
|
||||
# else:
|
||||
# self.cycle_ms = 0
|
||||
|
||||
# try:
|
||||
# ret, frame = self.cap.read()
|
||||
# if not ret:
|
||||
# break
|
||||
|
||||
# face_thread.set_frame(frame)
|
||||
|
||||
# cur_time = time.time()
|
||||
# execution_time = cur_time - base_time
|
||||
# base_time = cur_time
|
||||
# process_count += 1
|
||||
|
||||
# fps_time += execution_time
|
||||
# if fps_time >= 1: # 每隔1秒重新计算 FPS
|
||||
# self.fps = process_count
|
||||
# process_count = 0
|
||||
# fps_time = 0
|
||||
|
||||
# if execution_time < 5:
|
||||
# frame: QObject = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
|
||||
# for (top, right, bottom, left), name in zip(face_thread.face_locations, face_thread.face_names):
|
||||
# if name != "Unknown": # 只绘制已匹配的结果
|
||||
# self.match_count += 1 # 计数成功匹配的帧
|
||||
# # cv2.rectangle(frame, (left, top), (right, bottom), (0, 255, 0), 2)
|
||||
# # cv2.putText(frame, name, (left + 6, bottom - 6), cv2.FONT_HERSHEY_DUPLEX, 1.0, (255, 255, 255), 1)
|
||||
|
||||
# # 将OpenCV图像转换为PIL图像格式(注意要转换色彩空间,OpenCV是BGR,PIL是RGB)
|
||||
# pil_image = Image.fromarray(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
|
||||
# draw = ImageDraw.Draw(pil_image)
|
||||
# # 这里选择合适的中文字体文件路径,比如系统自带的宋体(不同系统路径可能有差异),并设置字体大小
|
||||
# font = ImageFont.truetype(font_path, 15)
|
||||
# # 在指定位置绘制中文
|
||||
# draw.text((left + 12, bottom + 12), name, font=font, fill=(255, 255, 255))
|
||||
# # 再将PIL图像转换回OpenCV图像格式
|
||||
# frame = cv2.cvtColor(np.array(pil_image), cv2.COLOR_RGB2BGR)
|
||||
# cv2.rectangle(frame, (left, top), (right, bottom), (0, 255, 0), 2)
|
||||
# else:
|
||||
# name = "未在人脸库中,无操作权限"
|
||||
# pil_image = Image.fromarray(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
|
||||
# draw = ImageDraw.Draw(pil_image)
|
||||
# #设置字体大小
|
||||
# font = ImageFont.truetype(font_path, 15)
|
||||
# # 在指定位置绘制中文
|
||||
# draw.text((left + 12, bottom + 12), name, font=font, fill=(255, 255, 255))
|
||||
# # 再将PIL图像转换回OpenCV图像格式
|
||||
# frame = cv2.cvtColor(np.array(pil_image), cv2.COLOR_RGB2BGR)
|
||||
# cv2.rectangle(frame, (left, top), (right, bottom), (255, 0, 0), 2)
|
||||
# self.image_signal.emit(frame)
|
||||
# else:
|
||||
# err_message = "Camera read timeout, URL = " + self.camera_url_str
|
||||
# print_error_msg(err_message)
|
||||
# break
|
||||
|
||||
# except Exception as e:
|
||||
# err_message = "Camera read exception, URL = " + self.camera_url_str
|
||||
# print_error_msg(err_message)
|
||||
# if self.running:
|
||||
# time.sleep(2)
|
||||
# break
|
||||
|
||||
# if self.cap:
|
||||
# self.cap.release()
|
||||
# self.cap = None
|
||||
|
||||
# print_inform_msg("Camera connection ended")
|
||||
# time.sleep(0.01)
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user